Merge remote-tracking branch 'stack_wallet_origin/ui-fixes' into firo/spend-mints

This commit is contained in:
sneurlax 2023-04-10 16:04:14 -05:00
commit d883aaf602
44 changed files with 975 additions and 828 deletions

View file

@ -1,17 +1,14 @@
import 'dart:convert'; import 'dart:convert';
import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
class Balance { class Balance {
final Coin coin;
final Amount total; final Amount total;
final Amount spendable; final Amount spendable;
final Amount blockedTotal; final Amount blockedTotal;
final Amount pendingSpendable; final Amount pendingSpendable;
Balance({ Balance({
required this.coin,
required this.total, required this.total,
required this.spendable, required this.spendable,
required this.blockedTotal, required this.blockedTotal,
@ -25,42 +22,40 @@ class Balance {
"pendingSpendable": pendingSpendable.toJsonString(), "pendingSpendable": pendingSpendable.toJsonString(),
}); });
// need to fall back to parsing from in due to cached balances being previously // need to fall back to parsing from int due to cached balances being previously
// stored as int values instead of Amounts // stored as int values instead of Amounts
factory Balance.fromJson(String json, Coin coin) { factory Balance.fromJson(String json, int deprecatedValue) {
final decoded = jsonDecode(json); final decoded = jsonDecode(json);
return Balance( return Balance(
coin: coin,
total: decoded["total"] is String total: decoded["total"] is String
? Amount.fromSerializedJsonString(decoded["total"] as String) ? Amount.fromSerializedJsonString(decoded["total"] as String)
: Amount( : Amount(
rawValue: BigInt.from(decoded["total"] as int), rawValue: BigInt.from(decoded["total"] as int),
fractionDigits: coin.decimals, fractionDigits: deprecatedValue,
), ),
spendable: decoded["spendable"] is String spendable: decoded["spendable"] is String
? Amount.fromSerializedJsonString(decoded["spendable"] as String) ? Amount.fromSerializedJsonString(decoded["spendable"] as String)
: Amount( : Amount(
rawValue: BigInt.from(decoded["spendable"] as int), rawValue: BigInt.from(decoded["spendable"] as int),
fractionDigits: coin.decimals, fractionDigits: deprecatedValue,
), ),
blockedTotal: decoded["blockedTotal"] is String blockedTotal: decoded["blockedTotal"] is String
? Amount.fromSerializedJsonString(decoded["blockedTotal"] as String) ? Amount.fromSerializedJsonString(decoded["blockedTotal"] as String)
: Amount( : Amount(
rawValue: BigInt.from(decoded["blockedTotal"] as int), rawValue: BigInt.from(decoded["blockedTotal"] as int),
fractionDigits: coin.decimals, fractionDigits: deprecatedValue,
), ),
pendingSpendable: decoded["pendingSpendable"] is String pendingSpendable: decoded["pendingSpendable"] is String
? Amount.fromSerializedJsonString( ? Amount.fromSerializedJsonString(
decoded["pendingSpendable"] as String) decoded["pendingSpendable"] as String)
: Amount( : Amount(
rawValue: BigInt.from(decoded["pendingSpendable"] as int), rawValue: BigInt.from(decoded["pendingSpendable"] as int),
fractionDigits: coin.decimals, fractionDigits: deprecatedValue,
), ),
); );
} }
Map<String, dynamic> toMap() => { Map<String, dynamic> toMap() => {
"coin": coin,
"total": total, "total": total,
"spendable": spendable, "spendable": spendable,
"blockedTotal": blockedTotal, "blockedTotal": blockedTotal,

View file

@ -1,62 +0,0 @@
import 'dart:convert';
import 'package:stackwallet/models/balance.dart';
import 'package:stackwallet/utilities/amount/amount.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
class TokenBalance extends Balance {
TokenBalance({
required this.contractAddress,
required super.total,
required super.spendable,
required super.blockedTotal,
required super.pendingSpendable,
super.coin = Coin.ethereum,
});
final String contractAddress;
@override
String toJsonIgnoreCoin() => jsonEncode({
"contractAddress": contractAddress,
"total": total.toJsonString(),
"spendable": spendable.toJsonString(),
"blockedTotal": blockedTotal.toJsonString(),
"pendingSpendable": pendingSpendable.toJsonString(),
});
factory TokenBalance.fromJson(
String json,
int fractionDigits,
) {
final decoded = jsonDecode(json);
return TokenBalance(
contractAddress: decoded["contractAddress"] as String,
total: decoded["total"] is String
? Amount.fromSerializedJsonString(decoded["total"] as String)
: Amount(
rawValue: BigInt.from(decoded["total"] as int),
fractionDigits: fractionDigits,
),
spendable: decoded["spendable"] is String
? Amount.fromSerializedJsonString(decoded["spendable"] as String)
: Amount(
rawValue: BigInt.from(decoded["spendable"] as int),
fractionDigits: fractionDigits,
),
blockedTotal: decoded["blockedTotal"] is String
? Amount.fromSerializedJsonString(decoded["blockedTotal"] as String)
: Amount(
rawValue: BigInt.from(decoded["blockedTotal"] as int),
fractionDigits: fractionDigits,
),
pendingSpendable: decoded["pendingSpendable"] is String
? Amount.fromSerializedJsonString(
decoded["pendingSpendable"] as String)
: Amount(
rawValue: BigInt.from(decoded["pendingSpendable"] as int),
fractionDigits: fractionDigits,
),
);
}
}

View file

@ -11,6 +11,7 @@ import 'package:stackwallet/pages/add_wallet_views/add_token_view/add_custom_tok
import 'package:stackwallet/pages/add_wallet_views/add_token_view/sub_widgets/add_token_list.dart'; import 'package:stackwallet/pages/add_wallet_views/add_token_view/sub_widgets/add_token_list.dart';
import 'package:stackwallet/pages/add_wallet_views/add_token_view/sub_widgets/add_token_list_element.dart'; import 'package:stackwallet/pages/add_wallet_views/add_token_view/sub_widgets/add_token_list_element.dart';
import 'package:stackwallet/pages/add_wallet_views/add_token_view/sub_widgets/add_token_text.dart'; import 'package:stackwallet/pages/add_wallet_views/add_token_view/sub_widgets/add_token_text.dart';
import 'package:stackwallet/pages/home_view/home_view.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart'; import 'package:stackwallet/pages_desktop_specific/desktop_home_view.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/services/coins/ethereum/ethereum_wallet.dart'; import 'package:stackwallet/services/coins/ethereum/ethereum_wallet.dart';
@ -97,9 +98,17 @@ class _EditWalletTokensViewState extends ConsumerState<EditWalletTokensView> {
if (widget.contractsToMarkSelected == null) { if (widget.contractsToMarkSelected == null) {
Navigator.of(context).pop(42); Navigator.of(context).pop(42);
} else { } else {
if (isDesktop) {
Navigator.of(context).popUntil( Navigator.of(context).popUntil(
ModalRoute.withName(DesktopHomeView.routeName), ModalRoute.withName(DesktopHomeView.routeName),
); );
} else {
await Navigator.of(context).pushNamedAndRemoveUntil(
HomeView.routeName,
(route) => false,
);
}
if (mounted) {
unawaited( unawaited(
showFloatingFlushBar( showFloatingFlushBar(
type: FlushBarType.success, type: FlushBarType.success,
@ -110,6 +119,7 @@ class _EditWalletTokensViewState extends ConsumerState<EditWalletTokensView> {
} }
} }
} }
}
Future<void> _addToken() async { Future<void> _addToken() async {
EthContract? contract; EthContract? contract;

View file

@ -8,7 +8,7 @@ import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/background.dart'; import 'package:stackwallet/widgets/background.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart'; import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance.dart';
import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart'; import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart';
class ChooseFromStackView extends ConsumerStatefulWidget { class ChooseFromStackView extends ConsumerStatefulWidget {

View file

@ -21,6 +21,7 @@ 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/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/conditional_parent.dart';
import 'package:stackwallet/widgets/rounded_container.dart'; import 'package:stackwallet/widgets/rounded_container.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
@ -44,8 +45,7 @@ class TokenSummary extends ConsumerWidget {
return Stack( return Stack(
children: [ children: [
RoundedContainer( RoundedContainer(
color: const Color(0xFFE9EAFF), // todo: fix color color: Theme.of(context).extension<StackColors>()!.tokenSummaryBG,
// color: Theme.of(context).extension<StackColors>()!.,
padding: const EdgeInsets.all(24), padding: const EdgeInsets.all(24),
child: Column( child: Column(
children: [ children: [
@ -54,7 +54,9 @@ class TokenSummary extends ConsumerWidget {
children: [ children: [
SvgPicture.asset( SvgPicture.asset(
Assets.svg.walletDesktop, Assets.svg.walletDesktop,
color: const Color(0xFF8488AB), // todo: fix color color: Theme.of(context)
.extension<StackColors>()!
.tokenSummaryTextSecondary,
width: 12, width: 12,
height: 12, height: 12,
), ),
@ -68,7 +70,9 @@ class TokenSummary extends ConsumerWidget {
), ),
), ),
style: STextStyles.w500_12(context).copyWith( style: STextStyles.w500_12(context).copyWith(
color: const Color(0xFF8488AB), // todo: fix color color: Theme.of(context)
.extension<StackColors>()!
.tokenSummaryTextSecondary,
), ),
), ),
], ],
@ -88,7 +92,11 @@ class TokenSummary extends ConsumerWidget {
), ),
)}" )}"
" ${token.symbol}", " ${token.symbol}",
style: STextStyles.pageTitleH1(context), style: STextStyles.pageTitleH1(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.tokenSummaryTextPrimary,
),
), ),
const SizedBox( const SizedBox(
width: 10, width: 10,
@ -119,7 +127,11 @@ class TokenSummary extends ConsumerWidget {
(value) => value.currency, (value) => value.currency,
), ),
)}", )}",
style: STextStyles.subtitle500(context), style: STextStyles.subtitle500(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.tokenSummaryTextPrimary,
),
), ),
const SizedBox( const SizedBox(
height: 20, height: 20,
@ -137,8 +149,13 @@ class TokenSummary extends ConsumerWidget {
child: WalletRefreshButton( child: WalletRefreshButton(
walletId: walletId, walletId: walletId,
initialSyncStatus: initialSyncStatus, initialSyncStatus: initialSyncStatus,
tokenContractAddress: ref.watch(tokenServiceProvider tokenContractAddress: ref.watch(
.select((value) => value!.tokenContract.address)), tokenServiceProvider.select(
(value) => value!.tokenContract.address,
),
),
overrideIconColor:
Theme.of(context).extension<StackColors>()!.topNavIconPrimary,
), ),
), ),
], ],
@ -197,7 +214,7 @@ class TokenWalletOptions extends StatelessWidget {
); );
}, },
subLabel: "Receive", subLabel: "Receive",
iconAssetSVG: Assets.svg.receive(context), iconAssetSVG: Assets.svg.arrowDownLeft,
), ),
const SizedBox( const SizedBox(
width: 16, width: 16,
@ -214,7 +231,7 @@ class TokenWalletOptions extends StatelessWidget {
); );
}, },
subLabel: "Send", subLabel: "Send",
iconAssetSVG: Assets.svg.send(context), iconAssetSVG: Assets.svg.arrowUpRight,
), ),
const SizedBox( const SizedBox(
width: 16, width: 16,
@ -251,12 +268,14 @@ class TokenOptionsButton extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final iconSize = subLabel == "Send" || subLabel == "Receive" ? 12.0 : 24.0;
return Column( return Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
RawMaterialButton( RawMaterialButton(
fillColor: Theme.of(context).extension<StackColors>()!.popupBG, fillColor:
Theme.of(context).extension<StackColors>()!.tokenSummaryButtonBG,
elevation: 0, elevation: 0,
focusElevation: 0, focusElevation: 0,
hoverElevation: 0, hoverElevation: 0,
@ -270,11 +289,27 @@ class TokenOptionsButton extends StatelessWidget {
onPressed: onPressed, onPressed: onPressed,
child: Padding( child: Padding(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
child: ConditionalParent(
condition: iconSize < 24,
builder: (child) => RoundedContainer(
padding: const EdgeInsets.all(6),
color: Theme.of(context)
.extension<StackColors>()!
.tokenSummaryIcon
.withOpacity(0.4),
radiusMultiplier: 10,
child: Center(
child: child,
),
),
child: SvgPicture.asset( child: SvgPicture.asset(
iconAssetSVG, iconAssetSVG,
color: const Color(0xFF424A97), // todo: fix color color: Theme.of(context)
width: 24, .extension<StackColors>()!
height: 24, .tokenSummaryIcon,
width: iconSize,
height: iconSize,
),
), ),
), ),
), ),
@ -283,7 +318,11 @@ class TokenOptionsButton extends StatelessWidget {
), ),
Text( Text(
subLabel, subLabel,
style: STextStyles.w500_12(context), style: STextStyles.w500_12(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.tokenSummaryTextPrimary,
),
) )
], ],
); );
@ -303,12 +342,14 @@ class CoinTickerTag extends ConsumerWidget {
return RoundedContainer( return RoundedContainer(
padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 4), padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 4),
radiusMultiplier: 0.25, radiusMultiplier: 0.25,
color: const Color(0xFF4D5798), // TODO: color theme for multi themes color: Theme.of(context).extension<StackColors>()!.ethTagBG,
child: Text( child: Text(
ref.watch(walletsChangeNotifierProvider ref.watch(
.select((value) => value.getManager(walletId).coin.ticker)), walletsChangeNotifierProvider
.select((value) => value.getManager(walletId).coin.ticker),
),
style: STextStyles.w600_12(context).copyWith( style: STextStyles.w600_12(context).copyWith(
color: Colors.white, // TODO: design is wrong? color: Theme.of(context).extension<StackColors>()!.ethTagText,
), ),
), ),
); );

