WIP: desktop address book displays contacts

This commit is contained in:
ryleedavis 2022-11-14 16:00:09 -07:00
parent a5af60535e
commit e0555f53a4
2 changed files with 288 additions and 296 deletions

View file

@ -13,7 +13,9 @@ 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';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/address_book_card.dart'; import 'package:stackwallet/widgets/address_book_card.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/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/loading_indicator.dart'; import 'package:stackwallet/widgets/loading_indicator.dart';
@ -21,8 +23,6 @@ import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/stack_text_field.dart'; import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart'; import 'package:stackwallet/widgets/textfield_icon_button.dart';
import 'package:stackwallet/utilities/util.dart';
class AddressBookView extends ConsumerStatefulWidget { class AddressBookView extends ConsumerStatefulWidget {
const AddressBookView({Key? key, this.coin}) : super(key: key); const AddressBookView({Key? key, this.coin}) : super(key: key);
@ -103,288 +103,287 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
final addressBookEntriesFuture = ref.watch( final addressBookEntriesFuture = ref.watch(
addressBookServiceProvider.select((value) => value.addressBookEntries)); addressBookServiceProvider.select((value) => value.addressBookEntries));
return Scaffold( final isDesktop = Util.isDesktop;
backgroundColor: Theme.of(context).extension<StackColors>()!.background, return ConditionalParent(
appBar: AppBar( condition: !isDesktop,
leading: AppBarBackButton( builder: (child) {
onPressed: () { return Scaffold(
Navigator.of(context).pop(); backgroundColor:
}, Theme.of(context).extension<StackColors>()!.background,
), appBar: AppBar(
title: Text( leading: AppBarBackButton(
"Address book", onPressed: () {
style: STextStyles.navBarTitle(context), Navigator.of(context).pop();
), },
actions: [
Padding(
padding: const EdgeInsets.only(
top: 10,
bottom: 10,
right: 10,
), ),
child: AspectRatio( title: Text(
aspectRatio: 1, "Address book",
child: AppBarIconButton( style: STextStyles.navBarTitle(context),
key: const Key("addressBookFilterViewButton"), ),
size: 36, actions: [
shadows: const [], Padding(
color: Theme.of(context).extension<StackColors>()!.background, padding: const EdgeInsets.only(
icon: SvgPicture.asset( top: 10,
Assets.svg.filter, bottom: 10,
color: Theme.of(context) right: 10,
.extension<StackColors>()!
.accentColorDark,
width: 20,
height: 20,
), ),
onPressed: () { child: AspectRatio(
Navigator.of(context).pushNamed( aspectRatio: 1,
AddressBookFilterView.routeName, child: AppBarIconButton(
); key: const Key("addressBookFilterViewButton"),
}, size: 36,
), shadows: const [],
), color:
), Theme.of(context).extension<StackColors>()!.background,
Padding( icon: SvgPicture.asset(
padding: const EdgeInsets.only( Assets.svg.filter,
top: 10, color: Theme.of(context)
bottom: 10, .extension<StackColors>()!
right: 10, .accentColorDark,
), width: 20,
child: AspectRatio( height: 20,
aspectRatio: 1,
child: AppBarIconButton(
key: const Key("addressBookAddNewContactViewButton"),
size: 36,
shadows: const [],
color: Theme.of(context).extension<StackColors>()!.background,
icon: SvgPicture.asset(
Assets.svg.plus,
color: Theme.of(context)
.extension<StackColors>()!
.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: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
child: 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 = "";
});
},
),
],
),
),
)
: null,
),
),
),
const SizedBox(
height: 16,
),
Text(
"Favorites",
style: STextStyles.smallMed12(context),
),
const SizedBox(
height: 12,
),
FutureBuilder(
future: addressBookEntriesFuture,
builder: (_, AsyncSnapshot<List<Contact>> snapshot) {
if (snapshot.connectionState ==
ConnectionState.done &&
snapshot.hasData) {
_cacheFav = snapshot.data!;
}
if (_cacheFav == null) {
// TODO proper loading animation
return const LoadingIndicator();
} else {
if (_cacheFav!.isNotEmpty) {
return RoundedWhiteContainer(
padding: const EdgeInsets.all(0),
child: Column(
children: [
..._cacheFav!
.where((element) => element.addresses
.where((e) => ref.watch(
addressBookFilterProvider
.select((value) => value
.coins
.contains(e.coin))))
.isNotEmpty)
.where((e) =>
e.isFavorite &&
ref
.read(
addressBookServiceProvider)
.matches(_searchTerm, e))
.where(
(element) => element.isFavorite)
.map(
(e) => AddressBookCard(
key: Key(
"favContactCard_${e.id}_key"),
contactId: e.id,
),
),
],
),
);
} else {
return 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,
),
FutureBuilder(
future: addressBookEntriesFuture,
builder: (_, AsyncSnapshot<List<Contact>> snapshot) {
if (snapshot.connectionState ==
ConnectionState.done &&
snapshot.hasData) {
_cache = snapshot.data!;
}
if (_cache == null) {
// TODO proper loading animation
return const LoadingIndicator();
} else {
if (_cache!.isNotEmpty) {
return RoundedWhiteContainer(
padding: const EdgeInsets.all(0),
child: Column(
children: [
..._cache!
.where((element) => element.addresses
.where((e) => ref.watch(
addressBookFilterProvider
.select((value) => value
.coins
.contains(e.coin))))
.isNotEmpty)
.where((e) => ref
.read(addressBookServiceProvider)
.matches(_searchTerm, e))
.where(
(element) => !element.isFavorite)
.map(
(e) => AddressBookCard(
key: Key(
"contactCard_${e.id}_key"),
contactId: e.id,
),
),
],
),
);
} else {
return RoundedWhiteContainer(
child: Center(
child: Text(
"Your contacts will appear here",
style: STextStyles.itemSubtitle(context),
),
),
);
}
}
},
),
],
), ),
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<StackColors>()!.background,
icon: SvgPicture.asset(
Assets.svg.plus,
color: Theme.of(context)
.extension<StackColors>()!
.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: 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 = "";
});
},
),
],
),
),
)
: null,
),
)
: null,
),
if (!isDesktop) const SizedBox(height: 16),
Text(
"Favorites",
style: STextStyles.smallMed12(context),
),
const SizedBox(
height: 12,
),
FutureBuilder(
future: addressBookEntriesFuture,
builder: (_, AsyncSnapshot<List<Contact>> snapshot) {
if (snapshot.connectionState == ConnectionState.done &&
snapshot.hasData) {
_cacheFav = snapshot.data!;
}
if (_cacheFav == null) {
// TODO proper loading animation
return const LoadingIndicator();
} else {
if (_cacheFav!.isNotEmpty) {
return RoundedWhiteContainer(
padding: EdgeInsets.all(!isDesktop ? 0 : 15),
child: Column(
children: [
..._cacheFav!
.where((element) => element.addresses
.where((e) => ref.watch(
addressBookFilterProvider.select((value) =>
value.coins.contains(e.coin))))
.isNotEmpty)
.where((e) =>
e.isFavorite &&
ref
.read(addressBookServiceProvider)
.matches(_searchTerm, e))
.where((element) => element.isFavorite)
.map(
(e) => AddressBookCard(
key: Key("favContactCard_${e.id}_key"),
contactId: e.id,
),
),
],
),
);
} else {
return 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,
),
FutureBuilder(
future: addressBookEntriesFuture,
builder: (_, AsyncSnapshot<List<Contact>> snapshot) {
if (snapshot.connectionState == ConnectionState.done &&
snapshot.hasData) {
_cache = snapshot.data!;
}
if (_cache == null) {
// TODO proper loading animation
return const LoadingIndicator();
} else {
if (_cache!.isNotEmpty) {
return RoundedWhiteContainer(
padding: EdgeInsets.all(!isDesktop ? 0 : 15),
child: Column(
children: [
..._cache!
.where((element) => element.addresses
.where((e) => ref.watch(
addressBookFilterProvider.select((value) =>
value.coins.contains(e.coin))))
.isNotEmpty)
.where((e) => ref
.read(addressBookServiceProvider)
.matches(_searchTerm, e))
.where((element) => !element.isFavorite)
.map(
(e) => AddressBookCard(
key: Key("desktopContactCard_${e.id}_key"),
contactId: e.id,
),
),
],
),
);
} else {
return RoundedWhiteContainer(
child: Center(
child: Text(
"Your contacts will appear here",
style: STextStyles.itemSubtitle(context),
),
),
);
}
}
},
),
],
), ),
); );
} }

