mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-20 06:08:34 +02:00
improve evm ui (#3129)
* improve evm ui * fix model generation * add db schema * bugfixes * scrollable fav token modal * make combined balance the default * add crypto_full_icons to pubspec * optimize transaction duplication check * fix format issue * add chain icons to swap tiles * decrease asset tile font weight * show chain icon in swap currency selector * move chain icon for tokens * new trade history row * ui fix * fix padding on modal * remove vec
This commit is contained in:
@@ -854,6 +854,9 @@ class SwapAmountBoxState extends State<SwapAmountBox> {
|
||||
.getCryptoSymbol(_selectedCurrency as CryptoCurrency)
|
||||
: _selectedCurrency.name.toUpperCase();
|
||||
|
||||
|
||||
final chainIconPath = (_selectedCurrency is CryptoCurrency) ? _getCurrencyChainIconPath(_selectedCurrency as CryptoCurrency) : null;
|
||||
|
||||
return Column(
|
||||
spacing: 12,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -939,16 +942,38 @@ class SwapAmountBoxState extends State<SwapAmountBox> {
|
||||
currencyToShow,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(width:10),
|
||||
RotatedBox(
|
||||
quarterTurns: 2,
|
||||
child: CakeImageWidget(imageUrl:
|
||||
"assets/new-ui/dropdown_arrow.svg",
|
||||
width: 4,
|
||||
height: 4,
|
||||
colorFilter: ColorFilter.mode(
|
||||
Theme.of(context).colorScheme.primary, BlendMode.srcIn),
|
||||
)),
|
||||
if (chainIconPath != null && chainIconPath.isNotEmpty) ...[
|
||||
SizedBox(width: 4),
|
||||
CakeImageWidget(
|
||||
imageUrl: chainIconPath,
|
||||
width: 12,
|
||||
height: 12,
|
||||
colorFilter: ColorFilter.mode(
|
||||
Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
BlendMode.srcIn),
|
||||
),
|
||||
SizedBox(width: 6)
|
||||
] else
|
||||
SizedBox(width: 10),
|
||||
Container(
|
||||
width:16,height:16,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(9999999999),
|
||||
color: Theme.of(context).colorScheme.surfaceContainerHigh
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: RotatedBox(
|
||||
quarterTurns: 2,
|
||||
child: CakeImageWidget(imageUrl:
|
||||
"assets/new-ui/dropdown_arrow.svg",
|
||||
width: 4,
|
||||
height: 4,
|
||||
colorFilter: ColorFilter.mode(
|
||||
Theme.of(context).colorScheme.primary, BlendMode.srcIn),
|
||||
)),
|
||||
),
|
||||
),
|
||||
SizedBox(width:4),
|
||||
],
|
||||
),
|
||||
@@ -1255,4 +1280,20 @@ class SwapAmountBoxState extends State<SwapAmountBox> {
|
||||
if (s.length <= head + tail + 3) return s;
|
||||
return s.substring(0, head) + '...' + s.substring(s.length - tail);
|
||||
}
|
||||
|
||||
String? _getCurrencyChainIconPath(CryptoCurrency curr) {
|
||||
try{
|
||||
|
||||
if(curr.chainIconPath != null) return curr.chainIconPath!;
|
||||
|
||||
|
||||
if(curr.tag != null) {
|
||||
final currencyFromTag = CryptoCurrency.fromString(curr.tag!);
|
||||
if(currencyFromTag.chainIconPath != null) {
|
||||
return currencyFromTag.chainIconPath!;
|
||||
}
|
||||
}
|
||||
}catch(_){}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/unspent_coin_type.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
|
||||
|
||||
enum AssetDetailsModalModes { normal, ltcTransparent, ltcPrivate }
|
||||
@@ -60,6 +59,7 @@ class AssetDetailsModal extends StatelessWidget {
|
||||
title: "",
|
||||
trailingIcon: Icon(Icons.close),
|
||||
onTrailingPressed: Navigator.of(context).pop,
|
||||
padding: EdgeInsets.only(top:12,right:18),
|
||||
),
|
||||
SafeArea(
|
||||
child: Column(
|
||||
@@ -89,25 +89,25 @@ class AssetDetailsModal extends StatelessWidget {
|
||||
fontSize: 28, color: Theme.of(context).colorScheme.onPrimary),
|
||||
)),
|
||||
),
|
||||
if (chainIconPath.isNotEmpty)
|
||||
Align(
|
||||
alignment: Alignment.bottomRight,
|
||||
child: Container(
|
||||
decoration: ShapeDecoration(
|
||||
shape: RoundedSuperellipseBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
side: BorderSide(color: Colors.black)),
|
||||
color: Colors.white),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: CakeImageWidget(imageUrl:
|
||||
chainIconPath,
|
||||
width: 18,
|
||||
height: 18,
|
||||
colorFilter:
|
||||
ColorFilter.mode(Colors.black, BlendMode.srcIn),
|
||||
),
|
||||
)))
|
||||
// if (chainIconPath.isNotEmpty)
|
||||
// Align(
|
||||
// alignment: Alignment.bottomRight,
|
||||
// child: Container(
|
||||
// decoration: ShapeDecoration(
|
||||
// shape: RoundedSuperellipseBorder(
|
||||
// borderRadius: BorderRadius.circular(8),
|
||||
// side: BorderSide(color: Colors.black)),
|
||||
// color: Colors.white),
|
||||
// child: Padding(
|
||||
// padding: const EdgeInsets.all(4.0),
|
||||
// child: CakeImageWidget(imageUrl:
|
||||
// chainIconPath,
|
||||
// width: 18,
|
||||
// height: 18,
|
||||
// colorFilter:
|
||||
// ColorFilter.mode(Colors.black, BlendMode.srcIn),
|
||||
// ),
|
||||
// )))
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -125,14 +125,16 @@ class AssetDetailsModal extends StatelessWidget {
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.onSurface),
|
||||
),
|
||||
if(asset != null)
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surfaceContainerHigh,
|
||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||
borderRadius: BorderRadius.circular(999999999)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4),
|
||||
|
||||
child: Text(
|
||||
chainTitle,
|
||||
asset?.title??"",
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant),
|
||||
),
|
||||
@@ -141,11 +143,22 @@ class AssetDetailsModal extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
if (subtitle.isNotEmpty)
|
||||
Text(
|
||||
subtitle,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
spacing: 4,
|
||||
children: [
|
||||
if(chainIconPath.isNotEmpty)
|
||||
CakeImageWidget(
|
||||
imageUrl: chainIconPath,
|
||||
width:16,height:16,colorFilter: ColorFilter.mode(Theme.of(context).colorScheme.onSurfaceVariant,BlendMode.srcIn),
|
||||
),
|
||||
Text(
|
||||
subtitle,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -17,7 +17,7 @@ class AssetTile extends StatelessWidget {
|
||||
this.title,
|
||||
this.trailingText,
|
||||
this.modalMode = AssetDetailsModalModes.normal,
|
||||
required this.wallet, required this.showSwap});
|
||||
required this.wallet, required this.showSwap, required this.isFirst, required this.isLast});
|
||||
|
||||
final BalanceRecord balance;
|
||||
final bool showSecondary;
|
||||
@@ -27,6 +27,8 @@ class AssetTile extends StatelessWidget {
|
||||
final String? trailingText;
|
||||
final AssetDetailsModalModes modalMode;
|
||||
final WalletBase wallet;
|
||||
final bool isFirst;
|
||||
final bool isLast;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -42,8 +44,8 @@ class AssetTile extends StatelessWidget {
|
||||
showSwap: showSwap,
|
||||
asset: balance.asset,
|
||||
title: title ?? balance.asset.fullName ?? balance.asset.name,
|
||||
chainTitle: _getChainTitle(),
|
||||
subtitle: trailingText ?? "",
|
||||
chainTitle: "",
|
||||
subtitle: trailingText ?? _getChainTitle(),
|
||||
amount: showSecondary ? balance.secondAvailableBalance : balance.availableBalance,
|
||||
currencyTitle: balance.asset.title,
|
||||
fiatAmount: showSecondary
|
||||
@@ -57,23 +59,15 @@ class AssetTile extends StatelessWidget {
|
||||
});
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18.0, vertical: 6.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18.0),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: 80,
|
||||
height: 72,
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
Theme.of(context).colorScheme.surfaceContainerHigh,
|
||||
Theme.of(context).colorScheme.surfaceContainer,
|
||||
],
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
),
|
||||
borderRadius: BorderRadius.all(Radius.circular(20)),
|
||||
border: Border.all(
|
||||
color: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||
width: 1,
|
||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||
borderRadius: BorderRadius.vertical(
|
||||
top: isFirst ? Radius.circular(18) : Radius.zero,
|
||||
bottom: isLast ? Radius.circular(18) : Radius.zero,
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
@@ -87,16 +81,16 @@ class AssetTile extends StatelessWidget {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
width: 45,
|
||||
height: 45,
|
||||
width: 36,
|
||||
height: 36,
|
||||
child: Stack(
|
||||
children: [
|
||||
if((iconPath).isNotEmpty)
|
||||
CakeImageWidget(imageUrl: iconPath)
|
||||
else
|
||||
Container(
|
||||
width: 45,
|
||||
height: 45,
|
||||
width: 36,
|
||||
height: 36,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
borderRadius: BorderRadius.circular(99999)),
|
||||
@@ -107,27 +101,27 @@ class AssetTile extends StatelessWidget {
|
||||
fontSize: 20, color: Theme.of(context).colorScheme.onPrimary),
|
||||
)),
|
||||
),
|
||||
if (chainIconPath.isNotEmpty)
|
||||
Align(
|
||||
alignment: Alignment.bottomRight,
|
||||
child: Container(
|
||||
decoration: ShapeDecoration(
|
||||
shape: RoundedSuperellipseBorder(
|
||||
borderRadius: BorderRadius.circular(5),side: BorderSide(color: Colors.black)),
|
||||
color: Colors.white),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(2.0),
|
||||
child: CakeImageWidget(
|
||||
imageUrl: chainIconPath,
|
||||
width: 12,
|
||||
height: 12,
|
||||
colorFilter:
|
||||
ColorFilter.mode(Colors.black, BlendMode.srcIn),
|
||||
),
|
||||
)))
|
||||
// if (chainIconPath.isNotEmpty)
|
||||
// Align(
|
||||
// alignment: Alignment.bottomRight,
|
||||
// child: Container(
|
||||
// decoration: ShapeDecoration(
|
||||
// shape: RoundedSuperellipseBorder(
|
||||
// borderRadius: BorderRadius.circular(5),side: BorderSide(color: Colors.black)),
|
||||
// color: Colors.white),
|
||||
// child: Padding(
|
||||
// padding: const EdgeInsets.all(2.0),
|
||||
// child: CakeImageWidget(
|
||||
// imageUrl: chainIconPath,
|
||||
// width: 12,
|
||||
// height: 12,
|
||||
// colorFilter:
|
||||
// ColorFilter.mode(Colors.black, BlendMode.srcIn),
|
||||
// ),
|
||||
// )))
|
||||
],
|
||||
)),
|
||||
SizedBox(width: 8.0),
|
||||
SizedBox(width: 12.0),
|
||||
Expanded(
|
||||
child: Column(
|
||||
spacing: 4.0,
|
||||
@@ -139,7 +133,7 @@ class AssetTile extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
title ?? balance.asset.fullName ?? balance.asset.name,
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
style: TextStyle(fontWeight: FontWeight.w500),
|
||||
),
|
||||
if(trailingText != null)
|
||||
Text(
|
||||
@@ -184,9 +178,9 @@ class AssetTile extends StatelessWidget {
|
||||
|
||||
String _getChainTitle() {
|
||||
try {
|
||||
return CryptoCurrency.fromString(wallet.currency.tag ??wallet.currency.title).title;
|
||||
return CryptoCurrency.fromString(wallet.currency.tag ??wallet.currency.title).fullName ?? "";
|
||||
} catch(e) {
|
||||
return wallet.currency.title;
|
||||
return wallet.currency.fullName ?? "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,11 +21,22 @@ class AssetsSection extends StatelessWidget {
|
||||
child: Observer(
|
||||
builder: (context) {
|
||||
final hasMweb = dashboardViewModel.hasMweb && dashboardViewModel.mwebEnabled;
|
||||
return ListView.builder(
|
||||
return ListView.separated(
|
||||
shrinkWrap: true,
|
||||
padding: EdgeInsets.zero,
|
||||
padding: EdgeInsets.symmetric(vertical: 18),
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemCount: dashboardViewModel.balanceViewModel.formattedBalances.length + (hasMweb ? 1 : 0),
|
||||
separatorBuilder: (context, index) => Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18.0),
|
||||
child: Container(
|
||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||
height:1,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: Container(color: Theme.of(context).colorScheme.surfaceContainerHigh,),
|
||||
),
|
||||
),
|
||||
),
|
||||
itemBuilder: (context, index) {
|
||||
return Observer(builder: (context) {
|
||||
if (hasMweb) {
|
||||
@@ -39,6 +50,8 @@ class AssetsSection extends StatelessWidget {
|
||||
modalMode: index > 0
|
||||
? AssetDetailsModalModes.ltcPrivate
|
||||
: AssetDetailsModalModes.ltcTransparent,
|
||||
isFirst: index == 0,
|
||||
isLast: index != 0,
|
||||
title: index > 0 ? "Litecoin Private" : null,
|
||||
);
|
||||
}
|
||||
@@ -48,6 +61,8 @@ class AssetsSection extends StatelessWidget {
|
||||
showSwap: dashboardViewModel.isEnabledSwapAction,
|
||||
balance: balance,
|
||||
wallet: dashboardViewModel.wallet,
|
||||
isFirst: index == 0,
|
||||
isLast: index == dashboardViewModel.balanceViewModel.formattedBalances.length-1,
|
||||
chainIconPath: _getChainIconPath(),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -69,6 +69,8 @@ class HistorySection extends StatelessWidget {
|
||||
CryptoCurrency? asset;
|
||||
if (transaction.additionalInfo["isLightning"] == true)
|
||||
asset = CryptoCurrency.btcln;
|
||||
else
|
||||
asset = item.assetOfTransaction;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
@@ -80,6 +82,8 @@ class HistorySection extends StatelessWidget {
|
||||
date: DateFormat('HH:mm').format(transaction.date),
|
||||
amount: item.formattedCryptoAmount,
|
||||
amountFiat: item.formattedFiatAmount,
|
||||
hasTokens: item.hasTokens,
|
||||
chainIconPath: _getChainIconPath(),
|
||||
roundedBottom: roundedBottom,
|
||||
roundedTop: roundedTop,
|
||||
bottomSeparator: !roundedBottom,
|
||||
@@ -101,6 +105,7 @@ class HistorySection extends StatelessWidget {
|
||||
child: HistoryTradeTile(
|
||||
from: tradeFrom!,
|
||||
to: tradeTo!,
|
||||
provider: trade.provider,
|
||||
date: DateFormat('HH:mm').format(item.trade.createdAt!),
|
||||
amount: trade.amountFormatted(),
|
||||
receiveAmount: trade.receiveAmountFormatted(),
|
||||
@@ -171,4 +176,12 @@ class HistorySection extends StatelessWidget {
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
String _getChainIconPath() {
|
||||
try {
|
||||
return CryptoCurrency.fromString(dashboardViewModel.wallet.currency.tag ??dashboardViewModel.wallet.currency.title).chainIconPath!;
|
||||
} catch(e) {
|
||||
return dashboardViewModel.wallet.currency.chainIconPath ?? "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ class HistoryTile extends StatelessWidget {
|
||||
required this.direction,
|
||||
required this.pending,
|
||||
required this.bottomSeparator,
|
||||
required this.hasTokens,
|
||||
this.chainIconPath,
|
||||
this.asset,
|
||||
});
|
||||
|
||||
@@ -27,6 +29,8 @@ class HistoryTile extends StatelessWidget {
|
||||
final bool roundedTop;
|
||||
final bool roundedBottom;
|
||||
final bool bottomSeparator;
|
||||
final bool hasTokens;
|
||||
final String? chainIconPath;
|
||||
final TransactionDirection direction;
|
||||
final bool pending;
|
||||
final CryptoCurrency? asset;
|
||||
@@ -93,6 +97,33 @@ class HistoryTile extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
if(hasTokens) {
|
||||
return Stack(children: [
|
||||
Opacity(
|
||||
opacity: pending ? 0.5 : 1,
|
||||
child: CakeImageWidget(imageUrl: asset?.iconSvgPath ?? asset?.iconPath ??"", width: 34,
|
||||
height: 34,),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.bottomRight,
|
||||
child: Container(
|
||||
decoration: ShapeDecoration(
|
||||
shape: RoundedSuperellipseBorder(
|
||||
borderRadius: BorderRadius.circular(5),side: BorderSide(color: Colors.black)),
|
||||
color: Colors.white),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(2.0),
|
||||
child: CakeImageWidget(
|
||||
imageUrl: chainIconPath,
|
||||
width: 12,
|
||||
height: 12,
|
||||
colorFilter:
|
||||
ColorFilter.mode(Colors.black, BlendMode.srcIn),
|
||||
),
|
||||
)))
|
||||
],);
|
||||
}
|
||||
|
||||
return CakeImageWidget(imageUrl:_getDirectionIcon(),
|
||||
colorFilter: ColorFilter.mode(
|
||||
direction == TransactionDirection.outgoing
|
||||
|
||||
@@ -4,22 +4,32 @@ import 'package:flutter/material.dart';
|
||||
class HistoryTileBase extends StatelessWidget {
|
||||
const HistoryTileBase({
|
||||
super.key,
|
||||
required this.title,
|
||||
this.title,
|
||||
this.titleWidget,
|
||||
required this.date,
|
||||
required this.amount,
|
||||
this.amount,
|
||||
required this.leadingIcon,
|
||||
required this.amountFiat,
|
||||
this.amountFiat,
|
||||
required this.roundedTop,
|
||||
required this.roundedBottom,
|
||||
required this.bottomSeparator,
|
||||
this.primaryTextColor,
|
||||
this.asset,
|
||||
});
|
||||
this.amountWidget,
|
||||
this.amountFiatWidget,
|
||||
}) : assert((title != null || titleWidget != null) && (title == null || titleWidget == null)),
|
||||
assert(
|
||||
(amountWidget != null || amount != null) && (amountWidget == null || amount == null)),
|
||||
assert((amountFiatWidget != null || amountFiat != null) &&
|
||||
(amountFiatWidget == null || amountFiat == null));
|
||||
|
||||
final String title;
|
||||
final String? title;
|
||||
final Widget? titleWidget;
|
||||
final String date;
|
||||
final String amount;
|
||||
final String amountFiat;
|
||||
final String? amount;
|
||||
final Widget? amountWidget;
|
||||
final String? amountFiat;
|
||||
final Widget? amountFiatWidget;
|
||||
final Widget leadingIcon;
|
||||
final bool roundedTop;
|
||||
final bool roundedBottom;
|
||||
@@ -105,8 +115,10 @@ class HistoryTileBase extends StatelessWidget {
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(title,
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.onSurface)),
|
||||
if(title != null)
|
||||
Text(title!,
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.onSurface))
|
||||
else if(titleWidget != null) titleWidget!,
|
||||
Text(date,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant)),
|
||||
@@ -115,12 +127,20 @@ class HistoryTileBase extends StatelessWidget {
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Text(amount,
|
||||
style: TextStyle(
|
||||
color: primaryTextColor ??
|
||||
Theme.of(context).colorScheme.onSurface)),
|
||||
Text(amountFiat, style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant)),
|
||||
],
|
||||
if (amount != null)
|
||||
Text(amount!,
|
||||
style: TextStyle(
|
||||
color: primaryTextColor ??
|
||||
Theme.of(context).colorScheme.onSurface))
|
||||
else if (amountWidget != null)
|
||||
amountWidget!,
|
||||
if (amountFiat != null)
|
||||
Text(amountFiat!,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant))
|
||||
else if (amountFiatWidget != null)
|
||||
amountFiatWidget!
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/coins_page/assets_history/history_tile_base.dart';
|
||||
import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
|
||||
import 'package:cw_core/crypto_amount_format.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@@ -14,10 +17,12 @@ class HistoryTradeTile extends StatelessWidget {
|
||||
required this.bottomSeparator,
|
||||
required this.from,
|
||||
required this.to,
|
||||
required this.swapState});
|
||||
required this.swapState,
|
||||
required this.provider});
|
||||
|
||||
final CryptoCurrency from;
|
||||
final CryptoCurrency to;
|
||||
final ExchangeProviderDescription provider;
|
||||
final String date;
|
||||
final String amount;
|
||||
final String receiveAmount;
|
||||
@@ -34,7 +39,7 @@ class HistoryTradeTile extends StatelessWidget {
|
||||
width: 50,
|
||||
child: Stack(
|
||||
children: [
|
||||
Image.asset(_getIconPath(from),
|
||||
CakeImageWidget(imageUrl: _getIconPath(from),
|
||||
width: currencyIconSize, height: currencyIconSize),
|
||||
Positioned(
|
||||
top: currencyIconSize / 2,
|
||||
@@ -45,7 +50,7 @@ class HistoryTradeTile extends StatelessWidget {
|
||||
width: 2,
|
||||
color: Theme.of(context).colorScheme.surfaceContainer),
|
||||
shape: BoxShape.circle),
|
||||
child: Image.asset(_getIconPath(to),
|
||||
child: CakeImageWidget(imageUrl: _getIconPath(to),
|
||||
width: currencyIconSize, height: currencyIconSize))),
|
||||
],
|
||||
),
|
||||
@@ -56,12 +61,55 @@ class HistoryTradeTile extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
final fromChainIcon = _getChainIcon(from);
|
||||
final toChainIcon = _getChainIcon(to);
|
||||
|
||||
return HistoryTileBase(
|
||||
title:
|
||||
"${from.toString()}${from == CryptoCurrency.btcln ? "-LN" : ""} → ${to.toString()}${to == CryptoCurrency.btcln ? "-LN" : ""}",
|
||||
// title:
|
||||
// "${from.toString()}${from == CryptoCurrency.btcln ? "-LN" : ""} → ${to.toString()}${to == CryptoCurrency.btcln ? "-LN" : ""}",
|
||||
titleWidget: Row(
|
||||
spacing: 4,
|
||||
children: [
|
||||
Text(swapState.title),
|
||||
CakeImageWidget(imageUrl: provider.image, width: 14, height: 14)
|
||||
],
|
||||
),
|
||||
date: date,
|
||||
amount: amount,
|
||||
amountFiat: receiveAmount,
|
||||
amountFiatWidget: Row(
|
||||
spacing: 4,
|
||||
children: [
|
||||
Text("-", style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant)),
|
||||
Text(amount.withMaxDecimals(8),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
fontWeight: FontWeight.w500)),
|
||||
Text(from.title, style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant)),
|
||||
if (fromChainIcon.isNotEmpty)
|
||||
CakeImageWidget(
|
||||
imageUrl: fromChainIcon,
|
||||
width: 12,
|
||||
height: 12,
|
||||
colorFilter:
|
||||
ColorFilter.mode(Theme.of(context).colorScheme.onSurfaceVariant, BlendMode.srcIn),
|
||||
)
|
||||
],
|
||||
),
|
||||
amountWidget: Row(
|
||||
spacing: 4,
|
||||
children: [
|
||||
Text(
|
||||
"+",
|
||||
),
|
||||
Text(
|
||||
receiveAmount.withMaxDecimals(8),
|
||||
style: TextStyle(fontWeight: FontWeight.w500),
|
||||
),
|
||||
Text(
|
||||
to.title,
|
||||
),
|
||||
if (toChainIcon.isNotEmpty) CakeImageWidget(imageUrl: toChainIcon, width: 12, height: 12)
|
||||
],
|
||||
),
|
||||
leadingIcon: _getLeadingStack(context),
|
||||
roundedTop: roundedTop,
|
||||
roundedBottom: roundedBottom,
|
||||
@@ -93,4 +141,21 @@ class HistoryTradeTile extends StatelessWidget {
|
||||
//TODO approporiate fallback
|
||||
return "";
|
||||
}
|
||||
|
||||
String _getChainIcon(CryptoCurrency currency) {
|
||||
try {
|
||||
if (currency.chainIconPath != null) {
|
||||
return currency.chainIconPath!;
|
||||
}
|
||||
|
||||
if ((currency.tag ?? "").isNotEmpty) {
|
||||
final currencyFromTag = CryptoCurrency.fromString(currency.tag!);
|
||||
if (currencyFromTag.chainIconPath != null) {
|
||||
return currencyFromTag.chainIconPath!;
|
||||
}
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
|
||||
import 'package:cw_core/card_design.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -25,11 +26,13 @@ class BalanceCard extends StatelessWidget {
|
||||
this.balance = "",
|
||||
this.fiatBalance = "",
|
||||
this.assetName = "",
|
||||
this.fiatCurrencyTitle = "",
|
||||
this.designSwitchDuration = const Duration(),
|
||||
this.actions = const [],
|
||||
this.capitalizeAssetName = true,
|
||||
this.onCustomizeTapped,
|
||||
this.accountIndex
|
||||
this.accountIndex,
|
||||
this.fiatFirst = false
|
||||
});
|
||||
|
||||
final double width;
|
||||
@@ -39,6 +42,8 @@ class BalanceCard extends StatelessWidget {
|
||||
final String accountName;
|
||||
final String balance;
|
||||
final String fiatBalance;
|
||||
final String fiatCurrencyTitle;
|
||||
final bool fiatFirst;
|
||||
final int? accountIndex;
|
||||
final bool capitalizeAssetName;
|
||||
final String assetName;
|
||||
@@ -53,14 +58,21 @@ class BalanceCard extends StatelessWidget {
|
||||
final Duration textFadeDuration = Duration(milliseconds: 80);
|
||||
final double iconWidth = width * 0.15;
|
||||
|
||||
final name = fiatFirst ? fiatCurrencyTitle : assetName;
|
||||
final resolvedAssetName = capitalizeAssetName ? name.toUpperCase() : name.toLowerCase();
|
||||
|
||||
final leadText = fiatFirst ? S.of(context).wallet_balance : accountName;
|
||||
|
||||
final bool showText = accountBalance.isNotEmpty ||
|
||||
accountName.isNotEmpty ||
|
||||
leadText.isNotEmpty ||
|
||||
balance.isNotEmpty ||
|
||||
fiatBalance.isNotEmpty ||
|
||||
assetName.isNotEmpty;
|
||||
resolvedAssetName.isNotEmpty;
|
||||
|
||||
final height = width * 0.62;
|
||||
|
||||
|
||||
|
||||
return AnimatedContainer(
|
||||
duration: designSwitchDuration,
|
||||
width: width,
|
||||
@@ -105,7 +117,7 @@ class BalanceCard extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
if(accountName.isNotEmpty || accountBalance.isNotEmpty)
|
||||
if(leadText.isNotEmpty || accountBalance.isNotEmpty)
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
@@ -127,8 +139,8 @@ class BalanceCard extends StatelessWidget {
|
||||
AnimatedDefaultTextStyle(
|
||||
duration: designSwitchDuration,
|
||||
style: Theme.of(context).textTheme.titleMedium!.copyWith(
|
||||
fontWeight: FontWeight.w500, color: design.colors.textColor),
|
||||
child: Text(accountName),
|
||||
fontWeight: FontWeight.w500, color: design.colors.textColor.withAlpha(leadText == accountName ? 255 : 128)),
|
||||
child: Text(leadText),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -157,7 +169,7 @@ class BalanceCard extends StatelessWidget {
|
||||
);
|
||||
},
|
||||
child: Row(
|
||||
key: ValueKey("$balance ${assetName.toUpperCase()}"),
|
||||
key: ValueKey("$balance ${resolvedAssetName.toUpperCase()}"),
|
||||
spacing: 8.0,
|
||||
children: [
|
||||
AnimatedDefaultTextStyle(
|
||||
@@ -165,14 +177,14 @@ class BalanceCard extends StatelessWidget {
|
||||
style: DefaultTextStyle.of(context)
|
||||
.style
|
||||
.copyWith(color: design.colors.textColor, fontSize: 28, fontWeight: FontWeight.w500, letterSpacing: -0.4),
|
||||
child: Text(balance),
|
||||
child: Text(fiatFirst ? fiatBalance : balance),
|
||||
),
|
||||
AnimatedDefaultTextStyle(
|
||||
duration: designSwitchDuration,
|
||||
style: DefaultTextStyle.of(context)
|
||||
.style
|
||||
.copyWith(color: design.colors.textColorSecondary, fontSize: 28, fontWeight: FontWeight.w400, letterSpacing: -0.4),
|
||||
child: Text(capitalizeAssetName ? assetName.toUpperCase() : assetName.toLowerCase()),
|
||||
child: Text(resolvedAssetName),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -196,8 +208,8 @@ class BalanceCard extends StatelessWidget {
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
key: ValueKey(fiatBalance),
|
||||
fiatBalance,
|
||||
key: ValueKey(fiatFirst ? balance : fiatBalance),
|
||||
fiatFirst ? "$assetName $balance" : "$fiatCurrencyTitle $fiatBalance",
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -115,8 +115,7 @@ class _CardsViewState extends State<CardsView> {
|
||||
|
||||
// The second balance should always be the lightning balance
|
||||
// printV(widget.dashboardViewModel.balanceViewModel.formattedBalances.first.availableBalance);
|
||||
final walletBalanceRecord = widget.dashboardViewModel.balanceViewModel.formattedBalances
|
||||
.elementAtOrNull(widget.lightningMode ? 1 : 0);
|
||||
final walletBalanceRecord = widget.dashboardViewModel.balanceViewModel.getMainBalanceRecord(widget.lightningMode);
|
||||
|
||||
late final String walletBalance;
|
||||
late final String walletFiatBalance;
|
||||
@@ -128,11 +127,16 @@ class _CardsViewState extends State<CardsView> {
|
||||
walletBalance = walletBalanceRecord?.combinedAvailableBalance ?? "0";
|
||||
walletFiatBalance = walletBalanceRecord?.combinedFiatAvailableBalance ?? "0.00";
|
||||
}
|
||||
} else {
|
||||
} else if(widget.dashboardViewModel.balanceViewModel.showCombinedBalance){
|
||||
walletBalance = "";
|
||||
walletFiatBalance = widget.dashboardViewModel.balanceViewModel.combinedFiatBalance;
|
||||
|
||||
}else {
|
||||
walletBalance = walletBalanceRecord?.availableBalance ?? "0";
|
||||
walletFiatBalance = walletBalanceRecord?.fiatAvailableBalance ?? "${widget.dashboardViewModel.appStore.settingsStore.fiatCurrency.title} 0.00";
|
||||
walletFiatBalance = walletBalanceRecord?.fiatAvailableBalanceRaw ?? "0.00";
|
||||
}
|
||||
|
||||
|
||||
// the card designs is empty if widget gets built before it loads.
|
||||
// should get populated before user sees anything
|
||||
final CardDesign cardDesign;
|
||||
@@ -154,6 +158,8 @@ class _CardsViewState extends State<CardsView> {
|
||||
accountBalance = account.balance ?? "0.00";
|
||||
}
|
||||
|
||||
final assetName = widget.dashboardViewModel.balanceViewModel.showCombinedBalance ? "" : walletBalanceRecord?.formattedAssetTitle ?? assetTitleFallback;
|
||||
|
||||
final List<BalanceCardAction> actions = widget.lightningMode
|
||||
? [
|
||||
BalanceCardAction(
|
||||
@@ -183,9 +189,11 @@ class _CardsViewState extends State<CardsView> {
|
||||
accountName: accountName,
|
||||
accountBalance: accountBalance,
|
||||
designSwitchDuration: Duration(milliseconds: 150),
|
||||
assetName: walletBalanceRecord?.formattedAssetTitle ?? assetTitleFallback,
|
||||
assetName: assetName,
|
||||
capitalizeAssetName: _shouldCapitalizeAssetName(),
|
||||
balance: walletBalance,
|
||||
fiatCurrencyTitle: walletBalanceRecord?.fiatCurrencyTicker ?? widget.dashboardViewModel.settingsStore.fiatCurrency.title,
|
||||
fiatFirst: widget.dashboardViewModel.balanceViewModel.showCombinedBalance,
|
||||
fiatBalance: walletFiatBalance,
|
||||
selected: _selectedIndex == visualIndex,
|
||||
onCustomizeTapped: _selectedIndex == visualIndex ? widget.onCustomizeTapped : null,
|
||||
|
||||
@@ -12,6 +12,7 @@ class ModalTopBar extends StatelessWidget {
|
||||
this.onTrailingPressed=nothing,
|
||||
this.leadingIcon,
|
||||
this.trailingIcon,
|
||||
this.padding,
|
||||
this.leadingWidget,
|
||||
this.trailingWidget}) {
|
||||
if(leadingIcon != null && leadingWidget != null) {
|
||||
@@ -27,6 +28,7 @@ class ModalTopBar extends StatelessWidget {
|
||||
final VoidCallback onLeadingPressed;
|
||||
final VoidCallback onTrailingPressed;
|
||||
final Widget? leadingIcon;
|
||||
final EdgeInsets? padding;
|
||||
final Widget? trailingIcon;
|
||||
final Widget? leadingWidget;
|
||||
final Widget? trailingWidget;
|
||||
@@ -36,7 +38,7 @@ class ModalTopBar extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(18),
|
||||
padding: padding??EdgeInsets.all(18),
|
||||
child: Stack(
|
||||
alignment: Alignment.topCenter,
|
||||
children: [
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_regular_row.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
|
||||
import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class FavoriteTokenModal extends StatelessWidget {
|
||||
const FavoriteTokenModal({super.key, required this.tokens});
|
||||
|
||||
final List<CryptoCurrency> tokens;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(18))
|
||||
),
|
||||
child: SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
ModalTopBar(
|
||||
title: S.of(context).favorite_token,
|
||||
leadingIcon: Icon(Icons.close),
|
||||
onLeadingPressed: Navigator.of(context).pop,
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
S.of(context).favorite_token_desc,
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant),
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
child: SingleChildScrollView(
|
||||
child: NewListSections(
|
||||
sections: {
|
||||
"": tokens
|
||||
.map((item) => ListItemRegularRow(
|
||||
keyValue: item.title,
|
||||
label: "${item.fullName} (${item.title})",
|
||||
iconPath: item.iconPath,
|
||||
onTap: () => Navigator.of(context).pop(item)))
|
||||
.toList()
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,23 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:cake_wallet/core/address_validator.dart';
|
||||
import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_regular_row.dart';
|
||||
import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_toggle.dart';
|
||||
import 'package:cake_wallet/entities/sort_balance_types.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/new-ui/pages/settings_page.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/favorite_token_modal.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
|
||||
import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart';
|
||||
import 'package:cake_wallet/src/widgets/picker.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/home_settings_view_model.dart';
|
||||
@@ -28,24 +37,79 @@ class HomeSettingsPage extends BasePage {
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
Observer(
|
||||
builder: (_) => SettingsPickerCell<SortBalanceBy>(
|
||||
title: S.current.sort_by,
|
||||
items: SortBalanceBy.values,
|
||||
selectedItem: _homeSettingsViewModel.sortBalanceBy,
|
||||
onItemSelected: _homeSettingsViewModel.setSortBalanceBy,
|
||||
),
|
||||
),
|
||||
// Observer(
|
||||
// builder: (_) => SettingsPickerCell<SortBalanceBy>(
|
||||
// title: S.current.sort_by,
|
||||
// items: SortBalanceBy.values,
|
||||
// selectedItem: _homeSettingsViewModel.sortBalanceBy,
|
||||
// onItemSelected: _homeSettingsViewModel.setSortBalanceBy,
|
||||
// ),
|
||||
// ),
|
||||
// Divider(color: Theme.of(context).colorScheme.outlineVariant),
|
||||
// Observer(
|
||||
// builder: (_) => SettingsSwitcherCell(
|
||||
// title: S.of(context).pin_at_top(_homeSettingsViewModel.nativeToken.title),
|
||||
// value: _homeSettingsViewModel.pinNativeToken,
|
||||
// title: S.of(context).show_combined_balance,
|
||||
// value: _homeSettingsViewModel.showCombinedBalance,
|
||||
// onValueChange: (_, bool value) {
|
||||
// _homeSettingsViewModel.setPinNativeToken(value);
|
||||
// _homeSettingsViewModel.setShowCombinedBalance(value);
|
||||
// },
|
||||
// ),
|
||||
// ),
|
||||
// Observer(
|
||||
// builder: (_) => _homeSettingsViewModel.showCombinedBalance
|
||||
// ? SizedBox.shrink()
|
||||
// : SettingsCellWithArrow(
|
||||
// title: S.of(context).favorite_token,
|
||||
// handler: (context) async {
|
||||
//
|
||||
// },
|
||||
// )),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
child: Observer(
|
||||
builder: (_) => NewListSections(sections: {
|
||||
"": [
|
||||
ListItemRegularRow(
|
||||
keyValue: "sort balance by",
|
||||
label: S.of(context).sort_by,
|
||||
trailingText: _homeSettingsViewModel.sortBalanceBy.toString(),
|
||||
onTap: () {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (context) => Picker(
|
||||
items: SortBalanceBy.values,
|
||||
selectedAtIndex:
|
||||
SortBalanceBy.values.indexOf(_homeSettingsViewModel.sortBalanceBy),
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
onItemSelected: _homeSettingsViewModel.setSortBalanceBy,
|
||||
isSeparated: false,
|
||||
),
|
||||
);
|
||||
}),
|
||||
ListItemToggle(
|
||||
keyValue: "show combined",
|
||||
label: S.of(context).show_combined_balance,
|
||||
value: _homeSettingsViewModel.showCombinedBalance,
|
||||
onChanged: (val) => _homeSettingsViewModel.setShowCombinedBalance(val)),
|
||||
if (!_homeSettingsViewModel.showCombinedBalance)
|
||||
ListItemRegularRow(
|
||||
keyValue: "fav token",
|
||||
label: S.of(context).favorite_token,
|
||||
trailingText: _homeSettingsViewModel.favoriteToken.title,
|
||||
showArrow: true,
|
||||
onTap: () async {
|
||||
final res = await showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) =>
|
||||
FavoriteTokenModal(tokens: _homeSettingsViewModel.enabledTokens));
|
||||
if (res != null && res is CryptoCurrency) {
|
||||
_homeSettingsViewModel.setFavoriteToken(res);
|
||||
}
|
||||
})
|
||||
]
|
||||
}),
|
||||
),
|
||||
),
|
||||
Divider(color: Theme.of(context).colorScheme.outlineVariant),
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
|
||||
@@ -152,6 +152,7 @@ class TokenUtilities {
|
||||
required WalletType walletType,
|
||||
required String address,
|
||||
}) async {
|
||||
if(address.isEmpty) return null;
|
||||
final lower = address.toLowerCase();
|
||||
switch (walletType) {
|
||||
case WalletType.ethereum:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/core/utilities.dart';
|
||||
import 'package:cake_wallet/entities/balance_display_mode.dart';
|
||||
import 'package:cake_wallet/entities/calculate_fiat_amount.dart';
|
||||
import 'package:cake_wallet/entities/fiat_api_mode.dart';
|
||||
@@ -6,8 +7,12 @@ import 'package:cake_wallet/entities/sort_balance_types.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||
import 'package:cake_wallet/evm/evm.dart';
|
||||
import 'package:cake_wallet/solana/solana.dart';
|
||||
import 'package:cake_wallet/tron/tron.dart';
|
||||
import 'package:cake_wallet/zano/zano.dart';
|
||||
import 'package:cw_core/crypto_amount_format.dart';
|
||||
import 'package:cw_core/transaction_history.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
|
||||
@@ -57,11 +62,16 @@ class BalanceRecord {
|
||||
.toString().withMaxDecimals(8);
|
||||
|
||||
String get combinedFiatAvailableBalance =>
|
||||
fiatAvailableBalance.split(" ").first +
|
||||
fiatCurrencyTicker +
|
||||
" " +
|
||||
((double.tryParse(fiatAvailableBalance.split(" ").last) ?? 0) +
|
||||
(double.tryParse(fiatSecondAvailableBalance.split(" ").last) ?? 0))
|
||||
.toString().withMaxDecimals(8);
|
||||
((double.tryParse(fiatAvailableBalanceRaw) ?? 0) +
|
||||
(double.tryParse(fiatSecondAvailableBalanceRaw) ?? 0))
|
||||
.toString()
|
||||
.withMaxDecimals(8);
|
||||
|
||||
String get fiatAvailableBalanceRaw => fiatAvailableBalance.split(" ").last;
|
||||
String get fiatSecondAvailableBalanceRaw => fiatSecondAvailableBalance.split(" ").last;
|
||||
String get fiatCurrencyTicker => fiatAvailableBalance.split(" ").first;
|
||||
}
|
||||
|
||||
class BalanceViewModel = BalanceViewModelBase with _$BalanceViewModel;
|
||||
@@ -410,6 +420,58 @@ abstract class BalanceViewModelBase with Store {
|
||||
return balance;
|
||||
}
|
||||
|
||||
BalanceRecord? getMainBalanceRecord(bool lightningMode) {
|
||||
if (lightningMode) {
|
||||
return formattedBalances.elementAtOrNull(1);
|
||||
}
|
||||
|
||||
if (wallet.walletInfo.favoriteTokenAddress != null) {
|
||||
return formattedBalances.firstWhereOrNull((item) => (getTokenAddressBasedOnWallet(item.asset) ==
|
||||
wallet.walletInfo.favoriteTokenAddress)) ??
|
||||
formattedBalances.elementAt(0);
|
||||
}
|
||||
|
||||
return formattedBalances.elementAt(0);
|
||||
}
|
||||
|
||||
String? getTokenAddressBasedOnWallet(CryptoCurrency asset) {
|
||||
if (wallet.type == WalletType.tron) {
|
||||
return tron!.getTokenAddress(asset);
|
||||
}
|
||||
|
||||
if (wallet.type == WalletType.solana) {
|
||||
return solana!.getTokenAddress(asset);
|
||||
}
|
||||
|
||||
if (isEVMCompatibleChain(wallet.type) && asset is Erc20Token) {
|
||||
return evm!.getTokenAddress(asset);
|
||||
}
|
||||
|
||||
if (wallet.type == WalletType.zano) {
|
||||
return zano!.getZanoAssetAddress(asset);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@computed
|
||||
bool get showCombinedBalance {
|
||||
if(wallet.type == WalletType.bitcoin) return false;
|
||||
if(balances.values.length == 1) return false;
|
||||
|
||||
return wallet.walletInfo.showCombinedBalance;
|
||||
}
|
||||
|
||||
@computed
|
||||
String get combinedFiatBalance {
|
||||
double ret = 0.0;
|
||||
for(final record in balances.values) {
|
||||
ret += double.tryParse(record.fiatAvailableBalanceRaw) ?? 0;
|
||||
}
|
||||
return ret.toStringAsFixed(2);
|
||||
}
|
||||
|
||||
|
||||
Balance _currencyBalance(CryptoCurrency cryptoCurrency) {
|
||||
final balance = wallet.balance[cryptoCurrency];
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import 'package:cake_wallet/store/dashboard/order_filter_store.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/zcash/zcash.dart';
|
||||
import 'package:cw_core/transaction_direction.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cake_wallet/utils/tor.dart';
|
||||
import 'package:cake_wallet/wownero/wownero.dart' as wow;
|
||||
@@ -481,18 +482,29 @@ abstract class DashboardViewModelBase with Store {
|
||||
}
|
||||
// printV("Transaction disposer callback (relevantTxs: ${relevantTxs.length} current: ${transactions.length})");
|
||||
|
||||
String _txIdentityString(String txHash, TransactionDirection direction) => '${txHash}_$direction';
|
||||
|
||||
final existingKeys = transactions
|
||||
.map((item) => _txIdentityString(item.transaction.txHash, item.transaction.direction))
|
||||
.toSet();
|
||||
|
||||
final newTransactions = relevantTxs
|
||||
.where((tx) => !existingKeys.contains(_txIdentityString(tx.txHash, tx.direction)))
|
||||
.map((tx) => TransactionListItem(
|
||||
transaction: tx,
|
||||
balanceViewModel: balanceViewModel,
|
||||
appStore: appStore,
|
||||
key: ValueKey('${wallet.type.name}_transaction_history_item_${tx.id}_key'),
|
||||
))
|
||||
.where((item) => !transactions.contains(item));
|
||||
.toList();
|
||||
|
||||
transactions.removeWhere((item) => newTransactions.any((tx) =>
|
||||
tx.transaction.txHash == item.transaction.txHash &&
|
||||
tx.transaction.direction == item.transaction.direction));
|
||||
final newKeys = newTransactions
|
||||
.map((item) => _txIdentityString(item.transaction.txHash, item.transaction.direction))
|
||||
.toSet();
|
||||
|
||||
transactions.removeWhere(
|
||||
(item) => newKeys.contains(_txIdentityString(item.transaction.txHash, item.transaction.direction)),
|
||||
);
|
||||
|
||||
transactions.addAll(newTransactions);
|
||||
// transactions.clear();
|
||||
|
||||
@@ -9,6 +9,7 @@ import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||
import 'package:cake_wallet/solana/solana.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/tron/tron.dart';
|
||||
import 'package:cake_wallet/utils/token_utilities.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
|
||||
import 'package:cake_wallet/zano/zano.dart';
|
||||
@@ -29,10 +30,14 @@ abstract class HomeSettingsViewModelBase with Store {
|
||||
: tokens = ObservableSet<CryptoCurrency>(),
|
||||
isAddingToken = false,
|
||||
isDeletingToken = false,
|
||||
isValidatingContractAddress = false {
|
||||
isValidatingContractAddress = false,
|
||||
showCombinedBalance = _balanceViewModel.wallet.walletInfo.showCombinedBalance,
|
||||
favoriteToken = _balanceViewModel.wallet.currency {
|
||||
_updateTokensList();
|
||||
_updateLocalFavoriteToken();
|
||||
|
||||
// React to wallet changes
|
||||
|
||||
// React to wallet changes
|
||||
reaction((_) => _balanceViewModel.wallet, (_) {
|
||||
_updateTokensList();
|
||||
});
|
||||
@@ -55,6 +60,9 @@ abstract class HomeSettingsViewModelBase with Store {
|
||||
|
||||
final ObservableSet<CryptoCurrency> tokens;
|
||||
|
||||
@computed
|
||||
List<CryptoCurrency> get enabledTokens => [_balanceViewModel.wallet.currency, ...tokens.where((item)=>item.enabled).toList()];
|
||||
|
||||
WalletType get walletType => _balanceViewModel.wallet.type;
|
||||
|
||||
@observable
|
||||
@@ -491,6 +499,45 @@ abstract class HomeSettingsViewModelBase with Store {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FIXME these two observables cause duplicated state and are needed because mobx. remove them as part of the refactor and replace with proper getters
|
||||
@observable
|
||||
bool showCombinedBalance;
|
||||
|
||||
@observable
|
||||
CryptoCurrency favoriteToken;
|
||||
|
||||
@action
|
||||
void setShowCombinedBalance(bool value) {
|
||||
_balanceViewModel.wallet.walletInfo.showCombinedBalance = value;
|
||||
showCombinedBalance = value;
|
||||
_balanceViewModel.wallet.updateBalance();
|
||||
_balanceViewModel.wallet.walletInfo.save();
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> setFavoriteToken(CryptoCurrency token) async {
|
||||
final String? address;
|
||||
|
||||
if(token == _balanceViewModel.wallet.currency) {
|
||||
address = null;
|
||||
} else {
|
||||
address = getTokenAddressBasedOnWallet(token);
|
||||
}
|
||||
|
||||
_balanceViewModel.wallet.walletInfo.favoriteTokenAddress = address;
|
||||
_balanceViewModel.wallet.walletInfo.save();
|
||||
_updateLocalFavoriteToken();
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> _updateLocalFavoriteToken() async {
|
||||
favoriteToken = await TokenUtilities.findTokenByAddress(
|
||||
walletType: _balanceViewModel.wallet.type, address: _balanceViewModel.wallet.walletInfo.favoriteTokenAddress ?? "") ??
|
||||
_balanceViewModel.wallet.currency;
|
||||
}
|
||||
|
||||
|
||||
@action
|
||||
void _refreshTokensList() {
|
||||
final _tokens = Set.of(tokens);
|
||||
|
||||
Reference in New Issue
Block a user