WIP add wallet coin options lists

This commit is contained in:
julian 2023-02-27 16:43:09 -06:00
parent 0956ee3137
commit 24e66f3d5f
9 changed files with 286 additions and 93 deletions

View file

@ -1,14 +1,17 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/add_wallet_text.dart';
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/mobile_coin_list.dart';
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/next_button.dart';
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/searchable_coin_list.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/default_eth_tokens.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
@ -17,27 +20,35 @@ import 'package:stackwallet/widgets/background.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
import 'package:stackwallet/widgets/desktop/desktop_scaffold.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';
class AddWalletView extends StatefulWidget {
class AddWalletView extends ConsumerStatefulWidget {
const AddWalletView({Key? key}) : super(key: key);
static const routeName = "/addWallet";
@override
State<AddWalletView> createState() => _AddWalletViewState();
ConsumerState<AddWalletView> createState() => _AddWalletViewState();
}
class _AddWalletViewState extends State<AddWalletView> {
class _AddWalletViewState extends ConsumerState<AddWalletView> {
late final TextEditingController _searchFieldController;
late final FocusNode _searchFocusNode;
String _searchTerm = "";
final List<Coin> coins = [...Coin.values];
final List<Coin> _coinsTestnet = [
...Coin.values.sublist(Coin.values.length - kTestNetCoinCount - 1),
];
final List<Coin> _coins = [
...Coin.values.sublist(0, Coin.values.length - kTestNetCoinCount - 1)
];
final List<AddWalletListEntity> coinEntities = [];
final List<AddWalletListEntity> tokenEntities = [];
final bool isDesktop = Util.isDesktop;
@ -45,13 +56,23 @@ class _AddWalletViewState extends State<AddWalletView> {
void initState() {
_searchFieldController = TextEditingController();
_searchFocusNode = FocusNode();
coins.remove(Coin.firoTestNet);
_coinsTestnet.remove(Coin.firoTestNet);
if (isDesktop) {
coins.remove(Coin.wownero);
_coins.remove(Coin.wownero);
if (Platform.isWindows) {
coins.remove(Coin.monero);
_coins.remove(Coin.monero);
}
}
coinEntities.addAll(_coins.map((e) => CoinEntity(e)));
if (ref.read(prefsChangeNotifierProvider).showTestNetCoins) {
coinEntities.addAll(_coinsTestnet.map((e) => CoinEntity(e)));
}
tokenEntities.addAll(DefaultTokens.list.map((e) => EthTokenEntity(e)));
tokenEntities.sort((a, b) => a.name.compareTo(b.name));
super.initState();
}
@ -166,7 +187,7 @@ class _AddWalletViewState extends State<AddWalletView> {
),
Expanded(
child: SearchableCoinList(
coins: coins,
entities: coinEntities,
isDesktop: true,
searchTerm: _searchTerm,
),
@ -218,8 +239,21 @@ class _AddWalletViewState extends State<AddWalletView> {
height: 16,
),
Expanded(
child: MobileCoinList(
coins: coins,
child: SingleChildScrollView(
child: Column(
children: [
ExpandingSubListItem(
title: "Coins",
entities: coinEntities,
initialState: ExpandableState.expanded,
),
ExpandingSubListItem(
title: "Tokens",
entities: tokenEntities,
initialState: ExpandableState.collapsed,
),
],
),
),
),
const SizedBox(
@ -237,3 +271,91 @@ class _AddWalletViewState extends State<AddWalletView> {
}
}
}
class ExpandingSubListItem extends StatefulWidget {
const ExpandingSubListItem({
Key? key,
required this.title,
required this.entities,
required this.initialState,
}) : super(key: key);
final String title;
final List<AddWalletListEntity> entities;
final ExpandableState initialState;
@override
State<ExpandingSubListItem> createState() => _ExpandingSubListItemState();
}
class _ExpandingSubListItemState extends State<ExpandingSubListItem> {
final isDesktop = Util.isDesktop;
late final ExpandableController _controller;
late bool _expandedState;
@override
void initState() {
_expandedState = widget.initialState == ExpandableState.expanded;
_controller = ExpandableController();
WidgetsBinding.instance.addPostFrameCallback((_) {
if (_expandedState) {
_controller.toggle?.call();
}
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Expandable(
controller: _controller,
onExpandChanged: (state) {
setState(() {
_expandedState = state == ExpandableState.expanded;
});
},
header: Container(
color: Colors.transparent,
child: Padding(
padding: const EdgeInsets.only(
top: 8.0,
bottom: 8.0,
right: 10,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
widget.title,
style: isDesktop
? STextStyles.desktopTextExtraExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textDark3,
)
: STextStyles.smallMed12(context),
textAlign: TextAlign.left,
),
SvgPicture.asset(
_expandedState ? Assets.svg.chevronUp : Assets.svg.chevronDown,
width: 12,
height: 6,
color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveSearchIconRight,
),
],
),
),
),
body: SingleChildScrollView(
primary: false,
child: MobileCoinList(
entities: widget.entities,
),
),
);
}
}

View file

@ -1,10 +1,10 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/mobile_coin_list.dart';
import 'package:stackwallet/providers/providers.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';
@ -12,30 +12,28 @@ import 'package:stackwallet/utilities/util.dart';
class CoinSelectItem extends ConsumerWidget {
const CoinSelectItem({
Key? key,
required this.coin,
required this.entity,
}) : super(key: key);
final Coin coin;
final AddWalletListEntity entity;
@override
Widget build(BuildContext context, WidgetRef ref) {
debugPrint("BUILD: CoinSelectItem for ${coin.name}");
final selectedCoin = ref.watch(addWalletSelectedCoinStateProvider);
debugPrint("BUILD: CoinSelectItem for ${entity.name}");
final selectedEntity = ref.watch(addWalletSelectedEntityStateProvider);
final isDesktop = Util.isDesktop;
return Container(
decoration: BoxDecoration(
// color: selectedCoin == coin ? CFColors.selection : CFColors.white,
color: selectedCoin == coin
color: selectedEntity == entity
? Theme.of(context).extension<StackColors>()!.textFieldActiveBG
: Theme.of(context).extension<StackColors>()!.popupBG,
borderRadius:
BorderRadius.circular(Constants.size.circularBorderRadius),
),
child: MaterialButton(
// splashColor: Theme.of(context).extension<StackColors>()!.highlight,
key: Key("coinSelectItemButtonKey_${coin.name}"),
key: Key("coinSelectItemButtonKey_${entity.name}${entity.ticker}"),
padding: isDesktop
? const EdgeInsets.only(left: 24)
: const EdgeInsets.all(12),
@ -51,7 +49,7 @@ class CoinSelectItem extends ConsumerWidget {
child: Row(
children: [
SvgPicture.asset(
Assets.svg.iconFor(coin: coin),
Assets.svg.iconFor(coin: entity.coin),
width: 26,
height: 26,
),
@ -59,15 +57,15 @@ class CoinSelectItem extends ConsumerWidget {
width: isDesktop ? 12 : 10,
),
Text(
coin.prettyName,
"${entity.name} (${entity.ticker})",
style: isDesktop
? STextStyles.desktopTextMedium(context)
: STextStyles.subtitle600(context).copyWith(
fontSize: 14,
),
),
if (isDesktop && selectedCoin == coin) const Spacer(),
if (isDesktop && selectedCoin == coin)
if (isDesktop && selectedEntity == entity) const Spacer(),
if (isDesktop && selectedEntity == entity)
Padding(
padding: const EdgeInsets.only(
right: 18,
@ -86,8 +84,9 @@ class CoinSelectItem extends ConsumerWidget {
],
),
),
onPressed: () =>
ref.read(addWalletSelectedCoinStateProvider.state).state = coin,
onPressed: () {
ref.read(addWalletSelectedEntityStateProvider.state).state = entity;
},
),
);
}

View file

@ -1,38 +1,73 @@
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/models/ethereum/eth_token.dart';
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/coin_select_item.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
class MobileCoinList extends StatelessWidget {
const MobileCoinList({
Key? key,
required this.coins,
required this.entities,
}) : super(key: key);
final List<Coin> coins;
final List<AddWalletListEntity> entities;
@override
Widget build(BuildContext context) {
return Consumer(
builder: (_, ref, __) {
bool showTestNet = ref.watch(
prefsChangeNotifierProvider.select((value) => value.showTestNetCoins),
);
return ListView.builder(
itemCount:
showTestNet ? coins.length : coins.length - (kTestNetCoinCount),
itemBuilder: (ctx, index) {
return Padding(
padding: const EdgeInsets.all(4),
child: CoinSelectItem(
coin: coins[index],
),
);
},
return ListView.builder(
shrinkWrap: true,
itemCount: entities.length,
primary: false,
itemBuilder: (ctx, index) {
return Padding(
padding: const EdgeInsets.all(4),
child: CoinSelectItem(
entity: entities[index],
),
);
},
);
}
}
abstract class AddWalletListEntity extends Equatable {
Coin get coin;
String get name;
String get ticker;
}
class EthTokenEntity extends AddWalletListEntity {
EthTokenEntity(this.token);
final EthToken token;
@override
Coin get coin => Coin.ethereum;
@override
String get name => token.name;
@override
String get ticker => token.symbol;
@override
List<Object?> get props => [coin, name, ticker, token.contractAddress];
}
class CoinEntity extends AddWalletListEntity {
CoinEntity(this._coin);
final Coin _coin;
@override
Coin get coin => _coin;
@override
String get name => coin.prettyName;
@override
String get ticker => coin.ticker;
@override
List<Object?> get props => [coin, name, ticker];
}

View file

@ -17,7 +17,7 @@ class AddWalletNextButton extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
debugPrint("BUILD: NextButton");
final selectedCoin =
ref.watch(addWalletSelectedCoinStateProvider.state).state;
ref.watch(addWalletSelectedEntityStateProvider.state).state;
final enabled = selectedCoin != null;
@ -26,10 +26,8 @@ class AddWalletNextButton extends ConsumerWidget {
? null
: () {
final selectedCoin =
ref.read(addWalletSelectedCoinStateProvider.state).state;
ref.read(addWalletSelectedEntityStateProvider.state).state;
//todo: check if print needed
// debugPrint("Next pressed with ${selectedCoin!.name} selected!");
Navigator.of(context).pushNamed(
CreateOrRestoreWalletView.routeName,
arguments: selectedCoin,

View file

@ -1,43 +1,41 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/coin_select_item.dart';
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/mobile_coin_list.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
class SearchableCoinList extends ConsumerWidget {
const SearchableCoinList({
Key? key,
required this.coins,
required this.entities,
required this.isDesktop,
required this.searchTerm,
}) : super(key: key);
final List<Coin> coins;
final List<AddWalletListEntity> entities;
final bool isDesktop;
final String searchTerm;
List<Coin> filterCoins(String text, bool showTestNetCoins) {
final _coins = [...coins];
List<AddWalletListEntity> filterCoins(String text, bool showTestNetCoins) {
final _entities = [...entities];
if (text.isNotEmpty) {
final lowercaseTerm = text.toLowerCase();
_coins.retainWhere((e) =>
e.ticker.toLowerCase().contains(lowercaseTerm) ||
e.prettyName.toLowerCase().contains(lowercaseTerm) ||
e.name.toLowerCase().contains(lowercaseTerm));
_entities.retainWhere(
(e) =>
e.ticker.toLowerCase().contains(lowercaseTerm) ||
e.name.toLowerCase().contains(lowercaseTerm) ||
e.coin.name.toLowerCase().contains(lowercaseTerm) ||
(e is EthTokenEntity &&
e.token.contractAddress.toLowerCase().contains(lowercaseTerm)),
);
}
if (!showTestNetCoins) {
_coins.removeWhere(
_entities.removeWhere(
(e) => e.name.endsWith("TestNet") || e == Coin.bitcoincashTestnet);
}
// remove firo testnet regardless
_coins.remove(Coin.firoTestNet);
// Kidgloves for Wownero on desktop
// if(isDesktop) {
// _coins.remove(Coin.wownero);
// }
return _coins;
return _entities;
}
@override
@ -46,15 +44,15 @@ class SearchableCoinList extends ConsumerWidget {
prefsChangeNotifierProvider.select((value) => value.showTestNetCoins),
);
final _coins = filterCoins(searchTerm, showTestNet);
final _entities = filterCoins(searchTerm, showTestNet);
return ListView.builder(
itemCount: _coins.length,
itemCount: _entities.length,
itemBuilder: (ctx, index) {
return Padding(
padding: const EdgeInsets.all(4),
child: CoinSelectItem(
coin: _coins[index],
entity: _entities[index],
),
);
},

View file

@ -1,10 +1,10 @@
import 'package:flutter/material.dart';
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/mobile_coin_list.dart';
import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/coin_image.dart';
import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_or_restore_wallet_subtitle.dart';
import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_or_restore_wallet_title.dart';
import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_wallet_button_group.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/background.dart';
@ -15,12 +15,12 @@ import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
class CreateOrRestoreWalletView extends StatelessWidget {
const CreateOrRestoreWalletView({
Key? key,
required this.coin,
required this.entity,
}) : super(key: key);
static const routeName = "/createOrRestoreWallet";
final Coin coin;
final AddWalletListEntity entity;
@override
Widget build(BuildContext context) {
@ -44,7 +44,7 @@ class CreateOrRestoreWalletView extends StatelessWidget {
flex: 10,
),
CreateRestoreWalletTitle(
coin: coin,
coin: entity.coin,
isDesktop: isDesktop,
),
const SizedBox(
@ -60,14 +60,14 @@ class CreateOrRestoreWalletView extends StatelessWidget {
height: 32,
),
CoinImage(
coin: coin,
coin: entity.coin,
isDesktop: isDesktop,
),
const SizedBox(
height: 32,
),
CreateWalletButtonGroup(
coin: coin,
coin: entity.coin,
isDesktop: isDesktop,
),
const Spacer(
@ -99,7 +99,7 @@ class CreateOrRestoreWalletView extends StatelessWidget {
Padding(
padding: const EdgeInsets.all(31),
child: CoinImage(
coin: coin,
coin: entity.coin,
isDesktop: isDesktop,
),
),
@ -107,7 +107,7 @@ class CreateOrRestoreWalletView extends StatelessWidget {
flex: 2,
),
CreateRestoreWalletTitle(
coin: coin,
coin: entity.coin,
isDesktop: isDesktop,
),
const SizedBox(
@ -120,7 +120,7 @@ class CreateOrRestoreWalletView extends StatelessWidget {
flex: 5,
),
CreateWalletButtonGroup(
coin: coin,
coin: entity.coin,
isDesktop: isDesktop,
),
],

View file

@ -1,14 +1,5 @@
import 'package:flutter/foundation.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/mobile_coin_list.dart';
int _count = 0;
final addWalletSelectedCoinStateProvider =
StateProvider.autoDispose<Coin?>((_) {
if (kDebugMode) {
_count++;
}
return null;
});
final addWalletSelectedEntityStateProvider =
StateProvider.autoDispose<AddWalletListEntity?>((_) => null);

View file

@ -12,6 +12,7 @@ import 'package:stackwallet/models/isar/models/isar_models.dart';
import 'package:stackwallet/models/paynym/paynym_account_lite.dart';
import 'package:stackwallet/models/send_view_auto_fill_data.dart';
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart';
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/mobile_coin_list.dart';
import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/create_or_restore_wallet_view.dart';
import 'package:stackwallet/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart';
import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart';
@ -654,11 +655,11 @@ class RouteGenerator {
return _routeError("${settings.name} invalid args: ${args.toString()}");
case CreateOrRestoreWalletView.routeName:
if (args is Coin) {
if (args is AddWalletListEntity) {
return getRoute(
shouldUseMaterialRoute: useMaterialPageRoute,
builder: (_) => CreateOrRestoreWalletView(
coin: args,
entity: args,
),
settings: RouteSettings(
name: settings.name,

View file

@ -0,0 +1,49 @@
import 'package:stackwallet/models/ethereum/erc20_token.dart';
import 'package:stackwallet/models/ethereum/eth_token.dart';
abstract class DefaultTokens {
static List<EthToken> list = [
Erc20Token(
contractAddress: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
name: "USD Coin",
symbol: "USDC",
decimals: 18,
balance: 0,
),
Erc20Token(
contractAddress: "0xdac17f958d2ee523a2206206994597c13d831ec7",
name: "Tether",
symbol: "USDT",
decimals: 18,
balance: 0,
),
Erc20Token(
contractAddress: "0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce",
name: "Shiba Inu",
symbol: "SHIB",
decimals: 18,
balance: 0,
),
Erc20Token(
contractAddress: "0xB8c77482e45F1F44dE1745F52C74426C631bDD52",
name: "BNB Token",
symbol: "BNB",
decimals: 18,
balance: 0,
),
Erc20Token(
contractAddress: "0x4Fabb145d64652a948d72533023f6E7A623C7C53",
name: "BUSD",
symbol: "BUSD",
decimals: 18,
balance: 0,
),
Erc20Token(
contractAddress: "0x514910771af9ca656af840dff83e8264ecf986ca",
name: "Chainlink",
symbol: "LINK",
decimals: 18,
balance: 0,
),
];
}