View file

@ -110,6 +110,9 @@ class _TokenViewState extends ConsumerState<TokenView> {
child: AppBarIconButton( child: AppBarIconButton(
icon: SvgPicture.asset( icon: SvgPicture.asset(
Assets.svg.verticalEllipsis, Assets.svg.verticalEllipsis,
color: Theme.of(context)
.extension<StackColors>()!
.topNavIconPrimary,
), ),
onPressed: () { onPressed: () {
// todo: context menu // todo: context menu

View file

@ -22,6 +22,7 @@ class WalletRefreshButton extends ConsumerStatefulWidget {
this.tokenContractAddress, this.tokenContractAddress,
this.onPressed, this.onPressed,
this.eventBus, this.eventBus,
this.overrideIconColor,
}) : super(key: key); }) : super(key: key);
final String walletId; final String walletId;
@ -29,6 +30,7 @@ class WalletRefreshButton extends ConsumerStatefulWidget {
final String? tokenContractAddress; final String? tokenContractAddress;
final VoidCallback? onPressed; final VoidCallback? onPressed;
final EventBus? eventBus; final EventBus? eventBus;
final Color? overrideIconColor;
@override @override
ConsumerState<WalletRefreshButton> createState() => _RefreshButtonState(); ConsumerState<WalletRefreshButton> createState() => _RefreshButtonState();
@ -155,11 +157,15 @@ class _RefreshButtonState extends ConsumerState<WalletRefreshButton>
Assets.svg.arrowRotate, Assets.svg.arrowRotate,
width: isDesktop ? 12 : 24, width: isDesktop ? 12 : 24,
height: isDesktop ? 12 : 24, height: isDesktop ? 12 : 24,
color: isDesktop color: widget.overrideIconColor != null
? widget.overrideIconColor!
: isDesktop
? Theme.of(context) ? Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.textFieldDefaultSearchIconRight .textFieldDefaultSearchIconRight
: Theme.of(context).extension<StackColors>()!.textFavoriteCard, : Theme.of(context)
.extension<StackColors>()!
.textFavoriteCard,
), ),
), ),
), ),

View file

@ -1,101 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/wallet_card.dart';
class WalletsSheet extends ConsumerWidget {
const WalletsSheet({
Key? key,
required this.coin,
}) : super(key: key);
final Coin coin;
@override
Widget build(BuildContext context, WidgetRef ref) {
final providers = ref
.watch(walletsChangeNotifierProvider
.select((value) => value.getManagerProvidersByCoin()))
.where((e) => e.item1 == coin)
.map((e) => e.item2)
.expand((e) => e)
.toList();
final maxHeight = MediaQuery.of(context).size.height * 0.60;
return Container(
decoration: BoxDecoration(
color: Theme.of(context).extension<StackColors>()!.popupBG,
borderRadius: const BorderRadius.vertical(
top: Radius.circular(20),
),
),
child: LimitedBox(
maxHeight: maxHeight,
child: Padding(
padding: const EdgeInsets.only(
left: 24,
right: 24,
top: 10,
bottom: 0,
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Center(
child: Container(
decoration: BoxDecoration(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldDefaultBG,
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
width: 60,
height: 4,
),
),
const SizedBox(
height: 36,
),
Text(
"${coin.prettyName} (${coin.ticker}) wallets",
style: STextStyles.pageTitleH2(context),
textAlign: TextAlign.left,
),
const SizedBox(
height: 16,
),
Flexible(
child: ListView.builder(
shrinkWrap: true,
itemCount: providers.length,
itemBuilder: (builderContext, index) {
final walletId = ref.watch(
providers[index].select((value) => value.walletId));
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: WalletSheetCard(
walletId: walletId,
popPrevious: true,
),
);
},
),
),
const SizedBox(
height: 24,
),
],
),
),
),
);
}
}

View file

@ -1,73 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/background.dart';
import 'package:stackwallet/widgets/conditional_parent.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/master_wallet_card.dart';
class EthWalletsOverview extends ConsumerStatefulWidget {
const EthWalletsOverview({Key? key}) : super(key: key);
static const routeName = "/ethWalletsOverview";
@override
ConsumerState<EthWalletsOverview> createState() => _EthWalletsOverviewState();
}
class _EthWalletsOverviewState extends ConsumerState<EthWalletsOverview> {
final isDesktop = Util.isDesktop;
final List<String> ethWalletIds = [];
@override
void initState() {
final walletsData =
ref.read(walletsServiceChangeNotifierProvider).fetchWalletsData();
walletsData.removeWhere((key, value) => value.coin != Coin.ethereum);
ethWalletIds.clear();
ethWalletIds.addAll(walletsData.values.map((e) => e.walletId));
super.initState();
}
@override
Widget build(BuildContext context) {
return Background(
child: ConditionalParent(
condition: !isDesktop,
builder: (child) => Scaffold(
backgroundColor:
Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar(
leading: const AppBarBackButton(),
title: Text(
"Ethereum (ETH) wallets",
style: STextStyles.navBarTitle(context),
),
),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16),
child: child,
),
),
),
child: ListView.separated(
itemCount: ethWalletIds.length,
separatorBuilder: (_, __) => const SizedBox(
height: 8,
),
itemBuilder: (_, index) => MasterWalletCard(
walletId: ethWalletIds[index],
),
),
),
);
}
}

View file