View file

@ -2,6 +2,7 @@ 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/models/contact.dart'; import 'package:stackwallet/models/contact.dart';
import 'package:stackwallet/pages/address_book_views/address_book_view.dart';
import 'package:stackwallet/pages/address_book_views/subviews/add_address_book_entry_view.dart'; import 'package:stackwallet/pages/address_book_views/subviews/add_address_book_entry_view.dart';
import 'package:stackwallet/pages/address_book_views/subviews/address_book_filter_view.dart'; import 'package:stackwallet/pages/address_book_views/subviews/address_book_filter_view.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart';
@ -9,11 +10,11 @@ import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.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';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart'; import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart'; import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/rounded_container.dart'; import 'package:stackwallet/widgets/rounded_container.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/stack_text_field.dart'; import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart'; import 'package:stackwallet/widgets/textfield_icon_button.dart';
@ -36,7 +37,7 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> {
late bool hasContacts = false; late bool hasContacts = false;
String filter = ""; String _searchTerm = "";
Future<void> selectCryptocurrency() async { Future<void> selectCryptocurrency() async {
await showDialog<dynamic>( await showDialog<dynamic>(
@ -123,25 +124,25 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> {
Constants.size.circularBorderRadius, Constants.size.circularBorderRadius,
), ),
child: TextField( child: TextField(
autocorrect: false, autocorrect: Util.isDesktop ? false : true,
enableSuggestions: false, enableSuggestions: Util.isDesktop ? false : true,
controller: _searchController, controller: _searchController,
focusNode: _searchFocusNode, focusNode: _searchFocusNode,
onChanged: (newString) { onChanged: (value) {
setState(() => filter = newString); setState(() {
_searchTerm = value;
});
}, },
style: STextStyles.field(context), style: STextStyles.field(context),
decoration: standardInputDecoration( decoration: standardInputDecoration(
"Search...", "Search",
_searchFocusNode, _searchFocusNode,
context, context,
).copyWith( ).copyWith(
labelStyle: STextStyles.fieldLabel(context)
.copyWith(fontSize: 16),
prefixIcon: Padding( prefixIcon: Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 10, horizontal: 10,
vertical: 16, vertical: 20,
), ),
child: SvgPicture.asset( child: SvgPicture.asset(
Assets.svg.search, Assets.svg.search,
@ -160,7 +161,6 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> {
onTap: () async { onTap: () async {
setState(() { setState(() {
_searchController.text = ""; _searchController.text = "";
filter = "";
}); });
}, },
), ),
@ -243,14 +243,7 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> {
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 26), padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 26),
child: SizedBox( child: SizedBox(
width: 489, width: 489,
child: RoundedWhiteContainer( child: AddressBookView(),
child: Center(
child: Text(
"Your contacts will appear here",
style: STextStyles.itemSubtitle(context),
),
),
),
), ),
), ),
], ],