WIP: desktop contact details

This commit is contained in:
julian 2022-11-17 11:10:26 -06:00
parent b6e4357c3c
commit 81d5f757b3
4 changed files with 427 additions and 136 deletions

View file

@ -5,7 +5,11 @@ import 'package:stackwallet/models/contact.dart';
import 'package:stackwallet/models/contact_address_entry.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_desktop_specific/home/address_book_view/subwidgets/desktop_address_book_scaffold.dart';
import 'package:stackwallet/pages_desktop_specific/home/address_book_view/subwidgets/desktop_contact_details.dart';
import 'package:stackwallet/providers/global/address_book_service_provider.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/providers/ui/address_book_providers/address_book_filter_provider.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
@ -19,13 +23,11 @@ import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
import 'package:stackwallet/widgets/icon_widgets/x_icon.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/textfield_icon_button.dart';
import '../../../providers/providers.dart';
import '../../../providers/ui/address_book_providers/address_book_filter_provider.dart';
class DesktopAddressBook extends ConsumerStatefulWidget {
const DesktopAddressBook({Key? key}) : super(key: key);
@ -42,6 +44,8 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> {
String _searchTerm = "";
String? currentContactId;
Future<void> selectCryptocurrency() async {
await showDialog<dynamic>(
context: context,
@ -139,8 +143,9 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> {
.where((e) => ref.watch(addressBookFilterProvider
.select((value) => value.coins.contains(e.coin))))
.isNotEmpty)
.where((e) =>
ref.read(addressBookServiceProvider).matches(_searchTerm, e));
.where(
(e) => ref.read(addressBookServiceProvider).matches(_searchTerm, e))
.toList();
final favorites = contacts
.where((element) => element.addresses
@ -150,7 +155,8 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> {
.where((e) =>
e.isFavorite &&
ref.read(addressBookServiceProvider).matches(_searchTerm, e))
.where((element) => element.isFavorite);
.where((element) => element.isFavorite)
.toList();
return DesktopScaffold(
appBar: DesktopAppBar(
@ -294,12 +300,56 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> {
padding: const EdgeInsets.all(0),
child: Column(
children: [
...favorites.map(
(e) => AddressBookCard(
key: Key("favContactCard_${e.id}_key"),
contactId: e.id,
for (int i = 0; i < favorites.length; i++)
Column(
children: [
if (i > 0)
Container(
color: Theme.of(context)
.extension<StackColors>()!
.background,
height: 1,
),
Padding(
padding: const EdgeInsets.all(4),
child: RoundedContainer(
padding: const EdgeInsets.all(0),
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark
.withOpacity(
currentContactId == favorites[i].id
? 0.08
: 0,
),
child: RawMaterialButton(
onPressed: () {
setState(() {
currentContactId = favorites[i].id;
});
},
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 16,
),
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
child: AddressBookCard(
key: Key(
"favContactCard_${favorites[i].id}_key"),
contactId: favorites[i].id,
desktopSendFrom: false,
),
),
),
),
],
),
),
],
),
),
@ -318,136 +368,70 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> {
children: [
RoundedWhiteContainer(
padding: const EdgeInsets.all(0),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
...allContacts.map(
(e) => AddressBookCard(
key: Key("desktopContactCard_${e.id}_key"),
contactId: e.id,
),
child: Column(
children: [
for (int i = 0; i < allContacts.length; i++)
Column(
children: [
if (i > 0)
Container(
color: Theme.of(context)
.extension<StackColors>()!
.background,
height: 1,
),
Padding(
padding: const EdgeInsets.all(4),
child: RoundedContainer(
padding: const EdgeInsets.all(0),
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark
.withOpacity(
currentContactId == allContacts[i].id
? 0.08
: 0,
),
child: RawMaterialButton(
onPressed: () {
setState(() {
currentContactId = allContacts[i].id;
});
},
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 16,
),
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
child: AddressBookCard(
key: Key(
"favContactCard_${allContacts[i].id}_key"),
contactId: allContacts[i].id,
desktopSendFrom: false,
),
),
),
),
],
),
],
),
],
),
),
],
),
details: Container(
color: Colors.purple,
),
details: currentContactId == null
? Container()
: DesktopContactDetails(
contactId: currentContactId!,
),
),
),
);
}
}
class DesktopAddressBookScaffold extends StatelessWidget {
const DesktopAddressBookScaffold({
Key? key,
required this.controlsLeft,
required this.controlsRight,
required this.filterItems,
required this.upperLabel,
required this.lowerLabel,
required this.favorites,
required this.all,
required this.details,
}) : super(key: key);
final Widget? controlsLeft;
final Widget? controlsRight;
final Widget? filterItems;
final Widget? upperLabel;
final Widget? lowerLabel;
final Widget? favorites;
final Widget? all;
final Widget? details;
static const double weirdRowHeight = 30;
@override
Widget build(BuildContext context) {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Expanded(
flex: 6,
child: controlsLeft ?? Container(),
),
const SizedBox(
width: 20,
),
Expanded(
flex: 5,
child: controlsRight ?? Container(),
),
],
),
const SizedBox(
height: 20,
),
Row(
children: [
Expanded(
child: filterItems ?? Container(),
),
],
),
Expanded(
child: Row(
children: [
Expanded(
flex: 6,
child: LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraints.maxHeight,
),
child: IntrinsicHeight(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: weirdRowHeight,
child: upperLabel,
),
favorites ?? Container(),
lowerLabel ?? Container(),
all ?? Container(),
],
),
),
),
);
},
),
),
const SizedBox(
width: 20,
),
Expanded(
flex: 5,
child: Column(
children: [
const SizedBox(
height: weirdRowHeight,
),
Expanded(
child: details ?? Container(),
),
],
),
),
],
),
)
],
);
}
}