@ -4,8 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/pages/wallet_view/wallet_view.dart'; import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
import 'package:stackwallet/pages/wallets_sheet/wallets_sheet.dart'; import 'package:stackwallet/pages/wallets_view/wallets_overview.dart';
import 'package:stackwallet/pages/wallets_view/eth_wallets_overview.dart';
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
@ -46,13 +45,7 @@ class WalletListItem extends ConsumerWidget {
BorderRadius.circular(Constants.size.circularBorderRadius), BorderRadius.circular(Constants.size.circularBorderRadius),
), ),
onPressed: () async { onPressed: () async {
if (coin == Coin.ethereum) { if (walletCount == 1 && coin != Coin.ethereum) {
unawaited(
Navigator.of(context).pushNamed(
EthWalletsOverview.routeName,
),
);
} else if (walletCount == 1) {
final providersByCoin = ref final providersByCoin = ref
.watch(walletsChangeNotifierProvider .watch(walletsChangeNotifierProvider
.select((value) => value.getManagerProvidersByCoin())) .select((value) => value.getManagerProvidersByCoin()))
@ -77,15 +70,9 @@ class WalletListItem extends ConsumerWidget {
} }
} else { } else {
unawaited( unawaited(
showModalBottomSheet<dynamic>( Navigator.of(context).pushNamed(
backgroundColor: Colors.transparent, WalletsOverview.routeName,
context: context, arguments: coin,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
),
),
builder: (_) => WalletsSheet(coin: coin),
), ),
); );
} }

View file

@ -0,0 +1,308 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/dialogs/desktop_expanding_wallet_card.dart';
import 'package:stackwallet/providers/db/main_db_provider.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/services/coins/ethereum/ethereum_wallet.dart';
import 'package:stackwallet/services/coins/manager.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/background.dart';
import 'package:stackwallet/widgets/conditional_parent.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/master_wallet_card.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
import 'package:stackwallet/widgets/wallet_card.dart';
import 'package:tuple/tuple.dart';
class WalletsOverview extends ConsumerStatefulWidget {
const WalletsOverview({
Key? key,
required this.coin,
this.navigatorState,
}) : super(key: key);
final Coin coin;
final NavigatorState? navigatorState;
static const routeName = "/walletsOverview";
@override
ConsumerState<WalletsOverview> createState() => _EthWalletsOverviewState();
}
class _EthWalletsOverviewState extends ConsumerState<WalletsOverview> {
final isDesktop = Util.isDesktop;
late final TextEditingController _searchController;
late final FocusNode searchFieldFocusNode;
String _searchString = "";
final List<Tuple2<Manager, List<EthContract>>> wallets = [];
List<Tuple2<Manager, List<EthContract>>> _filter(String searchTerm) {
if (searchTerm.isEmpty) {
return wallets;
}
final List<Tuple2<Manager, List<EthContract>>> results = [];
final term = searchTerm.toLowerCase();
for (final tuple in wallets) {
bool includeManager = false;
// search wallet name and total balance
includeManager |= _elementContains(tuple.item1.walletName, term);
includeManager |= _elementContains(
tuple.item1.balance.total.decimal.toString(),
term,
);
final List<EthContract> contracts = [];
for (final contract in tuple.item2) {
if (_elementContains(contract.name, term)) {
contracts.add(contract);
} else if (_elementContains(contract.symbol, term)) {
contracts.add(contract);
} else if (_elementContains(contract.type.name, term)) {
contracts.add(contract);
} else if (_elementContains(contract.address, term)) {
contracts.add(contract);
}
}
if (includeManager || contracts.isNotEmpty) {
results.add(Tuple2(tuple.item1, contracts));
}
}
return results;
}
bool _elementContains(String element, String term) {
return element.toLowerCase().contains(term);
}
@override
void initState() {
_searchController = TextEditingController();
searchFieldFocusNode = FocusNode();
final walletsData =
ref.read(walletsServiceChangeNotifierProvider).fetchWalletsData();
walletsData.removeWhere((key, value) => value.coin != widget.coin);
if (widget.coin == Coin.ethereum) {
for (final data in walletsData.values) {
final List<EthContract> contracts = [];
final manager =
ref.read(walletsChangeNotifierProvider).getManager(data.walletId);
final contractAddresses = (manager.wallet as EthereumWallet)
.getWalletTokenContractAddresses();
// fetch each contract
for (final contractAddress in contractAddresses) {
final contract = ref
.read(
mainDBProvider,
)
.getEthContractSync(
contractAddress,
);
// add it to list if it exists in DB
if (contract != null) {
contracts.add(contract);
}
}
// add tuple to list
wallets.add(
Tuple2(
ref.read(walletsChangeNotifierProvider).getManager(
data.walletId,
),
contracts,
),
);
}
} else {
// add non token wallet tuple to list
for (final data in walletsData.values) {
wallets.add(
Tuple2(
ref.read(walletsChangeNotifierProvider).getManager(
data.walletId,
),
[],
),
);
}
}
super.initState();
}
@override
void dispose() {
_searchController.dispose();
searchFieldFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Background(
child: ConditionalParent(
condition: !isDesktop,
builder: (child) => Scaffold(
backgroundColor:
Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar(
leading: const AppBarBackButton(),
title: Text(
"${widget.coin.prettyName} (${widget.coin.ticker}) wallets",
style: STextStyles.navBarTitle(context),
),
),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16),
child: child,
),
),
),
child: Column(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
child: TextField(
autocorrect: !isDesktop,
enableSuggestions: !isDesktop,
controller: _searchController,
focusNode: searchFieldFocusNode,
onChanged: (value) {
setState(() {
_searchString = value;
});
},
style: isDesktop
? STextStyles.desktopTextExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveText,
height: 1.8,
)
: STextStyles.field(context),
decoration: standardInputDecoration(
"Search...",
searchFieldFocusNode,
context,
desktopMed: isDesktop,
).copyWith(
prefixIcon: Padding(
padding: EdgeInsets.symmetric(
horizontal: isDesktop ? 12 : 10,
vertical: isDesktop ? 18 : 16,
),
child: SvgPicture.asset(
Assets.svg.search,
width: isDesktop ? 20 : 16,
height: isDesktop ? 20 : 16,
),
),
suffixIcon: _searchController.text.isNotEmpty
? Padding(
padding: const EdgeInsets.only(right: 0),
child: UnconstrainedBox(
child: Row(
children: [
TextFieldIconButton(
child: const XIcon(),
onTap: () async {
setState(() {
_searchController.text = "";
_searchString = "";
});
},
),
],
),
),
)
: null,
),
),
),
const SizedBox(
height: 16,
),
Expanded(
child: Builder(
builder: (context) {
final data = _filter(_searchString);
return ListView.separated(
itemBuilder: (_, index) {
final element = data[index];
if (element.item1.hasTokenSupport) {
if (isDesktop) {
return DesktopExpandingWalletCard(
key: Key(
"${element.item1.walletName}_${element.item2.map((e) => e.address).join()}"),
data: element,
navigatorState: widget.navigatorState!,
);
} else {
return MasterWalletCard(
walletId: element.item1.walletId,
);
}
} else {
return ConditionalParent(
condition: isDesktop,
builder: (child) => RoundedWhiteContainer(
padding: const EdgeInsets.symmetric(
vertical: 14,
horizontal: 20,
),
borderColor: Theme.of(context)
.extension<StackColors>()!
.backgroundAppBar,
child: child,
),
child: SimpleWalletCard(
walletId: element.item1.walletId,
popPrevious: isDesktop,
desktopNavigatorState:
isDesktop ? widget.navigatorState : null,
),
);
}
},
separatorBuilder: (_, __) => SizedBox(
height: isDesktop ? 10 : 8,
),
itemCount: data.length,
);
},
),
),
],
),
),
);
}
}

View file

