contact tx history

This commit is contained in:
julian 2022-11-17 16:01:11 -06:00
parent 8799a9cfa2
commit 51c98f90e9
4 changed files with 248 additions and 114 deletions

View file

@ -427,11 +427,8 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> {
),
details: currentContactId == null
? Container()
: RoundedWhiteContainer(
padding: const EdgeInsets.all(24),
child: DesktopContactDetails(
contactId: currentContactId!,
),
: DesktopContactDetails(
contactId: currentContactId!,
),
),
),

View file

@ -56,6 +56,7 @@ class DesktopAddressBookScaffold extends StatelessWidget {
),
Expanded(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: 6,
@ -96,7 +97,7 @@ class DesktopAddressBookScaffold extends StatelessWidget {
const SizedBox(
height: weirdRowHeight,
),
Expanded(
Flexible(
child: details ?? Container(),
),
],

View file

@ -1,8 +1,12 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:stackwallet/models/contact_address_entry.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/clipboard_interface.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/enums/flush_bar_type.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';
@ -12,10 +16,12 @@ class DesktopAddressCard extends StatelessWidget {
Key? key,
required this.entry,
required this.contactId,
this.clipboard = const ClipboardWrapper(),
}) : super(key: key);
final ContactAddressEntry entry;
final String contactId;
final ClipboardInterface clipboard;
@override
Widget build(BuildContext context) {
@ -57,7 +63,17 @@ class DesktopAddressCard extends StatelessWidget {
children: [
BlueTextButton(
text: "Copy",
onTap: () {},
onTap: () {
clipboard.setData(
ClipboardData(text: entry.address),
);
showFloatingFlushBar(
type: FlushBarType.info,
message: "Copied to clipboard",
iconAsset: Assets.svg.copy,
context: context,
);
},
),
if (contactId != "default")
const SizedBox(

View file

@ -1,14 +1,21 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:stackwallet/models/contact.dart';
import 'package:stackwallet/models/paymint/transactions_model.dart';
import 'package:stackwallet/pages_desktop_specific/home/address_book_view/subwidgets/desktop_address_card.dart';
import 'package:stackwallet/providers/global/address_book_service_provider.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/services/coins/manager.dart';
import 'package:stackwallet/utilities/assets.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';
import 'package:stackwallet/widgets/loading_indicator.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/transaction_card.dart';
import 'package:tuple/tuple.dart';
class DesktopContactDetails extends ConsumerStatefulWidget {
const DesktopContactDetails({
@ -24,132 +31,245 @@ class DesktopContactDetails extends ConsumerStatefulWidget {
}
class _DesktopContactDetailsState extends ConsumerState<DesktopContactDetails> {
List<Tuple2<String, Transaction>> _cachedTransactions = [];
bool _contactHasAddress(String address, Contact contact) {
for (final entry in contact.addresses) {
if (entry.address == address) {
return true;
}
}
return false;
}
Future<List<Tuple2<String, Transaction>>> _filteredTransactionsByContact(
List<Manager> managers,
) async {
final contact =
ref.read(addressBookServiceProvider).getContactById(widget.contactId);
// TODO: optimise
List<Tuple2<String, Transaction>> result = [];
for (final manager in managers) {
final transactions = (await manager.transactionData)
.getAllTransactions()
.values
.toList()
.where((e) => _contactHasAddress(e.address, contact));
for (final tx in transactions) {
result.add(Tuple2(manager.walletId, tx));
}
}
// sort by date
result.sort((a, b) => b.item2.timestamp - a.item2.timestamp);
return result;
}
@override
Widget build(BuildContext context) {
final contact = ref.watch(addressBookServiceProvider
.select((value) => value.getContactById(widget.contactId)));
return Column(
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Container(
width: 32,
height: 32,
decoration: BoxDecoration(
color: contact.id == "default"
? Colors.transparent
: Theme.of(context)
.extension<StackColors>()!
.textFieldDefaultBG,
borderRadius: BorderRadius.circular(32),
),
child: contact.id == "default"
? Center(
child: SvgPicture.asset(
Assets.svg.stackIcon(context),
width: 32,
),
)
: 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",
width: 86,
buttonHeight: ButtonHeight.xxs,
onPressed: () {},
),
],
),
const SizedBox(
height: 24,
),
Expanded(
child: LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraints.maxHeight,
),
child: IntrinsicHeight(
child: Column(
child: RoundedWhiteContainer(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Addresses",
style: STextStyles.desktopTextExtraExtraSmall(
context),
),
BlueTextButton(
text: "Add new",
onTap: () {},
),
],
Container(
width: 32,
height: 32,
decoration: BoxDecoration(
color: contact.id == "default"
? Colors.transparent
: Theme.of(context)
.extension<StackColors>()!
.textFieldDefaultBG,
borderRadius: BorderRadius.circular(32),
),
child: contact.id == "default"
? Center(
child: SvgPicture.asset(
Assets.svg.stackIcon(context),
width: 32,
),
)
: contact.emojiChar != null
? Center(
child: Text(contact.emojiChar!),
)
: Center(
child: SvgPicture.asset(
Assets.svg.user,
width: 18,
),
),
),
const SizedBox(
height: 12,
width: 16,
),
RoundedWhiteContainer(
padding: const EdgeInsets.all(0),
borderColor: Theme.of(context)
.extension<StackColors>()!
.background,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
for (int i = 0; i < contact.addresses.length; i++)
Column(
Text(
contact.name,
style: STextStyles.desktopTextSmall(context),
),
],
),
SecondaryButton(
label: "Options",
width: 86,
buttonHeight: ButtonHeight.xxs,
onPressed: () {},
),
],
),
const SizedBox(
height: 24,
),
Flexible(
child: ListView(
primary: false,
shrinkWrap: true,
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Addresses",
style:
STextStyles.desktopTextExtraExtraSmall(context),
),
BlueTextButton(
text: "Add new",
onTap: () {},
),
],
),
const SizedBox(
height: 12,
),
RoundedWhiteContainer(
padding: const EdgeInsets.all(0),
borderColor: Theme.of(context)
.extension<StackColors>()!
.background,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
for (int i = 0; i < contact.addresses.length; i++)
Column(
mainAxisSize: MainAxisSize.min,
children: [
if (i > 0)
Container(
color: Theme.of(context)
.extension<StackColors>()!
.background,
height: 1,
),
Padding(
padding: const EdgeInsets.all(18),
child: DesktopAddressCard(
entry: contact.addresses[i],
contactId: contact.id,
),
),
],
),
],
),
),
Text(
"Transaction history",
style: STextStyles.desktopTextExtraExtraSmall(context),
),
FutureBuilder(
future: _filteredTransactionsByContact(
ref.watch(walletsChangeNotifierProvider).managers),
builder: (_,
AsyncSnapshot<List<Tuple2<String, Transaction>>>
snapshot) {
if (snapshot.connectionState ==
ConnectionState.done &&
snapshot.hasData) {
_cachedTransactions = snapshot.data!;
if (_cachedTransactions.isNotEmpty) {
return RoundedWhiteContainer(
padding: const EdgeInsets.all(0),
borderColor: Theme.of(context)
.extension<StackColors>()!
.background,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (i > 0)
Container(
color: Theme.of(context)
.extension<StackColors>()!
.background,
height: 1,
),
Padding(
padding: const EdgeInsets.all(18),
child: DesktopAddressCard(
entry: contact.addresses[i],
contactId: contact.id,
..._cachedTransactions.map(
(e) => TransactionCard(
key: Key(
"contactDetailsTransaction_${e.item1}_${e.item2.txid}_cardKey"),
transaction: e.item2,
walletId: e.item1,
),
),
],
),
],
),
)
],
),
);
} else {
return RoundedWhiteContainer(
child: Center(
child: Text(
"No transactions found",
style: STextStyles.itemSubtitle(context),
),
),
);
}
} else {
// TODO: proper loading animation
if (_cachedTransactions.isEmpty) {
return const LoadingIndicator();
} else {
return RoundedWhiteContainer(
padding: const EdgeInsets.all(0),
borderColor: Theme.of(context)
.extension<StackColors>()!
.background,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
..._cachedTransactions.map(
(e) => TransactionCard(
key: Key(
"contactDetailsTransaction_${e.item1}_${e.item2.txid}_cardKey"),
transaction: e.item2,
walletId: e.item1,
),
),
],
),
);
}
}
},
),
],
),
),
);
},
],
),
),
),
],