basic add token view with correct navigation

This commit is contained in:
julian 2023-02-28 11:02:38 -06:00
parent f1bfe72b73
commit 6a734e28f0
6 changed files with 334 additions and 315 deletions

View file

@ -0,0 +1,310 @@
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_desktop_specific/my_stack_view/exit_to_my_stack_button.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/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/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/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 AddTokenView extends ConsumerStatefulWidget {
const AddTokenView({
Key? key,
}) : super(key: key);
static const routeName = "/addToken";
@override
ConsumerState<AddTokenView> createState() => _AddTokenViewState();
}
class _AddTokenViewState extends ConsumerState<AddTokenView> {
late final TextEditingController _searchFieldController;
late final FocusNode _searchFocusNode;
String _searchTerm = "";
final List<AddWalletListEntity> tokenEntities = [];
final bool isDesktop = Util.isDesktop;
List<AddWalletListEntity> filter(
String text,
List<AddWalletListEntity> 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)),
);
}
return _entities;
}
@override
void initState() {
_searchFieldController = TextEditingController();
_searchFocusNode = FocusNode();
tokenEntities.addAll(DefaultTokens.list.map((e) => EthTokenEntity(e)));
tokenEntities.sort((a, b) => a.name.compareTo(b.name));
super.initState();
}
@override
void dispose() {
_searchFieldController.dispose();
_searchFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType");
if (isDesktop) {
return DesktopScaffold(
appBar: const DesktopAppBar(
isCompactHeight: false,
leading: AppBarBackButton(),
trailing: ExitToMyStackButton(),
),
body: Column(
children: [
const AddWalletText(
isDesktop: true,
),
const SizedBox(
height: 16,
),
Expanded(
child: SizedBox(
width: 480,
child: RoundedWhiteContainer(
radiusMultiplier: 2,
padding: const EdgeInsets.only(
left: 16,
top: 16,
right: 16,
bottom: 0,
),
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(4.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
child: TextField(
autocorrect: Util.isDesktop ? false : true,
enableSuggestions: Util.isDesktop ? false : true,
controller: _searchFieldController,
focusNode: _searchFocusNode,
onChanged: (value) {
setState(() {
_searchTerm = value;
});
},
style:
STextStyles.desktopTextMedium(context).copyWith(
height: 2,
),
decoration: standardInputDecoration(
"Search",
_searchFocusNode,
context,
).copyWith(
contentPadding: const EdgeInsets.symmetric(
vertical: 10,
),
prefixIcon: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16,
// vertical: 20,
),
child: SvgPicture.asset(
Assets.svg.search,
width: 24,
height: 24,
color: Theme.of(context)
.extension<StackColors>()!
.textFieldDefaultSearchIconLeft,
),
),
suffixIcon: _searchFieldController.text.isNotEmpty
? Padding(
padding: const EdgeInsets.only(right: 10),
child: UnconstrainedBox(
child: Row(
children: [
TextFieldIconButton(
child: const XIcon(
width: 24,
height: 24,
),
onTap: () async {
setState(() {
_searchFieldController.text =
"";
_searchTerm = "";
});
},
),
],
),
),
)
: null,
),
),
),
),
Expanded(
child: AddWalletEntityList(
entities: filter(_searchTerm, tokenEntities),
),
),
],
),
),
),
),
const SizedBox(
height: 16,
),
const SizedBox(
height: 70,
width: 480,
child: AddWalletNextButton(
isDesktop: true,
),
),
const SizedBox(
height: 32,
),
],
),
);
} else {
return Background(
child: Scaffold(
backgroundColor:
Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar(
leading: AppBarBackButton(
onPressed: () {
Navigator.of(context).pop();
},
),
),
body: Container(
color: Theme.of(context).extension<StackColors>()!.background,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const AddWalletText(
isDesktop: false,
),
const SizedBox(
height: 16,
),
ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
child: TextField(
autofocus: isDesktop,
autocorrect: !isDesktop,
enableSuggestions: !isDesktop,
controller: _searchFieldController,
focusNode: _searchFocusNode,
onChanged: (value) => setState(() => _searchTerm = value),
style: STextStyles.field(context),
decoration: standardInputDecoration(
"Search",
_searchFocusNode,
context,
desktopMed: isDesktop,
).copyWith(
prefixIcon: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 16,
),
child: SvgPicture.asset(
Assets.svg.search,
width: 16,
height: 16,
),
),
suffixIcon: _searchFieldController.text.isNotEmpty
? Padding(
padding: const EdgeInsets.only(right: 0),
child: UnconstrainedBox(
child: Row(
children: [
TextFieldIconButton(
child: const XIcon(),
onTap: () async {
setState(() {
_searchFieldController.text = "";
_searchTerm = "";
});
},
),
],
),
),
)
: null,
),
),
),
const SizedBox(
height: 10,
),
Expanded(
child: AddWalletEntityList(
entities: filter(_searchTerm, tokenEntities),
),
),
const SizedBox(
height: 16,
),
const AddWalletNextButton(
isDesktop: false,
),
],
),
),
),
),
);
}
}
}

