/* * This file is part of Stack Wallet. * * Copyright (c) 2023 Cypher Stack * All Rights Reserved. * The code is distributed under GPLv3 license, see LICENSE file for details. * Generated by Cypher Stack on 2023-05-26 * */ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import '../../app_config.dart'; import '../../models/isar/models/blockchain_data/address.dart'; import '../../models/isar/models/contact_entry.dart'; import '../../providers/db/main_db_provider.dart'; import '../../providers/global/address_book_service_provider.dart'; import '../../providers/providers.dart'; import '../../providers/ui/address_book_providers/address_book_filter_provider.dart'; import '../../themes/stack_colors.dart'; import '../../utilities/assets.dart'; import '../../utilities/constants.dart'; import '../../utilities/text_styles.dart'; import '../../utilities/util.dart'; import '../../wallets/crypto_currency/crypto_currency.dart'; import '../../wallets/wallet/wallet_mixin_interfaces/spark_interface.dart'; import '../../widgets/address_book_card.dart'; import '../../widgets/background.dart'; import '../../widgets/conditional_parent.dart'; import '../../widgets/custom_buttons/app_bar_icon_button.dart'; import '../../widgets/icon_widgets/x_icon.dart'; import '../../widgets/rounded_white_container.dart'; import '../../widgets/stack_text_field.dart'; import '../../widgets/textfield_icon_button.dart'; import 'subviews/add_address_book_entry_view.dart'; import 'subviews/address_book_filter_view.dart'; class AddressBookView extends ConsumerStatefulWidget { const AddressBookView({ super.key, this.coin, this.filterTerm, }); static const String routeName = "/addressBook"; final CryptoCurrency? coin; final String? filterTerm; @override ConsumerState createState() => _AddressBookViewState(); } class _AddressBookViewState extends ConsumerState { late TextEditingController _searchController; final _searchFocusNode = FocusNode(); String _searchTerm = ""; @override void initState() { _searchController = TextEditingController(); ref.refresh(addressBookFilterProvider); if (widget.coin == null) { final coins = [...AppConfig.coins]; coins.removeWhere( (e) => e is Firo && e.network.isTestNet, ); final bool showTestNet = ref.read(prefsChangeNotifierProvider).showTestNetCoins; if (showTestNet) { ref.read(addressBookFilterProvider).addAll(coins, false); } else { ref.read(addressBookFilterProvider).addAll( coins.where((e) => e.network != CryptoCurrencyNetwork.test), false, ); } } else { ref.read(addressBookFilterProvider).add(widget.coin!, false); } WidgetsBinding.instance.addPostFrameCallback((_) async { final List addresses = []; final wallets = ref.read(pWallets).wallets; for (final wallet in wallets) { final String addressString; if (wallet is SparkInterface) { Address? address = await wallet.getCurrentReceivingSparkAddress(); if (address == null) { address = await wallet.generateNextSparkAddress(); await ref.read(mainDBProvider).updateOrPutAddresses([address]); } addressString = address.value; } else { final address = await wallet.getCurrentReceivingAddress(); addressString = address?.value ?? wallet.info.cachedReceivingAddress; } addresses.add( ContactAddressEntry() ..coinName = wallet.info.coin.identifier ..address = addressString ..label = "Current Receiving" ..other = wallet.info.name, ); } final self = ContactEntry( name: "My ${AppConfig.prefix}", addresses: addresses, isFavorite: true, customId: "default", ); await ref.read(addressBookServiceProvider).editContact(self); }); super.initState(); } @override void dispose() { _searchController.dispose(); _searchFocusNode.dispose(); super.dispose(); } @override Widget build(BuildContext context) { debugPrint("BUILD: $runtimeType"); final contacts = ref.watch(addressBookServiceProvider.select((value) => value.contacts)); final isDesktop = Util.isDesktop; return ConditionalParent( condition: !isDesktop, builder: (child) { return Background( child: Scaffold( backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () { Navigator.of(context).pop(); }, ), title: Text( "Address book", style: STextStyles.navBarTitle(context), ), actions: [ Padding( padding: const EdgeInsets.only( top: 10, bottom: 10, right: 10, ), child: AspectRatio( aspectRatio: 1, child: AppBarIconButton( key: const Key("addressBookFilterViewButton"), size: 36, shadows: const [], color: Theme.of(context) .extension()! .background, icon: SvgPicture.asset( Assets.svg.filter, color: Theme.of(context) .extension()! .accentColorDark, width: 20, height: 20, ), onPressed: () { Navigator.of(context).pushNamed( AddressBookFilterView.routeName, ); }, ), ), ), Padding( padding: const EdgeInsets.only( top: 10, bottom: 10, right: 10, ), child: AspectRatio( aspectRatio: 1, child: AppBarIconButton( key: const Key("addressBookAddNewContactViewButton"), size: 36, shadows: const [], color: Theme.of(context) .extension()! .background, icon: SvgPicture.asset( Assets.svg.plus, color: Theme.of(context) .extension()! .accentColorDark, width: 20, height: 20, ), onPressed: () { Navigator.of(context).pushNamed( AddAddressBookEntryView.routeName, ); }, ), ), ), ], ), body: LayoutBuilder( builder: (builderContext, constraints) { return Padding( padding: const EdgeInsets.only( left: 12, top: 12, right: 12, ), child: SingleChildScrollView( child: ConstrainedBox( constraints: BoxConstraints( minHeight: constraints.maxHeight - 24, ), child: IntrinsicHeight( child: Padding( padding: const EdgeInsets.all(4), child: ConstrainedBox( constraints: BoxConstraints( minHeight: MediaQuery.of(context).size.height - 271, ), child: child, ), ), ), ), ), ); }, ), ), ); }, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ ClipRRect( borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, ), child: !isDesktop ? TextField( autocorrect: Util.isDesktop ? false : true, enableSuggestions: Util.isDesktop ? false : true, controller: _searchController, focusNode: _searchFocusNode, onChanged: (value) { setState(() { _searchTerm = value; }); }, style: STextStyles.field(context), decoration: standardInputDecoration( "Search", _searchFocusNode, context, ).copyWith( prefixIcon: Padding( padding: const EdgeInsets.symmetric( horizontal: 10, vertical: 16, ), child: SvgPicture.asset( Assets.svg.search, width: 16, height: 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 = ""; _searchTerm = ""; }); }, ), ], ), ), ) : null, ), ) : null, ), if (!isDesktop) const SizedBox(height: 16), Text( "Favorites", style: STextStyles.smallMed12(context), ), const SizedBox( height: 12, ), if (contacts.isNotEmpty) RoundedWhiteContainer( padding: EdgeInsets.all(!isDesktop ? 0 : 15), child: Column( children: [ ...contacts .where( (element) => element.addressesSorted .where( (e) => ref.watch( addressBookFilterProvider.select( (value) => value.coins.contains(e.coin), ), ), ) .isNotEmpty, ) .where( (e) => e.isFavorite && ref .read(addressBookServiceProvider) .matches(widget.filterTerm ?? _searchTerm, e), ) .where((element) => element.isFavorite) .map( (e) => AddressBookCard( key: Key("favContactCard_${e.customId}_key"), contactId: e.customId, ), ), ], ), ), if (contacts.isEmpty) RoundedWhiteContainer( child: Center( child: Text( "Your favorite contacts will appear here", style: STextStyles.itemSubtitle(context), ), ), ), const SizedBox( height: 16, ), Text( "All contacts", style: STextStyles.smallMed12(context), ), const SizedBox( height: 12, ), if (contacts.isNotEmpty) Column( children: [ RoundedWhiteContainer( padding: EdgeInsets.all(!isDesktop ? 0 : 15), child: Padding( padding: const EdgeInsets.all(8.0), child: Column( children: [ ...contacts .where( (element) => element.addressesSorted .where( (e) => ref.watch( addressBookFilterProvider.select( (value) => value.coins.contains(e.coin), ), ), ) .isNotEmpty, ) .where( (e) => ref .read(addressBookServiceProvider) .matches(widget.filterTerm ?? _searchTerm, e), ) .map( (e) => AddressBookCard( key: Key("desktopContactCard_${e.customId}_key"), contactId: e.customId, ), ), ], ), ), ), ], ), if (contacts.isEmpty) RoundedWhiteContainer( child: Center( child: Text( "Your contacts will appear here", style: STextStyles.itemSubtitle(context), ), ), ), ], ), ); } }