View file

@ -0,0 +1,111 @@
import 'package:flutter/widgets.dart';
class DesktopAddressBookScaffold extends StatelessWidget {
const DesktopAddressBookScaffold({
Key? key,
required this.controlsLeft,
required this.controlsRight,
required this.filterItems,
required this.upperLabel,
required this.lowerLabel,
required this.favorites,
required this.all,
required this.details,
}) : super(key: key);
final Widget? controlsLeft;
final Widget? controlsRight;
final Widget? filterItems;
final Widget? upperLabel;
final Widget? lowerLabel;
final Widget? favorites;
final Widget? all;
final Widget? details;
static const double weirdRowHeight = 30;
@override
Widget build(BuildContext context) {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Expanded(
flex: 6,
child: controlsLeft ?? Container(),
),
const SizedBox(
width: 20,
),
Expanded(
flex: 5,
child: controlsRight ?? Container(),
),
],
),
const SizedBox(
height: 20,
),
Row(
children: [
Expanded(
child: filterItems ?? Container(),
),
],
),
Expanded(
child: Row(
children: [
Expanded(
flex: 6,
child: LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
primary: false,
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraints.maxHeight,
),
child: IntrinsicHeight(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: weirdRowHeight,
child: upperLabel,
),
favorites ?? Container(),
lowerLabel ?? Container(),
all ?? Container(),
],
),
),
),
);
},
),
),
const SizedBox(
width: 20,
),
Expanded(
flex: 5,
child: Column(
children: [
const SizedBox(
height: weirdRowHeight,
),
Expanded(
child: details ?? Container(),
),
],
),
),
],
),
)
],
);
}
}

View file

