add token list ui

This commit is contained in:
julian 2023-02-28 13:26:17 -06:00
parent 6a734e28f0
commit 695d43bbd5
8 changed files with 311 additions and 28 deletions

View file

@ -12,4 +12,15 @@ class EthToken {
final String symbol;
final int decimals;
final int balance;
@override
String toString() {
return "$runtimeType: { "
"name: $name, "
"symbol: $symbol, "
"contractAddress: $contractAddress, "
"decimals: $decimals, "
"balance: $balance"
" }";
}
}

View file

@ -1,12 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/models/add_wallet_list_entity/add_wallet_list_entity.dart';
import 'package:stackwallet/models/add_wallet_list_entity/sub_classes/eth_token_entity.dart';
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/add_wallet_entity_list.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/next_button.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_text.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/default_eth_tokens.dart';
@ -17,6 +16,7 @@ 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/desktop/primary_button.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';
@ -25,8 +25,11 @@ import 'package:stackwallet/widgets/textfield_icon_button.dart';
class AddTokenView extends ConsumerStatefulWidget {
const AddTokenView({
Key? key,
required this.walletId,
}) : super(key: key);
final String walletId;
static const routeName = "/addToken";
@override
@ -39,36 +42,42 @@ class _AddTokenViewState extends ConsumerState<AddTokenView> {
String _searchTerm = "";
final List<AddWalletListEntity> tokenEntities = [];
final List<AddTokenListElementData> tokenEntities = [];
final bool isDesktop = Util.isDesktop;
List<AddWalletListEntity> filter(
List<AddTokenListElementData> filter(
String text,
List<AddWalletListEntity> entities,
List<AddTokenListElementData> entities,
) {
final _entities = [...entities];
if (text.isNotEmpty) {
final lowercaseTerm = text.toLowerCase();
_entities.retainWhere(
(e) =>
e.ticker.toLowerCase().contains(lowercaseTerm) ||
e.name.toLowerCase().contains(lowercaseTerm) ||
(e is EthTokenEntity &&
e.token.contractAddress.toLowerCase().contains(lowercaseTerm)),
e.token.name.toLowerCase().contains(lowercaseTerm) ||
e.token.symbol.toLowerCase().contains(lowercaseTerm) ||
e.token.contractAddress.toLowerCase().contains(lowercaseTerm),
);
}
return _entities;
}
void onNextPressed() {
final selectedTokens =
tokenEntities.where((e) => e.selected).map((e) => e.token);
print("SELECTED TOKENS: $selectedTokens");
}
@override
void initState() {
_searchFieldController = TextEditingController();
_searchFocusNode = FocusNode();
tokenEntities.addAll(DefaultTokens.list.map((e) => EthTokenEntity(e)));
tokenEntities.sort((a, b) => a.name.compareTo(b.name));
tokenEntities
.addAll(DefaultTokens.list.map((e) => AddTokenListElementData(e)));
tokenEntities.sort((a, b) => a.token.name.compareTo(b.token.name));
super.initState();
}
@ -83,6 +92,8 @@ class _AddTokenViewState extends ConsumerState<AddTokenView> {
@override
Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType");
final walletName = ref.watch(walletsChangeNotifierProvider
.select((value) => value.getManager(widget.walletId).walletName));
if (isDesktop) {
return DesktopScaffold(
@ -93,8 +104,9 @@ class _AddTokenViewState extends ConsumerState<AddTokenView> {
),
body: Column(
children: [
const AddWalletText(
AddTokenText(
isDesktop: true,
walletName: walletName,
),
const SizedBox(
height: 16,
@ -183,8 +195,8 @@ class _AddTokenViewState extends ConsumerState<AddTokenView> {
),
),
Expanded(
child: AddWalletEntityList(
entities: filter(_searchTerm, tokenEntities),
child: AddTokenList(
items: filter(_searchTerm, tokenEntities),
),
),
],
@ -195,11 +207,12 @@ class _AddTokenViewState extends ConsumerState<AddTokenView> {
const SizedBox(
height: 16,
),
const SizedBox(
SizedBox(
height: 70,
width: 480,
child: AddWalletNextButton(
isDesktop: true,
child: PrimaryButton(
label: "Next",
onPressed: onNextPressed,
),
),
const SizedBox(
@ -219,6 +232,25 @@ class _AddTokenViewState extends ConsumerState<AddTokenView> {
Navigator.of(context).pop();
},
),
actions: [
AspectRatio(
aspectRatio: 1,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: AppBarIconButton(
icon: SvgPicture.asset(
Assets.svg.circlePlusFilled,
color: Theme.of(context)
.extension<StackColors>()!
.topNavIconPrimary,
),
onPressed: () {
// todo add custom token
},
),
),
),
],
),
body: Container(
color: Theme.of(context).extension<StackColors>()!.background,
@ -227,8 +259,9 @@ class _AddTokenViewState extends ConsumerState<AddTokenView> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const AddWalletText(
AddTokenText(
isDesktop: false,
walletName: walletName,
),
const SizedBox(
height: 16,
@ -289,15 +322,16 @@ class _AddTokenViewState extends ConsumerState<AddTokenView> {
height: 10,
),
Expanded(
child: AddWalletEntityList(
entities: filter(_searchTerm, tokenEntities),
child: AddTokenList(
items: filter(_searchTerm, tokenEntities),
),
),
const SizedBox(
height: 16,
),
const AddWalletNextButton(
isDesktop: false,
PrimaryButton(
label: "Next",
onPressed: onNextPressed,
),
],
),

View file

@ -0,0 +1,85 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:stackwallet/pages/add_wallet_views/add_token_view/sub_widgets/add_token_list_element.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/conditional_parent.dart';
class AddTokenList extends StatelessWidget {
const AddTokenList({
Key? key,
required this.items,
}) : super(key: key);
final List<AddTokenListElementData> items;
@override
Widget build(BuildContext context) {
return ListView.builder(
shrinkWrap: true,
primary: false,
itemCount: items.length,
itemBuilder: (ctx, index) {
return ConditionalParent(
condition: index == items.length - 1,
builder: (child) => Column(
mainAxisSize: MainAxisSize.min,
children: [
child,
Padding(
padding: const EdgeInsets.all(4),
child: RawMaterialButton(
fillColor:
Theme.of(context).extension<StackColors>()!.popupBG,
elevation: 0,
focusElevation: 0,
hoverElevation: 0,
highlightElevation: 0,
constraints: const BoxConstraints(),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
onPressed: () {
// todo add custom token
},
child: Padding(
padding: const EdgeInsets.all(12),
child: Row(
children: [
SvgPicture.asset(
Assets.svg.circlePlusFilled,
color: Theme.of(context)
.extension<StackColors>()!
.textDark,
width: 24,
height: 24,
),
const SizedBox(
width: 12,
),
Text(
"Add custom token",
style: STextStyles.w600_14(context),
),
],
),
),
),
),
],
),
child: Padding(
padding: const EdgeInsets.all(4),
child: AddTokenListElement(
data: items[index],
),
),
);
},
);
}
}

View file

@ -0,0 +1,94 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:isar/isar.dart';
import 'package:stackwallet/models/ethereum/eth_token.dart';
import 'package:stackwallet/models/isar/exchange_cache/currency.dart';
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/widgets/custom_buttons/draggable_switch_button.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
class AddTokenListElementData {
AddTokenListElementData(this.token);
final EthToken token;
bool selected = false;
}
class AddTokenListElement extends StatefulWidget {
const AddTokenListElement({Key? key, required this.data}) : super(key: key);
final AddTokenListElementData data;
@override
State<AddTokenListElement> createState() => _AddTokenListElementState();
}
class _AddTokenListElementState extends State<AddTokenListElement> {
@override
Widget build(BuildContext context) {
final currency = ExchangeDataLoadingService.instance.isar.currencies
.where()
.tickerExchangeNameEqualToAnyName(
"${widget.data.token.symbol}ERC20",
ChangeNowExchange.exchangeName,
)
.or()
.tickerExchangeNameEqualToAnyName(
widget.data.token.symbol,
ChangeNowExchange.exchangeName,
)
.or()
.tickerExchangeNameEqualToAnyName(
"${widget.data.token.symbol}BSC",
ChangeNowExchange.exchangeName,
)
.filter()
.imageIsNotEmpty()
.findFirstSync();
return RoundedWhiteContainer(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
currency != null
? SvgPicture.network(
currency.image,
width: 24,
height: 24,
)
: Container(
width: 24,
height: 24,
color: Colors.red,
),
const SizedBox(
width: 12,
),
Text(
"${widget.data.token.name} (${widget.data.token.symbol})",
style: STextStyles.w600_14(context),
overflow: TextOverflow.ellipsis,
),
],
),
const SizedBox(
width: 4,
),
SizedBox(
height: 20,
width: 40,
child: DraggableSwitchButton(
isOn: widget.data.selected,
onValueChanged: (newValue) {
widget.data.selected = newValue;
},
),
),
],
),
);
}
}

View file

@ -0,0 +1,49 @@
import 'package:flutter/material.dart';
import 'package:stackwallet/utilities/text_styles.dart';
class AddTokenText extends StatelessWidget {
const AddTokenText({
Key? key,
required this.isDesktop,
required this.walletName,
}) : super(key: key);
final String walletName;
final bool isDesktop;
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
walletName,
textAlign: TextAlign.center,
style: isDesktop
? STextStyles.sectionLabelMedium12(context) // todo: fixme
: STextStyles.sectionLabelMedium12(context),
),
const SizedBox(
height: 4,
),
Text(
"Add Tokens",
textAlign: TextAlign.center,
style: isDesktop
? STextStyles.desktopH2(context)
: STextStyles.pageTitleH1(context),
),
const SizedBox(
height: 8,
),
Text(
"You can also do it later in your wallet",
textAlign: TextAlign.center,
style: isDesktop
? STextStyles.desktopSubtitleH2(context)
: STextStyles.subtitle(context),
),
],
);
}
}

View file

@ -113,6 +113,7 @@ class _VerifyRecoveryPhraseViewState
unawaited(
Navigator.of(context).pushNamed(
AddTokenView.routeName,
arguments: widget.manager.walletId,
),
);
}

View file

@ -148,6 +148,7 @@ class _TokenDetailsViewState extends ConsumerState<MyTokensView> {
onPressed: () {
Navigator.of(context).pushNamed(
AddTokenView.routeName,
arguments: widget.walletId,
);
},
),

View file

@ -205,10 +205,18 @@ class RouteGenerator {
settings: RouteSettings(name: settings.name));
case AddTokenView.routeName:
if (args is String) {
return getRoute(
shouldUseMaterialRoute: useMaterialPageRoute,
builder: (_) => const AddTokenView(),
settings: RouteSettings(name: settings.name));
builder: (_) => AddTokenView(
walletId: args,
),
settings: RouteSettings(
name: settings.name,
),
);
}
return _routeError("${settings.name} invalid args: ${args.toString()}");
case PaynymClaimView.routeName:
if (args is String) {