mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-03 17:29:23 +00:00
add search to mobile coin wallets per-coin list
This commit is contained in:
parent
26cfa84da7
commit
742036138b
7 changed files with 441 additions and 465 deletions
|
@ -1,6 +1,14 @@
|
||||||
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: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/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/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';
|
||||||
|
@ -8,18 +16,25 @@ import 'package:stackwallet/utilities/util.dart';
|
||||||
import 'package:stackwallet/widgets/background.dart';
|
import 'package:stackwallet/widgets/background.dart';
|
||||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
import 'package:stackwallet/widgets/conditional_parent.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/icon_widgets/x_icon.dart';
|
||||||
import 'package:stackwallet/widgets/master_wallet_card.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:stackwallet/widgets/wallet_card.dart';
|
||||||
|
import 'package:tuple/tuple.dart';
|
||||||
|
|
||||||
class WalletsOverview extends ConsumerStatefulWidget {
|
class WalletsOverview extends ConsumerStatefulWidget {
|
||||||
const WalletsOverview({
|
const WalletsOverview({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.coin,
|
required this.coin,
|
||||||
|
this.navigatorState,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final Coin coin;
|
final Coin coin;
|
||||||
|
final NavigatorState? navigatorState;
|
||||||
|
|
||||||
static const routeName = "/ethWalletsOverview";
|
static const routeName = "/walletsOverview";
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ConsumerState<WalletsOverview> createState() => _EthWalletsOverviewState();
|
ConsumerState<WalletsOverview> createState() => _EthWalletsOverviewState();
|
||||||
|
@ -28,20 +43,123 @@ class WalletsOverview extends ConsumerStatefulWidget {
|
||||||
class _EthWalletsOverviewState extends ConsumerState<WalletsOverview> {
|
class _EthWalletsOverviewState extends ConsumerState<WalletsOverview> {
|
||||||
final isDesktop = Util.isDesktop;
|
final isDesktop = Util.isDesktop;
|
||||||
|
|
||||||
final List<String> walletIds = [];
|
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
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
_searchController = TextEditingController();
|
||||||
|
searchFieldFocusNode = FocusNode();
|
||||||
|
|
||||||
final walletsData =
|
final walletsData =
|
||||||
ref.read(walletsServiceChangeNotifierProvider).fetchWalletsData();
|
ref.read(walletsServiceChangeNotifierProvider).fetchWalletsData();
|
||||||
walletsData.removeWhere((key, value) => value.coin != widget.coin);
|
walletsData.removeWhere((key, value) => value.coin != widget.coin);
|
||||||
walletIds.clear();
|
|
||||||
|
|
||||||
walletIds.addAll(walletsData.values.map((e) => e.walletId));
|
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();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_searchController.dispose();
|
||||||
|
searchFieldFocusNode.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Background(
|
return Background(
|
||||||
|
@ -64,18 +182,125 @@ class _EthWalletsOverviewState extends ConsumerState<WalletsOverview> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: ListView.separated(
|
child: Column(
|
||||||
itemCount: walletIds.length,
|
children: [
|
||||||
separatorBuilder: (_, __) => const SizedBox(
|
ClipRRect(
|
||||||
height: 8,
|
borderRadius: BorderRadius.circular(
|
||||||
),
|
Constants.size.circularBorderRadius,
|
||||||
itemBuilder: (_, index) => widget.coin == Coin.ethereum
|
),
|
||||||
? MasterWalletCard(
|
child: TextField(
|
||||||
walletId: walletIds[index],
|
autocorrect: !isDesktop,
|
||||||
)
|
enableSuggestions: !isDesktop,
|
||||||
: WalletSheetCard(
|
controller: _searchController,
|
||||||
walletId: walletIds[index],
|
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,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,441 +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,
|
|
||||||
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: 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,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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_future.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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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),
|
||||||
),
|
),
|
||||||
|
|
|
@ -116,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,
|
||||||
),
|
),
|
||||||
|
@ -128,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,
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue