Merge branch 'staging' into docs

This commit is contained in:
julian-CStack 2023-07-03 13:51:05 -06:00 committed by GitHub
commit 05df748b11
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 285 additions and 185 deletions

View file

@ -9,9 +9,11 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/models/buy/response_objects/order.dart'; import 'package:stackwallet/models/buy/response_objects/order.dart';
import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/themes/theme_providers.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/utilities/util.dart';
@ -21,7 +23,7 @@ import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart';
class BuyOrderDetailsView extends StatefulWidget { class BuyOrderDetailsView extends ConsumerStatefulWidget {
const BuyOrderDetailsView({ const BuyOrderDetailsView({
Key? key, Key? key,
required this.order, required this.order,
@ -32,10 +34,11 @@ class BuyOrderDetailsView extends StatefulWidget {
static const String routeName = "/buyOrderDetails"; static const String routeName = "/buyOrderDetails";
@override @override
State<BuyOrderDetailsView> createState() => _BuyOrderDetailsViewState(); ConsumerState<BuyOrderDetailsView> createState() =>
_BuyOrderDetailsViewState();
} }
class _BuyOrderDetailsViewState extends State<BuyOrderDetailsView> { class _BuyOrderDetailsViewState extends ConsumerState<BuyOrderDetailsView> {
final isDesktop = Util.isDesktop; final isDesktop = Util.isDesktop;
@override @override
@ -245,7 +248,9 @@ class _BuyOrderDetailsViewState extends State<BuyOrderDetailsView> {
width: 64, width: 64,
height: 32, height: 32,
child: SvgPicture.asset( child: SvgPicture.asset(
Assets.buy.simplexLogo(context), Assets.buy.simplexLogo(
ref.watch(themeProvider).brightness,
),
), ),
), ),
], ],

View file

@ -11,11 +11,13 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:stackwallet/models/buy/response_objects/quote.dart'; import 'package:stackwallet/models/buy/response_objects/quote.dart';
import 'package:stackwallet/pages/buy_view/sub_widgets/buy_warning_popup.dart'; import 'package:stackwallet/pages/buy_view/sub_widgets/buy_warning_popup.dart';
import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/themes/theme_providers.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/utilities/util.dart';
@ -25,7 +27,7 @@ import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart';
class BuyQuotePreviewView extends StatefulWidget { class BuyQuotePreviewView extends ConsumerStatefulWidget {
const BuyQuotePreviewView({ const BuyQuotePreviewView({
Key? key, Key? key,
required this.quote, required this.quote,
@ -36,10 +38,11 @@ class BuyQuotePreviewView extends StatefulWidget {
static const String routeName = "/buyQuotePreview"; static const String routeName = "/buyQuotePreview";
@override @override
State<BuyQuotePreviewView> createState() => _BuyQuotePreviewViewState(); ConsumerState<BuyQuotePreviewView> createState() =>
_BuyQuotePreviewViewState();
} }
class _BuyQuotePreviewViewState extends State<BuyQuotePreviewView> { class _BuyQuotePreviewViewState extends ConsumerState<BuyQuotePreviewView> {
final isDesktop = Util.isDesktop; final isDesktop = Util.isDesktop;
Future<void> _buyWarning() async { Future<void> _buyWarning() async {
@ -222,7 +225,9 @@ class _BuyQuotePreviewViewState extends State<BuyQuotePreviewView> {
width: 64, width: 64,
height: 32, height: 32,
child: SvgPicture.asset( child: SvgPicture.asset(
Assets.buy.simplexLogo(context), Assets.buy.simplexLogo(
ref.watch(themeProvider).brightness,
),
), ),
), ),
], ],

View file

@ -11,6 +11,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/models/buy/response_objects/order.dart'; import 'package:stackwallet/models/buy/response_objects/order.dart';
import 'package:stackwallet/models/buy/response_objects/quote.dart'; import 'package:stackwallet/models/buy/response_objects/quote.dart';
@ -18,6 +19,7 @@ import 'package:stackwallet/pages/buy_view/buy_order_details.dart';
import 'package:stackwallet/services/buy/buy_response.dart'; import 'package:stackwallet/services/buy/buy_response.dart';
import 'package:stackwallet/services/buy/simplex/simplex_api.dart'; import 'package:stackwallet/services/buy/simplex/simplex_api.dart';
import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/themes/theme_providers.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/utilities/util.dart';
@ -28,7 +30,7 @@ import 'package:stackwallet/widgets/desktop/secondary_button.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/stack_dialog.dart'; import 'package:stackwallet/widgets/stack_dialog.dart';
class BuyWarningPopup extends StatefulWidget { class BuyWarningPopup extends ConsumerStatefulWidget {
const BuyWarningPopup({ const BuyWarningPopup({
Key? key, Key? key,
required this.quote, required this.quote,
@ -37,10 +39,10 @@ class BuyWarningPopup extends StatefulWidget {
final SimplexQuote quote; final SimplexQuote quote;
final SimplexOrder? order; final SimplexOrder? order;
@override @override
State<BuyWarningPopup> createState() => _BuyWarningPopupState(); ConsumerState<BuyWarningPopup> createState() => _BuyWarningPopupState();
} }
class _BuyWarningPopupState extends State<BuyWarningPopup> { class _BuyWarningPopupState extends ConsumerState<BuyWarningPopup> {
late final bool isDesktop; late final bool isDesktop;
SimplexOrder? order; SimplexOrder? order;
@ -236,7 +238,9 @@ class _BuyWarningPopupState extends State<BuyWarningPopup> {
width: 64, width: 64,
height: 32, height: 32,
child: SvgPicture.asset( child: SvgPicture.asset(
Assets.buy.simplexLogo(context), Assets.buy.simplexLogo(
ref.watch(themeProvider).brightness,
),
), ),
), ),
], ],
@ -291,7 +295,9 @@ class _BuyWarningPopupState extends State<BuyWarningPopup> {
width: 64, width: 64,
height: 32, height: 32,
child: SvgPicture.asset( child: SvgPicture.asset(
Assets.buy.simplexLogo(context), Assets.buy.simplexLogo(
ref.watch(themeProvider).brightness,
),
), ),
), ),
); );

View file

@ -22,6 +22,7 @@ import 'package:stackwallet/pages/receive_view/generate_receiving_uri_qr_code_vi
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/route_generator.dart';
import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/address_utils.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
@ -337,7 +338,11 @@ class _ReceiveViewState extends ConsumerState<ReceiveView> {
child: Column( child: Column(
children: [ children: [
QrImageView( QrImageView(
data: "${coin.uriScheme}:$receivingAddress", data: AddressUtils.buildUriString(
coin,
receivingAddress,
{},
),
size: MediaQuery.of(context).size.width / 2, size: MediaQuery.of(context).size.width / 2,
foregroundColor: Theme.of(context) foregroundColor: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!

View file

@ -21,6 +21,7 @@ import 'package:stackwallet/pages/token_view/token_view.dart';
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/route_generator.dart';
import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/address_utils.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
@ -236,7 +237,11 @@ class _DesktopReceiveState extends ConsumerState<DesktopReceive> {
), ),
Center( Center(
child: QrImageView( child: QrImageView(
data: "${coin.uriScheme}:$receivingAddress", data: AddressUtils.buildUriString(
coin,
receivingAddress,
{},
),
size: 200, size: 200,
foregroundColor: foregroundColor:
Theme.of(context).extension<StackColors>()!.accentColorDark, Theme.of(context).extension<StackColors>()!.accentColorDark,

View file

@ -9,7 +9,6 @@
*/ */
import 'dart:async'; import 'dart:async';
import 'dart:math';
import 'package:bip47/bip47.dart'; import 'package:bip47/bip47.dart';
import 'package:cw_core/monero_transaction_priority.dart'; import 'package:cw_core/monero_transaction_priority.dart';
@ -462,27 +461,11 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
void _cryptoAmountChanged() async { void _cryptoAmountChanged() async {
if (!_cryptoAmountChangeLock) { if (!_cryptoAmountChangeLock) {
String cryptoAmount = cryptoAmountController.text; final cryptoAmount = ref.read(pAmountFormatter(coin)).tryParse(
if (cryptoAmount.isNotEmpty && cryptoAmountController.text,
cryptoAmount != "." && );
cryptoAmount != ",") { if (cryptoAmount != null) {
if (cryptoAmount.startsWith("~")) { _amountToSend = cryptoAmount;
cryptoAmount = cryptoAmount.substring(1);
}
if (cryptoAmount.contains(" ")) {
cryptoAmount = cryptoAmount.split(" ").first;
}
// ensure we don't shift past minimum atomic value
final shift = min(ref.read(pAmountUnit(coin)).shift, coin.decimals);
_amountToSend = cryptoAmount.contains(",")
? Decimal.parse(cryptoAmount.replaceFirst(",", "."))
.shift(0 - shift)
.toAmount(fractionDigits: coin.decimals)
: Decimal.parse(cryptoAmount)
.shift(0 - shift)
.toAmount(fractionDigits: coin.decimals);
if (_cachedAmountToSend != null && if (_cachedAmountToSend != null &&
_cachedAmountToSend == _amountToSend) { _cachedAmountToSend == _amountToSend) {
return; return;
@ -677,15 +660,12 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
} }
void fiatTextFieldOnChanged(String baseAmountString) { void fiatTextFieldOnChanged(String baseAmountString) {
if (baseAmountString.isNotEmpty && final baseAmount = Amount.tryParseFiatString(
baseAmountString != "." && baseAmountString,
baseAmountString != ",") { locale: ref.read(localeServiceChangeNotifierProvider).locale,
final baseAmount = baseAmountString.contains(",") );
? Decimal.parse(baseAmountString.replaceFirst(",", ".")) if (baseAmount != null) {
.toAmount(fractionDigits: 2) final _price =
: Decimal.parse(baseAmountString).toAmount(fractionDigits: 2);
var _price =
ref.read(priceAnd24hChangeNotifierProvider).getPrice(coin).item1; ref.read(priceAnd24hChangeNotifierProvider).getPrice(coin).item1;
if (_price == Decimal.zero) { if (_price == Decimal.zero) {
@ -1389,7 +1369,10 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
), ),
if (!([Coin.nano, Coin.banano, Coin.epicCash].contains(coin))) if (!([Coin.nano, Coin.banano, Coin.epicCash].contains(coin)))
ConditionalParent( ConditionalParent(
condition: coin.isElectrumXCoin, condition: coin.isElectrumXCoin &&
!(((coin == Coin.firo || coin == Coin.firoTestNet) &&
ref.read(publicPrivateBalanceStateProvider.state).state ==
"Private")),
builder: (child) => Row( builder: (child) => Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
@ -1441,72 +1424,117 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
), ),
if (!([Coin.nano, Coin.banano, Coin.epicCash].contains(coin))) if (!([Coin.nano, Coin.banano, Coin.epicCash].contains(coin)))
if (!isCustomFee) if (!isCustomFee)
(feeSelectionResult?.$2 == null) Padding(
? FutureBuilder( padding: const EdgeInsets.all(10),
future: ref.watch( child: (feeSelectionResult?.$2 == null)
walletsChangeNotifierProvider.select( ? FutureBuilder(
(value) => value.getManager(walletId).fees, future: ref.watch(
walletsChangeNotifierProvider.select(
(value) => value.getManager(walletId).fees,
),
), ),
), builder: (context, snapshot) {
builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done &&
if (snapshot.connectionState == ConnectionState.done && snapshot.hasData) {
snapshot.hasData) { return DesktopFeeItem(
return DesktopFeeItem( feeObject: snapshot.data,
feeObject: snapshot.data, feeRateType: FeeRateType.average,
feeRateType: FeeRateType.average, walletId: walletId,
walletId: walletId, isButton: false,
feeFor: ({ feeFor: ({
required Amount amount, required Amount amount,
required FeeRateType feeRateType, required FeeRateType feeRateType,
required int feeRate, required int feeRate,
required Coin coin, required Coin coin,
}) async { }) async {
if (ref if (ref
.read(feeSheetSessionCacheProvider) .read(feeSheetSessionCacheProvider)
.average[amount] == .average[amount] ==
null) { null) {
final manager = ref final manager = ref
.read(walletsChangeNotifierProvider) .read(walletsChangeNotifierProvider)
.getManager(walletId); .getManager(walletId);
if (coin == Coin.monero || coin == Coin.wownero) { if (coin == Coin.monero ||
final fee = await manager.estimateFeeFor(amount, coin == Coin.wownero) {
MoneroTransactionPriority.regular.raw!); final fee = await manager.estimateFeeFor(
ref amount,
.read(feeSheetSessionCacheProvider) MoneroTransactionPriority.regular.raw!);
.average[amount] = fee;
} else if ((coin == Coin.firo ||
coin == Coin.firoTestNet) &&
ref ref
.read( .read(feeSheetSessionCacheProvider)
publicPrivateBalanceStateProvider .average[amount] = fee;
.state) } else if ((coin == Coin.firo ||
.state != coin == Coin.firoTestNet) &&
"Private") { ref
ref .read(
.read(feeSheetSessionCacheProvider) publicPrivateBalanceStateProvider
.average[amount] = .state)
await (manager.wallet as FiroWallet) .state !=
.estimateFeeForPublic(amount, feeRate); "Private") {
} else { ref
ref .read(feeSheetSessionCacheProvider)
.read(feeSheetSessionCacheProvider) .average[amount] = await (manager.wallet
.average[amount] = as FiroWallet)
await manager.estimateFeeFor( .estimateFeeForPublic(amount, feeRate);
amount, feeRate); } else {
ref
.read(feeSheetSessionCacheProvider)
.average[amount] =
await manager.estimateFeeFor(
amount, feeRate);
}
} }
} return ref
return ref .read(feeSheetSessionCacheProvider)
.read(feeSheetSessionCacheProvider) .average[amount]!;
.average[amount]!; },
}, isSelected: true,
isSelected: true, );
); } else {
} else { return Row(
return Row( children: [
AnimatedText(
stringsToLoopThrough: stringsToLoopThrough,
style: STextStyles.desktopTextExtraExtraSmall(
context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveText,
),
),
],
);
}
},
)
: (coin == Coin.firo || coin == Coin.firoTestNet) &&
ref
.watch(
publicPrivateBalanceStateProvider.state)
.state ==
"Private"
? Text(
"~${ref.watch(pAmountFormatter(coin)).format(
Amount(
rawValue: BigInt.parse("3794"),
fractionDigits: coin.decimals,
),
indicatePrecisionLoss: false,
)}",
style: STextStyles.desktopTextExtraExtraSmall(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveText,
),
textAlign: TextAlign.left,
)
: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
AnimatedText( Text(
stringsToLoopThrough: stringsToLoopThrough, feeSelectionResult?.$2 ?? "",
style: STextStyles.desktopTextExtraExtraSmall( style: STextStyles.desktopTextExtraExtraSmall(
context) context)
.copyWith( .copyWith(
@ -1514,36 +1542,21 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
.extension<StackColors>()! .extension<StackColors>()!
.textFieldActiveText, .textFieldActiveText,
), ),
textAlign: TextAlign.left,
),
Text(
feeSelectionResult?.$3 ?? "",
style: STextStyles.desktopTextExtraExtraSmall(
context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveSearchIconRight,
),
), ),
], ],
);
}
},
)
: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
feeSelectionResult?.$2 ?? "",
style: STextStyles.desktopTextExtraExtraSmall(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveText,
), ),
textAlign: TextAlign.left, ),
),
Text(
feeSelectionResult?.$3 ?? "",
style: STextStyles.desktopTextExtraExtraSmall(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveSearchIconRight,
),
),
],
),
if (isCustomFee) if (isCustomFee)
Padding( Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(

View file

@ -449,6 +449,15 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache {
); );
if (response.value == null) { if (response.value == null) {
if (response.exception != null &&
response.exception!.message
.contains("response is empty but status code is 200")) {
Logging.instance.log(
"No ${tokenContract.name} transfers found for $addressString",
level: LogLevel.Info,
);
return;
}
throw response.exception ?? throw response.exception ??
Exception("Failed to fetch token transaction data"); Exception("Failed to fetch token transaction data");
} }

View file

@ -80,7 +80,7 @@ class PriceAPI {
{required String baseCurrency}) async { {required String baseCurrency}) async {
final now = DateTime.now(); final now = DateTime.now();
if (_lastUsedBaseCurrency != baseCurrency || if (_lastUsedBaseCurrency != baseCurrency ||
now.difference(_lastCalled).inSeconds > 0) { now.difference(_lastCalled) > refreshIntervalDuration) {
_lastCalled = now; _lastCalled = now;
_lastUsedBaseCurrency = baseCurrency; _lastUsedBaseCurrency = baseCurrency;
} else { } else {

View file

@ -157,20 +157,22 @@ class ThemeService {
); );
} else { } else {
// check installed version // check installed version
final theme = ThemeService.instance.getTheme(themeId: "dark"); // final theme = ThemeService.instance.getTheme(themeId: "dark");
if ((theme?.version ?? 1) < _currentDefaultThemeVersion) { // Force update theme to add missing icons for now
Logging.instance.log( // TODO: uncomment if statement in future when themes are version 4 or above
"Updating default dark theme...", // if ((theme?.version ?? 1) < _currentDefaultThemeVersion) {
level: LogLevel.Info, Logging.instance.log(
); "Updating default dark theme...",
final darkZip = await rootBundle.load("assets/default_themes/dark.zip"); level: LogLevel.Info,
await ThemeService.instance );
.install(themeArchiveData: darkZip.buffer.asUint8List()); final darkZip = await rootBundle.load("assets/default_themes/dark.zip");
Logging.instance.log( await ThemeService.instance
"Updating default dark theme... finished", .install(themeArchiveData: darkZip.buffer.asUint8List());
level: LogLevel.Info, Logging.instance.log(
); "Updating default dark theme... finished",
} level: LogLevel.Info,
);
// }
} }
} }

View file

@ -126,7 +126,17 @@ class AddressUtils {
String address, String address,
Map<String, String> params, Map<String, String> params,
) { ) {
String uriString = "${coin.uriScheme}:$address"; // TODO: other sanitation as well ?
String sanitizedAddress = address;
if (coin == Coin.bitcoincash ||
coin == Coin.bitcoincashTestnet ||
coin == Coin.eCash) {
final prefix = "${coin.uriScheme}:";
if (address.startsWith(prefix)) {
sanitizedAddress = address.replaceFirst(prefix, "");
}
}
String uriString = "${coin.uriScheme}:$sanitizedAddress";
if (params.isNotEmpty) { if (params.isNotEmpty) {
uriString += Uri(queryParameters: params).toString(); uriString += Uri(queryParameters: params).toString();
} }

View file

@ -38,7 +38,15 @@ class AmountInputFormatter extends TextInputFormatter {
if (parts.length > 2) { if (parts.length > 2) {
return oldValue; return oldValue;
} }
final fractionDigits =
unit == null ? decimals : max(decimals - unit!.shift, 0);
if (newText.startsWith(decimalSeparator)) { if (newText.startsWith(decimalSeparator)) {
if (newText.length - 1 > fractionDigits) {
newText = newText.substring(0, fractionDigits + 1);
}
return TextEditingValue( return TextEditingValue(
text: newText, text: newText,
selection: TextSelection.collapsed( selection: TextSelection.collapsed(
@ -54,28 +62,24 @@ class AmountInputFormatter extends TextInputFormatter {
fraction = ""; fraction = "";
} }
final fractionDigits =
unit == null ? decimals : max(decimals - unit!.shift, 0);
if (fraction.length > fractionDigits) { if (fraction.length > fractionDigits) {
return oldValue; fraction = fraction.substring(0, fractionDigits);
} }
} }
if (newText.trim() == '' || newText.trim() == '0') { String newString;
return newValue.copyWith(text: ''); final val = BigInt.tryParse(newText);
} else if (BigInt.parse(newText) < BigInt.one) { if (val == null || val < BigInt.one) {
return newValue.copyWith(text: ''); newString = newText;
} else {
// insert group separator
final regex = RegExp(r'\B(?=(\d{3})+(?!\d))');
newString = newText.replaceAllMapped(
regex,
(m) => "${m.group(0)}${numberSymbols?.GROUP_SEP ?? ","}",
);
} }
// insert group separator
final regex = RegExp(r'\B(?=(\d{3})+(?!\d))');
String newString = newText.replaceAllMapped(
regex,
(m) => "${m.group(0)}${numberSymbols?.GROUP_SEP ?? ","}",
);
if (fraction != null) { if (fraction != null) {
newString += decimalSeparator; newString += decimalSeparator;
if (fraction.isNotEmpty) { if (fraction.isNotEmpty) {

View file

@ -65,8 +65,8 @@ class _EXCHANGE {
class _BUY { class _BUY {
const _BUY(); const _BUY();
String simplexLogo(BuildContext context) { String simplexLogo(Brightness themeBrightness) {
switch (MediaQuery.of(context).platformBrightness) { switch (themeBrightness) {
case Brightness.dark: case Brightness.dark:
return "assets/svg/buy/Simplex-Nuvei-Logo-light.svg"; return "assets/svg/buy/Simplex-Nuvei-Logo-light.svg";

View file

@ -16,6 +16,7 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart'; import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/widgets/animated_text.dart'; import 'package:stackwallet/widgets/animated_text.dart';
import 'package:stackwallet/widgets/conditional_parent.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart'; import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart'; import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
@ -234,6 +235,7 @@ class DesktopFeeItem extends ConsumerStatefulWidget {
required this.walletId, required this.walletId,
required this.feeFor, required this.feeFor,
required this.isSelected, required this.isSelected,
this.isButton = true,
}) : super(key: key); }) : super(key: key);
final FeeObject? feeObject; final FeeObject? feeObject;
@ -246,6 +248,7 @@ class DesktopFeeItem extends ConsumerStatefulWidget {
required Coin coin, required Coin coin,
}) feeFor; }) feeFor;
final bool isSelected; final bool isSelected;
final bool isButton;
@override @override
ConsumerState<DesktopFeeItem> createState() => _DesktopFeeItemState(); ConsumerState<DesktopFeeItem> createState() => _DesktopFeeItemState();
@ -291,19 +294,50 @@ class _DesktopFeeItemState extends ConsumerState<DesktopFeeItem> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType : ${widget.feeRateType}"); debugPrint("BUILD: $runtimeType : ${widget.feeRateType}");
return MaterialButton( return ConditionalParent(
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, condition: widget.isButton,
onPressed: () { builder: (child) => MaterialButton(
Navigator.of(context).pop( materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
( onPressed: () {
widget.feeRateType, Navigator.of(context).pop(
feeString, (
timeString, widget.feeRateType,
), feeString,
); timeString,
}, ),
);
},
child: child,
),
child: Builder( child: Builder(
builder: (_) { builder: (_) {
if (!widget.isButton) {
final coin = ref.watch(
walletsChangeNotifierProvider.select(
(value) => value.getManager(widget.walletId).coin,
),
);
if ((coin == Coin.firo || coin == Coin.firoTestNet) &&
ref.watch(publicPrivateBalanceStateProvider.state).state ==
"Private") {
return Text(
"~${ref.watch(pAmountFormatter(coin)).format(
Amount(
rawValue: BigInt.parse("3794"),
fractionDigits: coin.decimals,
),
indicatePrecisionLoss: false,
)}",
style: STextStyles.desktopTextExtraExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveText,
),
textAlign: TextAlign.left,
);
}
}
if (widget.feeRateType == FeeRateType.custom) { if (widget.feeRateType == FeeRateType.custom) {
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,

View file

@ -26,6 +26,7 @@ import 'package:stackwallet/services/ethereum/ethereum_token_service.dart';
import 'package:stackwallet/services/transaction_notification_tracker.dart'; import 'package:stackwallet/services/transaction_notification_tracker.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';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/show_loading.dart'; import 'package:stackwallet/utilities/show_loading.dart';
import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/conditional_parent.dart';
@ -136,17 +137,18 @@ class SimpleWalletCard extends ConsumerWidget {
context: desktopNavigatorState?.context ?? context, context: desktopNavigatorState?.context ?? context,
opaqueBG: true, opaqueBG: true,
message: "Loading ${contract.name}", message: "Loading ${contract.name}",
isDesktop: Util.isDesktop,
); );
if (!success) { if (!success) {
// TODO: show error dialog here?
Logging.instance.log(
"Failed to load token wallet for $contract",
level: LogLevel.Error,
);
return; return;
} }
if (desktopNavigatorState == null) {
// pop loading
nav.pop();
}
if (desktopNavigatorState != null) { if (desktopNavigatorState != null) {
await desktopNavigatorState!.pushNamed( await desktopNavigatorState!.pushNamed(
DesktopTokenView.routeName, DesktopTokenView.routeName,