@ -0,0 +1,191 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:stackwallet/models/contact_address_entry.dart';
import 'package:stackwallet/providers/global/address_book_service_provider.dart';
import 'package:stackwallet/utilities/assets.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/widgets/custom_buttons/blue_text_button.dart';
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
class DesktopContactDetails extends ConsumerStatefulWidget {
const DesktopContactDetails({
Key? key,
required this.contactId,
}) : super(key: key);
final String contactId;
@override
ConsumerState<DesktopContactDetails> createState() =>
_DesktopContactDetailsState();
}
class _DesktopContactDetailsState extends ConsumerState<DesktopContactDetails> {
@override
Widget build(BuildContext context) {
final contact = ref.watch(addressBookServiceProvider
.select((value) => value.getContactById(widget.contactId)));
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Container(
width: 32,
height: 32,
decoration: BoxDecoration(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldDefaultBG,
borderRadius: BorderRadius.circular(32),
),
child: contact.id == "default"
? Center(
child: SvgPicture.asset(
Assets.svg.stackIcon(context),
width: 20,
),
)
: contact.emojiChar != null
? Center(
child: Text(contact.emojiChar!),
)
: Center(
child: SvgPicture.asset(
Assets.svg.user,
width: 18,
),
),
),
const SizedBox(
width: 16,
),
Text(
contact.name,
style: STextStyles.desktopTextSmall(context),
),
],
),
SecondaryButton(
label: "Options",
onPressed: () {},
),
],
),
const SizedBox(
height: 24,
),
Expanded(
child: LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraints.maxHeight,
),
child: IntrinsicHeight(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Addresses",
style: STextStyles.desktopTextExtraExtraSmall(
context),
),
BlueTextButton(
text: "Add new",
onTap: () {},
),
],
),
Column(
mainAxisSize: MainAxisSize.min,
children: [
...contact.addresses
.map((e) => AddressCard(entry: e)),
],
)
],
),
),
),
);
},
),
),
],
);
}
}
class AddressCard extends StatelessWidget {
const AddressCard({
Key? key,
required this.entry,
}) : super(key: key);
final ContactAddressEntry entry;
@override
Widget build(BuildContext context) {
return Row(
children: [
SvgPicture.asset(
Assets.svg.iconFor(
coin: entry.coin,
),
height: 32,
width: 32,
),
const SizedBox(
width: 16,
),
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SelectableText(
"${entry.label} ${entry.coin.ticker}",
style: STextStyles.desktopTextExtraExtraSmall(context).copyWith(
color: Theme.of(context).extension<StackColors>()!.textDark,
),
),
const SizedBox(
height: 2,
),
SelectableText(
entry.address,
style: STextStyles.desktopTextExtraExtraSmall(context),
),
const SizedBox(
height: 8,
),
Row(
children: [
BlueTextButton(
text: "Copy",
onTap: () {},
),
const SizedBox(
width: 16,
),
BlueTextButton(
text: "Edit",
onTap: () {},
),
],
)
],
),
],
);
}
}

View file

@ -18,10 +18,12 @@ class AddressBookCard extends ConsumerStatefulWidget {
Key? key,
required this.contactId,
this.indicatorDown,
this.desktopSendFrom = true,
}) : super(key: key);
final String contactId;
final ExpandableState? indicatorDown;
final bool desktopSendFrom;
@override
ConsumerState<AddressBookCard> createState() => _AddressBookCardState();
@ -30,10 +32,12 @@ class AddressBookCard extends ConsumerStatefulWidget {
class _AddressBookCardState extends ConsumerState<AddressBookCard> {
late final String contactId;
late final bool isDesktop;
late final bool desktopSendFrom;
@override
void initState() {
contactId = widget.contactId;
desktopSendFrom = widget.desktopSendFrom;
isDesktop = Util.isDesktop;
super.initState();
}
@ -107,6 +111,7 @@ class _AddressBookCardState extends ConsumerState<AddressBookCard> {
const SizedBox(
width: 16,
),
if (isDesktop && !desktopSendFrom) const Spacer(),
if (isDesktop)
Text(
coinsString,
@ -129,8 +134,8 @@ class _AddressBookCardState extends ConsumerState<AddressBookCard> {
),
],
),
if (isDesktop) const Spacer(),
if (isDesktop)
if (isDesktop && desktopSendFrom) const Spacer(),
if (isDesktop && desktopSendFrom)
SvgPicture.asset(
widget.indicatorDown == ExpandableState.collapsed
? Assets.svg.chevronDown