@ -1,435 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart';
import 'package:stackwallet/providers/db/main_db_provider.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/services/coins/ethereum/ethereum_wallet.dart';
import 'package:stackwallet/services/coins/manager.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/animated_widgets/rotate_icon.dart';
import 'package:stackwallet/widgets/expandable.dart';
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
import 'package:stackwallet/widgets/wallet_card.dart';
import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart';
import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart';
import 'package:tuple/tuple.dart';
class DesktopCoinWalletsDialog extends ConsumerStatefulWidget {
const DesktopCoinWalletsDialog({
Key? key,
required this.coin,
required this.navigatorState,
}) : super(key: key);
final Coin coin;
final NavigatorState navigatorState;
@override
ConsumerState<DesktopCoinWalletsDialog> createState() =>
_DesktopCoinWalletsDialogState();
}
class _DesktopCoinWalletsDialogState
extends ConsumerState<DesktopCoinWalletsDialog> {
final isDesktop = Util.isDesktop;
late final TextEditingController _searchController;
late final FocusNode searchFieldFocusNode;
String _searchString = "";
final List<Tuple2<Manager, List<EthContract>>> wallets = [];
List<Tuple2<Manager, List<EthContract>>> _filter(String searchTerm) {
if (searchTerm.isEmpty) {
return wallets;
}
final List<Tuple2<Manager, List<EthContract>>> results = [];
final term = searchTerm.toLowerCase();
for (final tuple in wallets) {
bool includeManager = false;
// search wallet name and total balance
includeManager |= _elementContains(tuple.item1.walletName, term);
includeManager |= _elementContains(
tuple.item1.balance.total.decimal.toString(),
term,
);
final List<EthContract> contracts = [];
for (final contract in tuple.item2) {
if (_elementContains(contract.name, term)) {
contracts.add(contract);
} else if (_elementContains(contract.symbol, term)) {
contracts.add(contract);
} else if (_elementContains(contract.type.name, term)) {
contracts.add(contract);
} else if (_elementContains(contract.address, term)) {
contracts.add(contract);
}
}
if (includeManager || contracts.isNotEmpty) {
results.add(Tuple2(tuple.item1, contracts));
}
}
return results;
}
bool _elementContains(String element, String term) {
return element.toLowerCase().contains(term);
}
@override
void initState() {
_searchController = TextEditingController();
searchFieldFocusNode = FocusNode();
final walletsData =
ref.read(walletsServiceChangeNotifierProvider).fetchWalletsData();
walletsData.removeWhere((key, value) => value.coin != widget.coin);
if (widget.coin == Coin.ethereum) {
for (final data in walletsData.values) {
final List<EthContract> contracts = [];
final manager =
ref.read(walletsChangeNotifierProvider).getManager(data.walletId);
final contractAddresses = (manager.wallet as EthereumWallet)
.getWalletTokenContractAddresses();
// fetch each contract
for (final contractAddress in contractAddresses) {
final contract = ref
.read(
mainDBProvider,
)
.getEthContractSync(
contractAddress,
);
// add it to list if it exists in DB
if (contract != null) {
contracts.add(contract);
}
}
// add tuple to list
wallets.add(
Tuple2(
ref.read(walletsChangeNotifierProvider).getManager(
data.walletId,
),
contracts,
),
);
}
} else {
// add non token wallet tuple to list
for (final data in walletsData.values) {
wallets.add(
Tuple2(
ref.read(walletsChangeNotifierProvider).getManager(
data.walletId,
),
[],
),
);
}
}
super.initState();
}
@override
void dispose() {
_searchController.dispose();
searchFieldFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
child: TextField(
autocorrect: !isDesktop,
enableSuggestions: !isDesktop,
controller: _searchController,
focusNode: searchFieldFocusNode,
onChanged: (value) {
setState(() {
_searchString = value;
});
},
style: isDesktop
? STextStyles.desktopTextExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveText,
height: 1.8,
)
: STextStyles.field(context),
decoration: standardInputDecoration(
"Search...",
searchFieldFocusNode,
context,
desktopMed: isDesktop,
).copyWith(
prefixIcon: Padding(
padding: EdgeInsets.symmetric(
horizontal: isDesktop ? 12 : 10,
vertical: isDesktop ? 18 : 16,
),
child: SvgPicture.asset(
Assets.svg.search,
width: isDesktop ? 20 : 16,
height: isDesktop ? 20 : 16,
),
),
suffixIcon: _searchController.text.isNotEmpty
? Padding(
padding: const EdgeInsets.only(right: 0),
child: UnconstrainedBox(
child: Row(
children: [
TextFieldIconButton(
child: const XIcon(),
onTap: () async {
setState(() {
_searchController.text = "";
_searchString = "";
});
},
),
],
),
),
)
: null,
),
),
),
const SizedBox(
height: 16,
),
Expanded(
child: Builder(builder: (context) {
final data = _filter(_searchString);
return ListView.separated(
itemBuilder: (_, index) => widget.coin == Coin.ethereum
? _DesktopWalletCard(
key: Key(
"${data[index].item1.walletName}_${data[index].item2.map((e) => e.address).join()}"),
data: data[index],
navigatorState: widget.navigatorState,
)
: RoundedWhiteContainer(
padding: const EdgeInsets.symmetric(
vertical: 14,
horizontal: 20,
),
borderColor: Theme.of(context)
.extension<StackColors>()!
.backgroundAppBar,
child: WalletSheetCard(
walletId: data[index].item1.walletId,
popPrevious: true,
desktopNavigatorState: widget.navigatorState,
),
),
separatorBuilder: (_, __) => const SizedBox(
height: 10,
),
itemCount: data.length,
);
}),
),
],
);
}
}
class _DesktopWalletCard extends StatefulWidget {
const _DesktopWalletCard({
Key? key,
required this.data,
required this.navigatorState,
}) : super(key: key);
final Tuple2<Manager, List<EthContract>> data;
final NavigatorState navigatorState;
@override
State<_DesktopWalletCard> createState() => _DesktopWalletCardState();
}
class _DesktopWalletCardState extends State<_DesktopWalletCard> {
final expandableController = ExpandableController();
final rotateIconController = RotateIconController();
final List<String> tokenContractAddresses = [];
@override
void initState() {
if (widget.data.item1.hasTokenSupport) {
tokenContractAddresses.addAll(
widget.data.item2.map((e) => e.address),
);
}
super.initState();
}
@override
Widget build(BuildContext context) {
return RoundedWhiteContainer(
padding: EdgeInsets.zero,
borderColor: Theme.of(context).extension<StackColors>()!.backgroundAppBar,
child: Expandable(
initialState: widget.data.item1.hasTokenSupport
? ExpandableState.expanded
: ExpandableState.collapsed,
controller: expandableController,
expandOverride: () {},
header: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 14,
),
child: Row(
children: [
Expanded(
child: Row(
children: [
Expanded(
flex: 2,
child: Row(
children: [
WalletInfoCoinIcon(
coin: widget.data.item1.coin,
),
const SizedBox(
width: 12,
),
Text(
widget.data.item1.walletName,
style: STextStyles.desktopTextExtraSmall(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textDark,
),
),
],
),
),
Expanded(
flex: 4,
child: WalletInfoRowBalance(
walletId: widget.data.item1.walletId,
),
),
],
),
),
MaterialButton(
padding: const EdgeInsets.all(5),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
minWidth: 32,
height: 32,
color: Theme.of(context)
.extension<StackColors>()!
.textFieldDefaultBG,
elevation: 0,
hoverElevation: 0,
disabledElevation: 0,
highlightElevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
onPressed: () {
if (expandableController.state == ExpandableState.collapsed) {
rotateIconController.forward?.call();
} else {
rotateIconController.reverse?.call();
}
expandableController.toggle?.call();
},
child: RotateIcon(
controller: rotateIconController,
icon: RotatedBox(
quarterTurns: 2,
child: SvgPicture.asset(
Assets.svg.chevronDown,
width: 14,
),
),
curve: Curves.easeInOut,
),
),
],
),
),
body: ListView(
shrinkWrap: true,
primary: false,
children: [
Container(
width: double.infinity,
height: 1,
color:
Theme.of(context).extension<StackColors>()!.backgroundAppBar,
),
Padding(
padding: const EdgeInsets.only(
left: 32,
right: 14,
top: 14,
bottom: 14,
),
child: WalletSheetCard(
walletId: widget.data.item1.walletId,
popPrevious: true,
desktopNavigatorState: widget.navigatorState,
),
),
...tokenContractAddresses.map(
(e) => Padding(
padding: const EdgeInsets.only(
left: 32,
right: 14,
top: 14,
bottom: 14,
),
child: WalletSheetCard(
walletId: widget.data.item1.walletId,
contractAddress: e,
popPrevious: true,
desktopNavigatorState: widget.navigatorState,
),
),
),
],
),
),
);
}
}

View file

@ -0,0 +1,192 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart';
import 'package:stackwallet/services/coins/manager.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/animated_widgets/rotate_icon.dart';
import 'package:stackwallet/widgets/expandable.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/wallet_card.dart';
import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance.dart';
import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart';
import 'package:tuple/tuple.dart';
class DesktopExpandingWalletCard extends StatefulWidget {
const DesktopExpandingWalletCard({
Key? key,
required this.data,
required this.navigatorState,
}) : super(key: key);
final Tuple2<Manager, List<EthContract>> data;
final NavigatorState navigatorState;
@override
State<DesktopExpandingWalletCard> createState() =>
_DesktopExpandingWalletCardState();
}
class _DesktopExpandingWalletCardState
extends State<DesktopExpandingWalletCard> {
final expandableController = ExpandableController();
final rotateIconController = RotateIconController();
final List<String> tokenContractAddresses = [];
@override
void initState() {
if (widget.data.item1.hasTokenSupport) {
tokenContractAddresses.addAll(
widget.data.item2.map((e) => e.address),
);
}
super.initState();
}
@override
Widget build(BuildContext context) {
return RoundedWhiteContainer(
padding: EdgeInsets.zero,
borderColor: Theme.of(context).extension<StackColors>()!.backgroundAppBar,
child: Expandable(
initialState: widget.data.item1.hasTokenSupport
? ExpandableState.expanded
: ExpandableState.collapsed,
controller: expandableController,
onExpandWillChange: (toState) {
if (toState == ExpandableState.expanded) {
rotateIconController.forward?.call();
} else {
rotateIconController.reverse?.call();
}
},
header: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 14,
),
child: Row(
children: [
Expanded(
child: Row(
children: [
Expanded(
flex: 2,
child: Row(
children: [
WalletInfoCoinIcon(
coin: widget.data.item1.coin,
),
const SizedBox(
width: 12,
),
Text(
widget.data.item1.walletName,
style: STextStyles.desktopTextExtraSmall(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textDark,
),
),
],
),
),
Expanded(
flex: 4,
child: WalletInfoRowBalance(
walletId: widget.data.item1.walletId,
),
),
],
),
),
MaterialButton(
padding: const EdgeInsets.all(5),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
minWidth: 32,
height: 32,
color: Theme.of(context)
.extension<StackColors>()!
.textFieldDefaultBG,
elevation: 0,
hoverElevation: 0,
disabledElevation: 0,
highlightElevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
onPressed: () {
if (expandableController.state == ExpandableState.collapsed) {
rotateIconController.forward?.call();
} else {
rotateIconController.reverse?.call();
}
expandableController.toggle?.call();
},
child: RotateIcon(
controller: rotateIconController,
icon: RotatedBox(
quarterTurns: 2,
child: SvgPicture.asset(
Assets.svg.chevronDown,
width: 14,
),
),
curve: Curves.easeInOut,
),
),
],
),
),
body: ListView(
shrinkWrap: true,
primary: false,
children: [
Container(
width: double.infinity,
height: 1,
color:
Theme.of(context).extension<StackColors>()!.backgroundAppBar,
),
Padding(
padding: const EdgeInsets.only(
left: 32,
right: 14,
top: 14,
bottom: 14,
),
child: SimpleWalletCard(
walletId: widget.data.item1.walletId,
popPrevious: true,
desktopNavigatorState: widget.navigatorState,
),
),
...tokenContractAddresses.map(
(e) => Padding(
padding: const EdgeInsets.only(
left: 32,
right: 14,
top: 14,
bottom: 14,
),
child: SimpleWalletCard(
walletId: widget.data.item1.walletId,
contractAddress: e,
popPrevious: true,
desktopNavigatorState: widget.navigatorState,
),
),
),
],
),
),
);
}
}

View file