View file

@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/add_wallet_views/add_token_view/add_token_view.dart';
import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart';
import 'package:stackwallet/pages/add_wallet_views/verify_recovery_phrase_view/sub_widgets/word_table.dart';
import 'package:stackwallet/pages/home_view/home_view.dart';
@ -14,6 +15,7 @@ import 'package:stackwallet/providers/providers.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';
@ -107,6 +109,13 @@ class _VerifyRecoveryPhraseViewState
(route) => false,
),
);
if (widget.manager.coin == Coin.ethereum) {
unawaited(
Navigator.of(context).pushNamed(
AddTokenView.routeName,
),
);
}
}
}

View file

@ -1,16 +0,0 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class AllTokensView extends ConsumerStatefulWidget {
const AllTokensView({
Key? key,
}) : super(key: key);
static const String routeName = "/allTokens";
@override
ConsumerState<ConsumerStatefulWidget> createState() {
// TODO: implement createState
throw UnimplementedError();
}
}

View file

@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/models/ethereum/eth_token.dart';
import 'package:stackwallet/pages/token_view/all_tokens_view.dart';
import 'package:stackwallet/pages/add_wallet_views/add_token_view/add_token_view.dart';
import 'package:stackwallet/pages/token_view/sub_widgets/my_tokens_list.dart';
import 'package:stackwallet/services/coins/manager.dart';
import 'package:stackwallet/utilities/assets.dart';
@ -41,13 +41,11 @@ class MyTokensView extends ConsumerStatefulWidget {
class _TokenDetailsViewState extends ConsumerState<MyTokensView> {
late final String walletAddress;
// late final String walletName;
late final TextEditingController _searchController;
final searchFieldFocusNode = FocusNode();
@override
void initState() {
// walletAddress = widget.walletAddress;
_searchController = TextEditingController();
super.initState();
@ -133,7 +131,7 @@ class _TokenDetailsViewState extends ConsumerState<MyTokensView> {
child: AspectRatio(
aspectRatio: 1,
child: AppBarIconButton(
key: const Key("transactionSearchFilterViewButton"),
key: const Key("addTokenAppBarIconButtonKey"),
size: 36,
shadows: const [],
color: Theme.of(context)
@ -149,7 +147,7 @@ class _TokenDetailsViewState extends ConsumerState<MyTokensView> {
),
onPressed: () {
Navigator.of(context).pushNamed(
AllTokensView.routeName,
AddTokenView.routeName,
);
},
),
@ -258,10 +256,11 @@ class _TokenDetailsViewState extends ConsumerState<MyTokensView> {
),
Expanded(
child: MyTokensList(
managerProvider: widget.managerProvider,
walletId: widget.walletId,
tokens: widget.tokens,
walletAddress: widget.walletAddress),
managerProvider: widget.managerProvider,
walletId: widget.walletId,
tokens: widget.tokens,
walletAddress: widget.walletAddress,
),
),
],
),

View file

@ -1,290 +0,0 @@
import 'package:decimal/decimal.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:stackwallet/pages/wallet_view/sub_widgets/wallet_balance_toggle_sheet.dart';
import 'package:stackwallet/pages/wallet_view/sub_widgets/wallet_refresh_button.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/providers/wallet/wallet_balance_toggle_state_provider.dart';
import 'package:stackwallet/services/coins/manager.dart';
import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/enums/wallet_balance_toggle_state.dart';
import 'package:stackwallet/utilities/format.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/animated_text.dart';
class TokenSummaryInfo extends StatefulWidget {
const TokenSummaryInfo({
Key? key,
required this.walletId,
required this.managerProvider,
required this.initialSyncStatus,
}) : super(key: key);
final String walletId;
final ChangeNotifierProvider<Manager> managerProvider;
final WalletSyncStatus initialSyncStatus;
@override
State<TokenSummaryInfo> createState() => _TokenSummaryInfoState();
}
class _TokenSummaryInfoState extends State<TokenSummaryInfo> {
late final String walletId;
late final ChangeNotifierProvider<Manager> managerProvider;
void showSheet() {
showModalBottomSheet<dynamic>(
backgroundColor: Colors.transparent,
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
),
),
builder: (_) => WalletBalanceToggleSheet(walletId: walletId),
);
}
Decimal? _balanceTotalCached;
Decimal? _balanceCached;
@override
void initState() {
walletId = widget.walletId;
managerProvider = widget.managerProvider;
super.initState();
}
@override
Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType");
return Row(
children: [
Expanded(
child: Consumer(
builder: (_, ref, __) {
final Coin coin =
ref.watch(managerProvider.select((value) => value.coin));
final externalCalls = ref.watch(prefsChangeNotifierProvider
.select((value) => value.externalCalls));
Future<Decimal>? totalBalanceFuture;
Future<Decimal>? availableBalanceFuture;
final manager = ref.watch(walletsChangeNotifierProvider
.select((value) => value.getManager(walletId)));
totalBalanceFuture = Future(() => manager.balance.getTotal());
availableBalanceFuture =
Future(() => manager.balance.getSpendable());
final locale = ref.watch(localeServiceChangeNotifierProvider
.select((value) => value.locale));
final baseCurrency = ref.watch(prefsChangeNotifierProvider
.select((value) => value.currency));
final priceTuple = ref.watch(priceAnd24hChangeNotifierProvider
.select((value) => value.getPrice(coin)));
final _showAvailable =
ref.watch(walletBalanceToggleStateProvider.state).state ==
WalletBalanceToggleState.available;
return FutureBuilder(
future: _showAvailable
? availableBalanceFuture
: totalBalanceFuture,
builder: (fbContext, AsyncSnapshot<Decimal> snapshot) {
if (snapshot.connectionState == ConnectionState.done &&
snapshot.hasData &&
snapshot.data != null) {
if (_showAvailable) {
_balanceCached = snapshot.data!;
} else {
_balanceTotalCached = snapshot.data!;
}
}
Decimal? balanceToShow =
_showAvailable ? _balanceCached : _balanceTotalCached;
if (balanceToShow != null) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
onTap: showSheet,
child: Row(
children: [
if (coin == Coin.firo || coin == Coin.firoTestNet)
Text(
"${_showAvailable ? "Private" : "Public"} Balance",
style:
STextStyles.subtitle500(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFavoriteCard,
),
),
Text(
"${_showAvailable ? "Available" : "Full"} Balance",
style:
STextStyles.subtitle500(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFavoriteCard,
),
),
const SizedBox(
width: 4,
),
SvgPicture.asset(
Assets.svg.chevronDown,
color: Theme.of(context)
.extension<StackColors>()!
.textFavoriteCard,
width: 8,
height: 4,
),
],
),
),
const Spacer(),
FittedBox(
fit: BoxFit.scaleDown,
child: Text(
"${Format.localizedStringAsFixed(
value: balanceToShow,
locale: locale,
decimalPlaces: 8,
)} ${coin.ticker}",
style: STextStyles.pageTitleH1(context).copyWith(
fontSize: 24,
color: Theme.of(context)
.extension<StackColors>()!
.textFavoriteCard,
),
),
),
if (externalCalls)
Text(
"${Format.localizedStringAsFixed(
value: priceTuple.item1 * balanceToShow,
locale: locale,
decimalPlaces: 2,
)} $baseCurrency",
style: STextStyles.subtitle500(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFavoriteCard,
),
),
],
);
} else {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
onTap: showSheet,
child: Row(
children: [
if (coin == Coin.firo || coin == Coin.firoTestNet)
Text(
"${_showAvailable ? "Private" : "Public"} Balance",
style:
STextStyles.subtitle500(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFavoriteCard,
),
),
if (coin != Coin.firo && coin != Coin.firoTestNet)
Text(
"${_showAvailable ? "Available" : "Full"} Balance",
style:
STextStyles.subtitle500(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFavoriteCard,
),
),
const SizedBox(
width: 4,
),
SvgPicture.asset(
Assets.svg.chevronDown,
width: 8,
height: 4,
color: Theme.of(context)
.extension<StackColors>()!
.textFavoriteCard,
),
],
),
),
const Spacer(),
AnimatedText(
stringsToLoopThrough: const [
"Loading balance",
"Loading balance.",
"Loading balance..",
"Loading balance..."
],
style: STextStyles.pageTitleH1(context).copyWith(
fontSize: 24,
color: Theme.of(context)
.extension<StackColors>()!
.textFavoriteCard,
),
),
AnimatedText(
stringsToLoopThrough: const [
"Loading balance",
"Loading balance.",
"Loading balance..",
"Loading balance..."
],
style: STextStyles.subtitle500(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFavoriteCard,
),
),
],
);
}
},
);
},
),
),
Column(
children: [
Consumer(
builder: (_, ref, __) {
return SvgPicture.asset(
Assets.svg.iconFor(
coin: ref.watch(
managerProvider.select((value) => value.coin),
),
),
width: 24,
height: 24,
);
},
),
const Spacer(),
WalletRefreshButton(
walletId: walletId,
initialSyncStatus: widget.initialSyncStatus,
),
],
)
],
);
}
}

View file

@ -12,6 +12,7 @@ import 'package:stackwallet/models/isar/models/blockchain_data/transaction.dart'
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_token_view/add_token_view.dart';
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/add_wallet_view.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';
@ -203,6 +204,12 @@ class RouteGenerator {
builder: (_) => const AddWalletView(),
settings: RouteSettings(name: settings.name));
case AddTokenView.routeName:
return getRoute(
shouldUseMaterialRoute: useMaterialPageRoute,
builder: (_) => const AddTokenView(),
settings: RouteSettings(name: settings.name));
case PaynymClaimView.routeName:
if (args is String) {
return getRoute(