@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/dialogs/desktop_coin_wallets_dialog.dart'; import 'package:stackwallet/pages/wallets_view/wallets_overview.dart';
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
@ -103,7 +103,7 @@ class _DesktopWalletSummaryRowState extends State<DesktopWalletSummaryRow> {
right: 32, right: 32,
bottom: 32, bottom: 32,
), ),
child: DesktopCoinWalletsDialog( child: WalletsOverview(
coin: widget.coin, coin: widget.coin,
navigatorState: Navigator.of(context), navigatorState: Navigator.of(context),
), ),

View file

@ -106,7 +106,7 @@ import 'package:stackwallet/pages/wallet_view/transaction_views/edit_note_view.d
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart'; import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_search_filter_view.dart'; import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_search_filter_view.dart';
import 'package:stackwallet/pages/wallet_view/wallet_view.dart'; import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
import 'package:stackwallet/pages/wallets_view/eth_wallets_overview.dart'; import 'package:stackwallet/pages/wallets_view/wallets_overview.dart';
import 'package:stackwallet/pages/wallets_view/wallets_view.dart'; import 'package:stackwallet/pages/wallets_view/wallets_view.dart';
import 'package:stackwallet/pages_desktop_specific/address_book_view/desktop_address_book.dart'; import 'package:stackwallet/pages_desktop_specific/address_book_view/desktop_address_book.dart';
import 'package:stackwallet/pages_desktop_specific/addresses/desktop_wallet_addresses_view.dart'; import 'package:stackwallet/pages_desktop_specific/addresses/desktop_wallet_addresses_view.dart';
@ -280,14 +280,19 @@ class RouteGenerator {
), ),
); );
case EthWalletsOverview.routeName: case WalletsOverview.routeName:
if (args is Coin) {
return getRoute( return getRoute(
shouldUseMaterialRoute: useMaterialPageRoute, shouldUseMaterialRoute: useMaterialPageRoute,
builder: (_) => const EthWalletsOverview(), builder: (_) => WalletsOverview(
coin: args,
),
settings: RouteSettings( settings: RouteSettings(
name: settings.name, name: settings.name,
), ),
); );
}
return _routeError("${settings.name} invalid args: ${args.toString()}");
case TokenContractDetailsView.routeName: case TokenContractDetailsView.routeName:
if (args is Tuple2<String, String>) { if (args is Tuple2<String, String>) {

View file

@ -1978,7 +1978,6 @@ class EpicCashWallet extends CoinServiceAPI
(jsonBalances['amount_awaiting_finalization'] as double).toString(); (jsonBalances['amount_awaiting_finalization'] as double).toString();
_balance = Balance( _balance = Balance(
coin: coin,
total: Amount.fromDecimal( total: Amount.fromDecimal(
Decimal.parse(total) + Decimal.parse(awaiting), Decimal.parse(total) + Decimal.parse(awaiting),
fractionDigits: coin.decimals, fractionDigits: coin.decimals,

View file

@ -10,7 +10,6 @@ import 'package:stackwallet/models/balance.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart'; import 'package:stackwallet/models/isar/models/isar_models.dart';
import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/models/node_model.dart';
import 'package:stackwallet/models/paymint/fee_object_model.dart'; import 'package:stackwallet/models/paymint/fee_object_model.dart';
import 'package:stackwallet/models/token_balance.dart';
import 'package:stackwallet/services/coins/coin_service.dart'; import 'package:stackwallet/services/coins/coin_service.dart';
import 'package:stackwallet/services/ethereum/ethereum_api.dart'; import 'package:stackwallet/services/ethereum/ethereum_api.dart';
import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart'; import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
@ -78,14 +77,13 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB {
); );
} }
TokenBalance getCachedTokenBalance(EthContract contract) { Balance getCachedTokenBalance(EthContract contract) {
final jsonString = DB.instance.get<dynamic>( final jsonString = DB.instance.get<dynamic>(
boxName: _walletId, boxName: _walletId,
key: TokenCacheKeys.tokenBalance(contract.address), key: TokenCacheKeys.tokenBalance(contract.address),
) as String?; ) as String?;
if (jsonString == null) { if (jsonString == null) {
return TokenBalance( return Balance(
contractAddress: contract.address,
total: Amount( total: Amount(
rawValue: BigInt.zero, rawValue: BigInt.zero,
fractionDigits: contract.decimals, fractionDigits: contract.decimals,
@ -104,7 +102,7 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB {
), ),
); );
} }
return TokenBalance.fromJson( return Balance.fromJson(
jsonString, jsonString,
contract.decimals, contract.decimals,
); );
@ -222,7 +220,6 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB {
web3.Web3Client client = getEthClient(); web3.Web3Client client = getEthClient();
web3.EtherAmount ethBalance = await client.getBalance(_credentials.address); web3.EtherAmount ethBalance = await client.getBalance(_credentials.address);
_balance = Balance( _balance = Balance(
coin: coin,
total: Amount( total: Amount(
rawValue: ethBalance.getInWei, rawValue: ethBalance.getInWei,
fractionDigits: coin.decimals, fractionDigits: coin.decimals,

View file

@ -2522,7 +2522,6 @@ class FiroWallet extends CoinServiceAPI
} }
_balancePrivate = Balance( _balancePrivate = Balance(
coin: coin,
total: Amount( total: Amount(
rawValue: rawValue:
BigInt.from(intLelantusBalance + unconfirmedLelantusBalance), BigInt.from(intLelantusBalance + unconfirmedLelantusBalance),
@ -3810,7 +3809,6 @@ class FiroWallet extends CoinServiceAPI
// finally update public balance // finally update public balance
_balance = Balance( _balance = Balance(
coin: coin,
total: satoshiBalanceTotal, total: satoshiBalanceTotal,
spendable: satoshiBalanceSpendable, spendable: satoshiBalanceSpendable,
blockedTotal: satoshiBalanceBlocked, blockedTotal: satoshiBalanceBlocked,

View file

@ -747,7 +747,6 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
final total = await _totalBalance; final total = await _totalBalance;
final available = await _availableBalance; final available = await _availableBalance;
_balance = Balance( _balance = Balance(
coin: coin,
total: total, total: total,
spendable: available, spendable: available,
blockedTotal: Amount( blockedTotal: Amount(

View file

@ -774,7 +774,6 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
final total = await _totalBalance; final total = await _totalBalance;
final available = await _availableBalance; final available = await _availableBalance;
_balance = Balance( _balance = Balance(
coin: coin,
total: total, total: total,
spendable: available, spendable: available,
blockedTotal: Amount( blockedTotal: Amount(

View file

@ -1,5 +1,5 @@
import 'package:stackwallet/models/balance.dart';
import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart'; import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart';
import 'package:stackwallet/models/token_balance.dart';
import 'package:stackwallet/services/ethereum/ethereum_api.dart'; import 'package:stackwallet/services/ethereum/ethereum_api.dart';
import 'package:stackwallet/services/mixins/eth_token_cache.dart'; import 'package:stackwallet/services/mixins/eth_token_cache.dart';
import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount.dart';
@ -21,8 +21,7 @@ class CachedEthTokenBalance with EthTokenCache {
if (response.value != null) { if (response.value != null) {
await updateCachedBalance( await updateCachedBalance(
TokenBalance( Balance(
contractAddress: token.address,
total: response.value!, total: response.value!,
spendable: response.value!, spendable: response.value!,
blockedTotal: Amount( blockedTotal: Amount(

View file

@ -1,6 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'package:decimal/decimal.dart';
import 'package:ethereum_addresses/ethereum_addresses.dart'; import 'package:ethereum_addresses/ethereum_addresses.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:http/http.dart'; import 'package:http/http.dart';
@ -8,10 +7,10 @@ import 'package:isar/isar.dart';
import 'package:stackwallet/db/isar/main_db.dart'; import 'package:stackwallet/db/isar/main_db.dart';
import 'package:stackwallet/dto/ethereum/eth_token_tx_dto.dart'; import 'package:stackwallet/dto/ethereum/eth_token_tx_dto.dart';
import 'package:stackwallet/dto/ethereum/eth_token_tx_extra_dto.dart'; import 'package:stackwallet/dto/ethereum/eth_token_tx_extra_dto.dart';
import 'package:stackwallet/models/balance.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart'; import 'package:stackwallet/models/isar/models/isar_models.dart';
import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/models/node_model.dart';
import 'package:stackwallet/models/paymint/fee_object_model.dart'; import 'package:stackwallet/models/paymint/fee_object_model.dart';
import 'package:stackwallet/models/token_balance.dart';
import 'package:stackwallet/services/coins/ethereum/ethereum_wallet.dart'; import 'package:stackwallet/services/coins/ethereum/ethereum_wallet.dart';
import 'package:stackwallet/services/ethereum/ethereum_api.dart'; import 'package:stackwallet/services/ethereum/ethereum_api.dart';
import 'package:stackwallet/services/event_bus/events/global/updated_in_background_event.dart'; import 'package:stackwallet/services/event_bus/events/global/updated_in_background_event.dart';
@ -40,7 +39,6 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache {
// late web3dart.EthereumAddress _contractAddress; // late web3dart.EthereumAddress _contractAddress;
late web3dart.EthPrivateKey _credentials; late web3dart.EthPrivateKey _credentials;
late web3dart.DeployedContract _deployedContract; late web3dart.DeployedContract _deployedContract;
late web3dart.ContractFunction _balanceFunction;
late web3dart.ContractFunction _sendFunction; late web3dart.ContractFunction _sendFunction;
late web3dart.Web3Client _client; late web3dart.Web3Client _client;
@ -60,8 +58,8 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache {
EthContract get tokenContract => _tokenContract; EthContract get tokenContract => _tokenContract;
EthContract _tokenContract; EthContract _tokenContract;
TokenBalance get balance => _balance ??= getCachedBalance(); Balance get balance => _balance ??= getCachedBalance();
TokenBalance? _balance; Balance? _balance;
Coin get coin => Coin.ethereum; Coin get coin => Coin.ethereum;
@ -259,12 +257,12 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache {
final contractAddress = final contractAddress =
web3dart.EthereumAddress.fromHex(tokenContract.address); web3dart.EthereumAddress.fromHex(tokenContract.address);
// if (tokenContract.abi == null) { if (tokenContract.abi == null) {
_tokenContract = await _updateTokenABI( _tokenContract = await _updateTokenABI(
forContract: tokenContract, forContract: tokenContract,
usingContractAddress: contractAddress.hex, usingContractAddress: contractAddress.hex,
); );
// } }
String? mnemonicString = await ethWallet.mnemonicString; String? mnemonicString = await ethWallet.mnemonicString;
@ -284,7 +282,6 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache {
); );
try { try {
_balanceFunction = _deployedContract.function('balanceOf');
_sendFunction = _deployedContract.function('transfer'); _sendFunction = _deployedContract.function('transfer');
} catch (_) { } catch (_) {
//==================================================================== //====================================================================
@ -359,7 +356,6 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache {
contractAddress, contractAddress,
); );
_balanceFunction = _deployedContract.function('balanceOf');
_sendFunction = _deployedContract.function('transfer'); _sendFunction = _deployedContract.function('transfer');
_client = await getEthClient(); _client = await getEthClient();
@ -405,24 +401,16 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache {
} }
Future<void> refreshCachedBalance() async { Future<void> refreshCachedBalance() async {
final balanceRequest = await _client.call( final response = await EthereumAPI.getWalletTokenBalance(
contract: _deployedContract, address: _credentials.address.hex,
function: _balanceFunction, contractAddress: tokenContract.address,
params: [_credentials.address],
); );
String _balance = balanceRequest.first.toString(); if (response.value != null) {
await updateCachedBalance(
final newBalance = TokenBalance( Balance(
contractAddress: tokenContract.address, total: response.value!,
total: Amount.fromDecimal( spendable: response.value!,
Decimal.parse(_balance),
fractionDigits: tokenContract.decimals,
),
spendable: Amount.fromDecimal(
Decimal.parse(_balance),
fractionDigits: tokenContract.decimals,
),
blockedTotal: Amount( blockedTotal: Amount(
rawValue: BigInt.zero, rawValue: BigInt.zero,
fractionDigits: tokenContract.decimals, fractionDigits: tokenContract.decimals,
@ -431,9 +419,15 @@ class EthTokenWallet extends ChangeNotifier with EthTokenCache {
rawValue: BigInt.zero, rawValue: BigInt.zero,
fractionDigits: tokenContract.decimals, fractionDigits: tokenContract.decimals,
), ),
),
); );
await updateCachedBalance(newBalance);
notifyListeners(); notifyListeners();
} else {
Logging.instance.log(
"CachedEthTokenBalance.fetchAndUpdateCachedBalance failed: ${response.exception}",
level: LogLevel.Warning,
);
}
} }
Future<List<Transaction>> get transactions => ethWallet.db Future<List<Transaction>> get transactions => ethWallet.db

View file

@ -76,7 +76,6 @@ mixin CoinControlInterface {
} }
final balance = Balance( final balance = Balance(
coin: _coin,
total: satoshiBalanceTotal, total: satoshiBalanceTotal,
spendable: satoshiBalanceSpendable, spendable: satoshiBalanceSpendable,
blockedTotal: satoshiBalanceBlocked, blockedTotal: satoshiBalanceBlocked,

View file

@ -1,6 +1,6 @@
import 'package:stackwallet/db/hive/db.dart'; import 'package:stackwallet/db/hive/db.dart';
import 'package:stackwallet/models/balance.dart';
import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart'; import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart';
import 'package:stackwallet/models/token_balance.dart';
import 'package:stackwallet/utilities/amount/amount.dart'; import 'package:stackwallet/utilities/amount/amount.dart';
abstract class TokenCacheKeys { abstract class TokenCacheKeys {
@ -19,14 +19,13 @@ mixin EthTokenCache {
} }
// token balance cache // token balance cache
TokenBalance getCachedBalance() { Balance getCachedBalance() {
final jsonString = DB.instance.get<dynamic>( final jsonString = DB.instance.get<dynamic>(
boxName: _walletId, boxName: _walletId,
key: TokenCacheKeys.tokenBalance(_token.address), key: TokenCacheKeys.tokenBalance(_token.address),
) as String?; ) as String?;
if (jsonString == null) { if (jsonString == null) {
return TokenBalance( return Balance(
contractAddress: _token.address,
total: Amount( total: Amount(
rawValue: BigInt.zero, rawValue: BigInt.zero,
fractionDigits: _token.decimals, fractionDigits: _token.decimals,
@ -45,13 +44,13 @@ mixin EthTokenCache {
), ),
); );
} }
return TokenBalance.fromJson( return Balance.fromJson(
jsonString, jsonString,
_token.decimals, _token.decimals,
); );
} }
Future<void> updateCachedBalance(TokenBalance balance) async { Future<void> updateCachedBalance(Balance balance) async {
await DB.instance.put<dynamic>( await DB.instance.put<dynamic>(
boxName: _walletId, boxName: _walletId,
key: TokenCacheKeys.tokenBalance(_token.address), key: TokenCacheKeys.tokenBalance(_token.address),

View file

@ -70,7 +70,6 @@ mixin WalletCache {
) as String?; ) as String?;
if (jsonString == null) { if (jsonString == null) {
return Balance( return Balance(
coin: _coin,
total: Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals), total: Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals),
spendable: spendable:
Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals), Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals),
@ -80,7 +79,7 @@ mixin WalletCache {
Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals), Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals),
); );
} }
return Balance.fromJson(jsonString, _coin); return Balance.fromJson(jsonString, _coin.decimals);
} }
Future<void> updateCachedBalance(Balance balance) async { Future<void> updateCachedBalance(Balance balance) async {
@ -99,7 +98,6 @@ mixin WalletCache {
) as String?; ) as String?;
if (jsonString == null) { if (jsonString == null) {
return Balance( return Balance(
coin: _coin,
total: Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals), total: Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals),
spendable: spendable:
Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals), Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals),
@ -109,7 +107,7 @@ mixin WalletCache {
Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals), Amount(rawValue: BigInt.zero, fractionDigits: _coin.decimals),
); );
} }
return Balance.fromJson(jsonString, _coin); return Balance.fromJson(jsonString, _coin.decimals);
} }
Future<void> updateCachedBalanceSecondary(Balance balance) async { Future<void> updateCachedBalanceSecondary(Balance balance) async {

View file

@ -335,6 +335,26 @@ class ChanColors extends StackColorTheme {
@override @override
Color get rateTypeToggleDesktopColorOff => buttonBackSecondary; Color get rateTypeToggleDesktopColorOff => buttonBackSecondary;
// token view colors
@override
Color get ethTagText => const Color(0xFFFFFFFF);
@override
Color get ethTagBG => const Color(0xFF4D5798);
@override
Color get ethWalletTagText => const Color(0xFF4D5798);
@override
Color get ethWalletTagBG => const Color(0xFFF0F3FD);
@override
Color get tokenSummaryTextPrimary => const Color(0xFF232323);
@override
Color get tokenSummaryTextSecondary => const Color(0xFF8488AB);
@override
Color get tokenSummaryBG => const Color(0xFFE9EAFF);
@override
Color get tokenSummaryButtonBG => const Color(0xFFFFFFFF);
@override
Color get tokenSummaryIcon => const Color(0xFF424A97);
@override @override
BoxShadow get standardBoxShadow => BoxShadow( BoxShadow get standardBoxShadow => BoxShadow(
color: shadow, color: shadow,

View file

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/theme/chan_colors.dart';
import 'package:stackwallet/utilities/theme/dark_colors.dart'; import 'package:stackwallet/utilities/theme/dark_colors.dart';
import 'package:stackwallet/utilities/theme/forest_colors.dart'; import 'package:stackwallet/utilities/theme/forest_colors.dart';
import 'package:stackwallet/utilities/theme/fruit_sorbet_colors.dart'; import 'package:stackwallet/utilities/theme/fruit_sorbet_colors.dart';
@ -7,9 +8,7 @@ import 'package:stackwallet/utilities/theme/light_colors.dart';
import 'package:stackwallet/utilities/theme/ocean_breeze_colors.dart'; import 'package:stackwallet/utilities/theme/ocean_breeze_colors.dart';
import 'package:stackwallet/utilities/theme/oled_black_colors.dart'; import 'package:stackwallet/utilities/theme/oled_black_colors.dart';
import 'package:stackwallet/utilities/theme/oled_chans_colors.dart'; import 'package:stackwallet/utilities/theme/oled_chans_colors.dart';
import 'package:stackwallet/utilities/theme/orange_colors.dart';
import 'chan_colors.dart';
import 'orange_colors.dart';
enum ThemeType { enum ThemeType {
light, light,
@ -285,6 +284,17 @@ abstract class StackColorTheme {
Color get rateTypeToggleDesktopColorOn; Color get rateTypeToggleDesktopColorOn;
Color get rateTypeToggleDesktopColorOff; Color get rateTypeToggleDesktopColorOff;
// token view colors
Color get ethTagText;
Color get ethTagBG;
Color get ethWalletTagText;
Color get ethWalletTagBG;
Color get tokenSummaryTextPrimary;
Color get tokenSummaryTextSecondary;
Color get tokenSummaryBG;
Color get tokenSummaryButtonBG;
Color get tokenSummaryIcon;
BoxShadow get standardBoxShadow; BoxShadow get standardBoxShadow;
BoxShadow? get homeViewButtonBarBoxShadow; BoxShadow? get homeViewButtonBarBoxShadow;
} }

View file

@ -335,6 +335,26 @@ class DarkColors extends StackColorTheme {
@override @override
Color get rateTypeToggleDesktopColorOff => buttonBackSecondary; Color get rateTypeToggleDesktopColorOff => buttonBackSecondary;
// token view colors
@override
Color get ethTagText => const Color(0xFFFFFFFF);
@override
Color get ethTagBG => const Color(0xFF5761A2);
@override
Color get ethWalletTagText => const Color(0xFFE7EBFF);
@override
Color get ethWalletTagBG => const Color(0xFF414868);
@override
Color get tokenSummaryTextPrimary => const Color(0xFFFFFFFF);
@override
Color get tokenSummaryTextSecondary => const Color(0xFFC9D0FF);
@override
Color get tokenSummaryBG => const Color(0xFF464C73);
@override
Color get tokenSummaryButtonBG => const Color(0xFFC9D0FF);
@override
Color get tokenSummaryIcon => const Color(0xFF252C78);
@override @override
BoxShadow get standardBoxShadow => BoxShadow( BoxShadow get standardBoxShadow => BoxShadow(
color: shadow, color: shadow,

View file

@ -335,6 +335,26 @@ class ForestColors extends StackColorTheme {
@override @override
Color get rateTypeToggleDesktopColorOff => buttonBackSecondary; Color get rateTypeToggleDesktopColorOff => buttonBackSecondary;
// token view colors
@override
Color get ethTagText => const Color(0xFFFFFFFF);
@override
Color get ethTagBG => const Color(0xFF4D5798);
@override
Color get ethWalletTagText => const Color(0xFF4D5798);
@override
Color get ethWalletTagBG => const Color(0xFFEBEFFE);
@override
Color get tokenSummaryTextPrimary => const Color(0xFF232323);
@override
Color get tokenSummaryTextSecondary => const Color(0xFF4D5798);
@override
Color get tokenSummaryBG => const Color(0xFFFFFFFF);
@override
Color get tokenSummaryButtonBG => const Color(0xFFE9FBEF);
@override
Color get tokenSummaryIcon => const Color(0xFF22867A);
@override @override
BoxShadow get standardBoxShadow => BoxShadow( BoxShadow get standardBoxShadow => BoxShadow(
color: shadow, color: shadow,

View file

@ -335,6 +335,26 @@ class FruitSorbetColors extends StackColorTheme {
@override @override
Color get rateTypeToggleDesktopColorOff => popupBG; Color get rateTypeToggleDesktopColorOff => popupBG;
// token view colors
@override
Color get ethTagText => const Color(0xFFFFFFFF);
@override
Color get ethTagBG => const Color(0xFF4D5798);
@override
Color get ethWalletTagText => const Color(0xFF4D5798);
@override
Color get ethWalletTagBG => const Color(0xFFEBEFFE);
@override
Color get tokenSummaryTextPrimary => const Color(0xFF232323);
@override
Color get tokenSummaryTextSecondary => const Color(0xFF4D5798);
@override
Color get tokenSummaryBG => const Color(0xFFFFF8EE);
@override
Color get tokenSummaryButtonBG => const Color(0xFFFEDED4);
@override
Color get tokenSummaryIcon => const Color(0xFFF62A45);
@override @override
BoxShadow get standardBoxShadow => BoxShadow( BoxShadow get standardBoxShadow => BoxShadow(
color: shadow, color: shadow,

View file

@ -335,6 +335,26 @@ class LightColors extends StackColorTheme {
@override @override
Color get rateTypeToggleDesktopColorOff => buttonBackSecondary; Color get rateTypeToggleDesktopColorOff => buttonBackSecondary;
// token view colors
@override
Color get ethTagText => const Color(0xFFFFFFFF);
@override
Color get ethTagBG => const Color(0xFF4D5798);
@override
Color get ethWalletTagText => const Color(0xFF4D5798);
@override
Color get ethWalletTagBG => const Color(0xFFF0F3FD);
@override
Color get tokenSummaryTextPrimary => const Color(0xFF232323);
@override
Color get tokenSummaryTextSecondary => const Color(0xFF8488AB);
@override
Color get tokenSummaryBG => const Color(0xFFE9EAFF);
@override
Color get tokenSummaryButtonBG => const Color(0xFFFFFFFF);
@override
Color get tokenSummaryIcon => const Color(0xFF424A97);
@override @override
BoxShadow get standardBoxShadow => BoxShadow( BoxShadow get standardBoxShadow => BoxShadow(
color: shadow, color: shadow,

View file

@ -342,6 +342,26 @@ class OceanBreezeColors extends StackColorTheme {
@override @override
Color get rateTypeToggleDesktopColorOff => buttonBackSecondary; Color get rateTypeToggleDesktopColorOff => buttonBackSecondary;
// token view colors
@override
Color get ethTagText => const Color(0xFFFFFFFF);
@override
Color get ethTagBG => const Color(0xFF4D5798);
@override
Color get ethWalletTagText => const Color(0xFF4D5798);
@override
Color get ethWalletTagBG => const Color(0xFFEBEFFE);
@override
Color get tokenSummaryTextPrimary => const Color(0xFF232323);
@override
Color get tokenSummaryTextSecondary => const Color(0xFF4D5798);
@override
Color get tokenSummaryBG => const Color(0xFFFFFFFF);
@override
Color get tokenSummaryButtonBG => const Color(0xFFEDF4F9);
@override
Color get tokenSummaryIcon => const Color(0xFF197287);
@override @override
BoxShadow get standardBoxShadow => BoxShadow( BoxShadow get standardBoxShadow => BoxShadow(
color: shadow, color: shadow,

View file

@ -338,6 +338,26 @@ class OledBlackColors extends StackColorTheme {
@override @override
Color get rateTypeToggleDesktopColorOff => buttonBackSecondary; Color get rateTypeToggleDesktopColorOff => buttonBackSecondary;
// token view colors
@override
Color get ethTagText => const Color(0xFFFFFFFF);
@override
Color get ethTagBG => const Color(0xFF5761A2);
@override
Color get ethWalletTagText => const Color(0xFFDEDEDE);
@override
Color get ethWalletTagBG => const Color(0xFF222539);
@override
Color get tokenSummaryTextPrimary => const Color(0xFFFFFFFF);
@override
Color get tokenSummaryTextSecondary => const Color(0xFFC9D0FF);
@override
Color get tokenSummaryBG => const Color(0xFF292D45);
@override
Color get tokenSummaryButtonBG => const Color(0xFFC9D0FF);
@override
Color get tokenSummaryIcon => const Color(0xFF252C78);
@override @override
BoxShadow get standardBoxShadow => BoxShadow( BoxShadow get standardBoxShadow => BoxShadow(
color: shadow, color: shadow,

View file

@ -335,6 +335,26 @@ class DarkChansColors extends StackColorTheme {
@override @override
Color get rateTypeToggleDesktopColorOff => buttonBackSecondary; Color get rateTypeToggleDesktopColorOff => buttonBackSecondary;
// token view colors
@override
Color get ethTagText => const Color(0xFFFFFFFF);
@override
Color get ethTagBG => const Color(0xFF5761A2);
@override
Color get ethWalletTagText => const Color(0xFFDEDEDE);
@override
Color get ethWalletTagBG => const Color(0xFF222539);
@override
Color get tokenSummaryTextPrimary => const Color(0xFFFFFFFF);
@override
Color get tokenSummaryTextSecondary => const Color(0xFFC9D0FF);
@override
Color get tokenSummaryBG => const Color(0xFF292D45);
@override
Color get tokenSummaryButtonBG => const Color(0xFFC9D0FF);
@override
Color get tokenSummaryIcon => const Color(0xFF252C78);
@override @override
BoxShadow get standardBoxShadow => BoxShadow( BoxShadow get standardBoxShadow => BoxShadow(
color: shadow, color: shadow,

View file

@ -335,6 +335,26 @@ class OrangeColors extends StackColorTheme {
@override @override
Color get rateTypeToggleDesktopColorOff => buttonBackSecondary; Color get rateTypeToggleDesktopColorOff => buttonBackSecondary;
// token view colors
@override
Color get ethTagText => const Color(0xFFFFFFFF);
@override
Color get ethTagBG => const Color(0xFF4D5798);
@override
Color get ethWalletTagText => const Color(0xFF4D5798);
@override
Color get ethWalletTagBG => const Color(0xFFEBEFFE);
@override
Color get tokenSummaryTextPrimary => const Color(0xFF232323);
@override
Color get tokenSummaryTextSecondary => const Color(0xFF4D5798);
@override
Color get tokenSummaryBG => const Color(0xFFFFFFFF);
@override
Color get tokenSummaryButtonBG => const Color(0xAAFFC58F);
@override
Color get tokenSummaryIcon => const Color(0xFFF36B43);
@override @override
BoxShadow get standardBoxShadow => BoxShadow( BoxShadow get standardBoxShadow => BoxShadow(
color: shadow, color: shadow,

View file

@ -187,6 +187,17 @@ class StackColors extends ThemeExtension<StackColors> {
final Color rateTypeToggleDesktopColorOn; final Color rateTypeToggleDesktopColorOn;
final Color rateTypeToggleDesktopColorOff; final Color rateTypeToggleDesktopColorOff;
// token view colors
final Color ethTagText;
final Color ethTagBG;
final Color ethWalletTagText;
final Color ethWalletTagBG;
final Color tokenSummaryTextPrimary;
final Color tokenSummaryTextSecondary;
final Color tokenSummaryBG;
final Color tokenSummaryButtonBG;
final Color tokenSummaryIcon;
final BoxShadow standardBoxShadow; final BoxShadow standardBoxShadow;
final BoxShadow? homeViewButtonBarBoxShadow; final BoxShadow? homeViewButtonBarBoxShadow;
@ -337,6 +348,15 @@ class StackColors extends ThemeExtension<StackColors> {
required this.rateTypeToggleDesktopColorOff, required this.rateTypeToggleDesktopColorOff,
required this.standardBoxShadow, required this.standardBoxShadow,
required this.homeViewButtonBarBoxShadow, required this.homeViewButtonBarBoxShadow,
required this.ethTagText,
required this.ethTagBG,
required this.ethWalletTagText,
required this.ethWalletTagBG,
required this.tokenSummaryTextPrimary,
required this.tokenSummaryTextSecondary,
required this.tokenSummaryBG,
required this.tokenSummaryButtonBG,
required this.tokenSummaryIcon,
}); });
factory StackColors.fromStackColorTheme(StackColorTheme colorTheme) { factory StackColors.fromStackColorTheme(StackColorTheme colorTheme) {
@ -490,6 +510,15 @@ class StackColors extends ThemeExtension<StackColors> {
rateTypeToggleDesktopColorOff: colorTheme.rateTypeToggleDesktopColorOff, rateTypeToggleDesktopColorOff: colorTheme.rateTypeToggleDesktopColorOff,
homeViewButtonBarBoxShadow: colorTheme.homeViewButtonBarBoxShadow, homeViewButtonBarBoxShadow: colorTheme.homeViewButtonBarBoxShadow,
standardBoxShadow: colorTheme.standardBoxShadow, standardBoxShadow: colorTheme.standardBoxShadow,
ethTagText: colorTheme.ethTagText,
ethTagBG: colorTheme.ethTagBG,
ethWalletTagText: colorTheme.ethWalletTagText,
ethWalletTagBG: colorTheme.ethWalletTagBG,
tokenSummaryTextPrimary: colorTheme.tokenSummaryTextPrimary,
tokenSummaryTextSecondary: colorTheme.tokenSummaryTextSecondary,
tokenSummaryBG: colorTheme.tokenSummaryBG,
tokenSummaryButtonBG: colorTheme.tokenSummaryButtonBG,
tokenSummaryIcon: colorTheme.tokenSummaryIcon,
); );
} }
@ -639,6 +668,15 @@ class StackColors extends ThemeExtension<StackColors> {
Color? rateTypeToggleColorOff, Color? rateTypeToggleColorOff,
Color? rateTypeToggleDesktopColorOn, Color? rateTypeToggleDesktopColorOn,
Color? rateTypeToggleDesktopColorOff, Color? rateTypeToggleDesktopColorOff,
Color? ethTagText,
Color? ethTagBG,
Color? ethWalletTagText,
Color? ethWalletTagBG,
Color? tokenSummaryTextPrimary,
Color? tokenSummaryTextSecondary,
Color? tokenSummaryBG,
Color? tokenSummaryButtonBG,
Color? tokenSummaryIcon,
BoxShadow? homeViewButtonBarBoxShadow, BoxShadow? homeViewButtonBarBoxShadow,
BoxShadow? standardBoxShadow, BoxShadow? standardBoxShadow,
}) { }) {
@ -833,6 +871,17 @@ class StackColors extends ThemeExtension<StackColors> {
rateTypeToggleDesktopColorOn ?? this.rateTypeToggleDesktopColorOn, rateTypeToggleDesktopColorOn ?? this.rateTypeToggleDesktopColorOn,
rateTypeToggleDesktopColorOff: rateTypeToggleDesktopColorOff:
rateTypeToggleDesktopColorOff ?? this.rateTypeToggleDesktopColorOff, rateTypeToggleDesktopColorOff ?? this.rateTypeToggleDesktopColorOff,
ethTagText: ethTagText ?? this.ethTagText,
ethTagBG: ethTagBG ?? this.ethTagBG,
ethWalletTagText: ethWalletTagText ?? this.ethWalletTagText,
ethWalletTagBG: ethWalletTagBG ?? this.ethWalletTagBG,
tokenSummaryTextPrimary:
tokenSummaryTextPrimary ?? this.tokenSummaryTextPrimary,
tokenSummaryTextSecondary:
tokenSummaryTextSecondary ?? this.tokenSummaryTextSecondary,
tokenSummaryBG: tokenSummaryBG ?? this.tokenSummaryBG,
tokenSummaryButtonBG: tokenSummaryButtonBG ?? this.tokenSummaryButtonBG,
tokenSummaryIcon: tokenSummaryIcon ?? this.tokenSummaryIcon,
homeViewButtonBarBoxShadow: homeViewButtonBarBoxShadow:
homeViewButtonBarBoxShadow ?? this.homeViewButtonBarBoxShadow, homeViewButtonBarBoxShadow ?? this.homeViewButtonBarBoxShadow,
standardBoxShadow: standardBoxShadow ?? this.standardBoxShadow, standardBoxShadow: standardBoxShadow ?? this.standardBoxShadow,
@ -1557,6 +1606,51 @@ class StackColors extends ThemeExtension<StackColors> {
other.rateTypeToggleDesktopColorOff, other.rateTypeToggleDesktopColorOff,
t, t,
)!, )!,
ethTagText: Color.lerp(
ethTagText,
other.ethTagText,
t,
)!,
ethTagBG: Color.lerp(
ethTagBG,
other.ethTagBG,
t,
)!,
ethWalletTagText: Color.lerp(
ethWalletTagText,
other.ethWalletTagText,
t,
)!,
ethWalletTagBG: Color.lerp(
ethWalletTagBG,
other.ethWalletTagBG,
t,
)!,
tokenSummaryTextPrimary: Color.lerp(
tokenSummaryTextPrimary,
other.tokenSummaryTextPrimary,
t,
)!,
tokenSummaryTextSecondary: Color.lerp(
tokenSummaryTextSecondary,
other.tokenSummaryTextSecondary,
t,
)!,
tokenSummaryBG: Color.lerp(
tokenSummaryBG,
other.tokenSummaryBG,
t,
)!,
tokenSummaryButtonBG: Color.lerp(
tokenSummaryButtonBG,
other.tokenSummaryButtonBG,
t,
)!,
tokenSummaryIcon: Color.lerp(
tokenSummaryIcon,
other.tokenSummaryIcon,
t,
)!,
); );
} }

View file

@ -3,7 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart'; import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance.dart';
import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart'; import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart';
class EthWalletRadio extends ConsumerStatefulWidget { class EthWalletRadio extends ConsumerStatefulWidget {

View file

@ -49,7 +49,13 @@ class _MasterWalletCardState extends ConsumerState<MasterWalletCard> {
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
child: Expandable( child: Expandable(
controller: expandableController, controller: expandableController,
expandOverride: () {}, onExpandWillChange: (toState) {
if (toState == ExpandableState.expanded) {
rotateIconController.forward?.call();
} else {
rotateIconController.reverse?.call();
}
},
header: Padding( header: Padding(
padding: const EdgeInsets.all(12), padding: const EdgeInsets.all(12),
child: Row( child: Row(
@ -110,7 +116,7 @@ class _MasterWalletCardState extends ConsumerState<MasterWalletCard> {
padding: const EdgeInsets.all( padding: const EdgeInsets.all(
7, 7,
), ),
child: WalletSheetCard( child: SimpleWalletCard(
walletId: widget.walletId, walletId: widget.walletId,
popPrevious: true, popPrevious: true,
), ),
@ -122,7 +128,7 @@ class _MasterWalletCardState extends ConsumerState<MasterWalletCard> {
right: 7, right: 7,
bottom: 7, bottom: 7,
), ),
child: WalletSheetCard( child: SimpleWalletCard(
walletId: widget.walletId, walletId: widget.walletId,
contractAddress: e, contractAddress: e,
popPrevious: true, popPrevious: true,

View file

@ -21,8 +21,8 @@ import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/wallet_info_row/wallet_info_row.dart'; import 'package:stackwallet/widgets/wallet_info_row/wallet_info_row.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
class WalletSheetCard extends ConsumerWidget { class SimpleWalletCard extends ConsumerWidget {
const WalletSheetCard({ const SimpleWalletCard({
Key? key, Key? key,
required this.walletId, required this.walletId,
this.contractAddress, this.contractAddress,
@ -113,7 +113,7 @@ class WalletSheetCard extends ConsumerWidget {
child: MaterialButton( child: MaterialButton(
// splashColor: Theme.of(context).extension<StackColors>()!.highlight, // splashColor: Theme.of(context).extension<StackColors>()!.highlight,
key: Key("walletsSheetItemButtonKey_$walletId"), key: Key("walletsSheetItemButtonKey_$walletId"),
padding: const EdgeInsets.all(5), padding: const EdgeInsets.all(10),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(

View file

@ -8,7 +8,7 @@ import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart'; import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart'; import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance.dart';
import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart'; import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart';
class WalletInfoRow extends ConsumerWidget { class WalletInfoRow extends ConsumerWidget {

View file

@ -84,7 +84,7 @@ void main() {
), ),
home: mockingjay.MockNavigatorProvider( home: mockingjay.MockNavigatorProvider(
navigator: navigator, navigator: navigator,
child: const WalletSheetCard( child: const SimpleWalletCard(
walletId: "wallet id", walletId: "wallet id",
)), )),
), ),
@ -122,7 +122,7 @@ void main() {
mockito.when(wallets.getManagerProvider("wallet id")).thenAnswer( mockito.when(wallets.getManagerProvider("wallet id")).thenAnswer(
(realInvocation) => ChangeNotifierProvider((ref) => manager)); (realInvocation) => ChangeNotifierProvider((ref) => manager));
const walletSheetCard = WalletSheetCard( const walletSheetCard = SimpleWalletCard(
walletId: "wallet id", walletId: "wallet id",
); );

View file

@ -15,7 +15,7 @@ import 'package:stackwallet/utilities/amount/amount.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/theme/light_colors.dart'; import 'package:stackwallet/utilities/theme/light_colors.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart'; import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance.dart';
import 'wallet_info_row_balance_future_test.mocks.dart'; import 'wallet_info_row_balance_future_test.mocks.dart';

View file

@ -15,7 +15,7 @@ import 'package:stackwallet/utilities/amount/amount.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/theme/light_colors.dart'; import 'package:stackwallet/utilities/theme/light_colors.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart'; import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance.dart';
import 'package:stackwallet/widgets/wallet_info_row/wallet_info_row.dart'; import 'package:stackwallet/widgets/wallet_info_row/wallet_info_row.dart';
import 'wallet_info_row_test.mocks.dart'; import 'wallet_info_row_test.mocks.dart';