From 5bf9adb1a35baed0297c9cc606dd757e92f35db9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Olav?= Date: Thu, 2 Nov 2023 13:57:25 +0100 Subject: [PATCH] flutter: redesign transaction list I'm done now! Not touching this screen for a long while --- lib/pages/tabs/dashboard_tab_page.dart | 189 ++++++++++++++---- packages/sail_ui/assets/svgs/icon_pending.svg | 3 + .../sail_ui/assets/svgs/icon_pending_half.svg | 4 + packages/sail_ui/assets/svgs/icon_success.svg | 5 + packages/sail_ui/lib/style/color.dart | 2 +- packages/sail_ui/lib/style/color_scheme.dart | 1 + .../lib/widgets/core/sail_snackbar.dart | 1 + .../sail_ui/lib/widgets/core/sail_svg.dart | 11 +- .../sail_ui/lib/widgets/core/sail_text.dart | 2 +- 9 files changed, 175 insertions(+), 43 deletions(-) create mode 100644 packages/sail_ui/assets/svgs/icon_pending.svg create mode 100644 packages/sail_ui/assets/svgs/icon_pending_half.svg create mode 100644 packages/sail_ui/assets/svgs/icon_success.svg diff --git a/lib/pages/tabs/dashboard_tab_page.dart b/lib/pages/tabs/dashboard_tab_page.dart index 424b5a51..8e9b3a05 100644 --- a/lib/pages/tabs/dashboard_tab_page.dart +++ b/lib/pages/tabs/dashboard_tab_page.dart @@ -2,11 +2,12 @@ import 'dart:convert'; import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:get_it/get_it.dart'; -import 'package:intl/intl.dart'; import 'package:logger/logger.dart'; import 'package:sail_ui/sail_ui.dart'; import 'package:sail_ui/theme/theme.dart'; +import 'package:sail_ui/widgets/core/sail_snackbar.dart'; import 'package:sail_ui/widgets/core/sail_text.dart'; import 'package:sidesail/providers/balance_provider.dart'; import 'package:sidesail/providers/transactions_provider.dart'; @@ -78,45 +79,17 @@ class DashboardTabPage extends StatelessWidget { titleTrailing: viewModel.transactions.length.toString(), endWidget: SailToggle(label: 'Show raw', value: viewModel.showRaw, onChanged: viewModel.toggleRaw), children: [ - SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: DataTable( - dataRowMaxHeight: viewModel.showRaw ? 350 : null, - columns: [ - if (viewModel.showRaw) DataColumn(label: SailText.primary12('Raw')), - DataColumn(label: SailText.primary12('Category')), - DataColumn(label: SailText.primary12('Amount')), - DataColumn(label: SailText.primary12('Fee')), - DataColumn(label: SailText.primary12('TXID')), - DataColumn(label: SailText.primary12('Time')), - DataColumn(label: SailText.primary12('Address')), - DataColumn(label: SailText.primary12('Label')), - DataColumn(label: SailText.primary12('Account')), - ], - rows: viewModel.transactions.map((tx) { - return DataRow( - cells: [ - if (viewModel.showRaw) - DataCell( - SizedBox( - width: 600, - child: SailText.primary12( - const JsonEncoder.withIndent(' ').convert(jsonDecode(tx.raw)), - ), - ), - ), - DataCell(SailText.primary12(tx.category)), - DataCell(SailText.primary12(tx.amount.toString())), - DataCell(SailText.primary12(tx.fee.toString())), - DataCell(SailText.primary12(tx.txid)), - DataCell(SailText.primary12(DateFormat('HH:mm MMM d').format(tx.time))), - DataCell(SailText.primary12(tx.address)), - DataCell(SailText.primary12(tx.label)), - DataCell(SailText.primary12(tx.account)), - ], - ); - }).toList(), - ), + SailColumn( + spacing: 0, + withDivider: true, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + for (final tx in viewModel.transactions) + TxView( + showRAW: viewModel.showRaw, + tx: tx, + ), + ], ), ], ), @@ -128,6 +101,142 @@ class DashboardTabPage extends StatelessWidget { } } +class TxView extends StatefulWidget { + final bool showRAW; + final Transaction tx; + + const TxView({super.key, required this.showRAW, required this.tx}); + + @override + State createState() => _TxViewState(); +} + +class _TxViewState extends State { + bool expanded = false; + late Map decodedTx; + @override + void initState() { + super.initState(); + decodedTx = jsonDecode(widget.tx.raw); + } + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric( + vertical: SailStyleValues.padding15, + horizontal: SailStyleValues.padding10, + ), + child: SailColumn( + spacing: SailStyleValues.padding8, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SailScaleButton( + onPressed: () { + setState(() { + expanded = !expanded; + }); + }, + child: SingleValueView( + icon: widget.tx.confirmations >= 1 + ? Tooltip( + message: '${widget.tx.confirmations} confirmations', + child: SailSVG.icon(SailSVGAsset.iconConfirmed, width: 13), + ) + : Tooltip( + message: 'Unconfirmed', + child: SailSVG.icon(SailSVGAsset.iconPending, width: 13), + ), + copyable: false, + label: 'label', + value: extractTXTitle(widget.tx), + ), + ), + if (expanded) ExpandedTXView(decodedTX: decodedTx), + ], + ), + ); + } + + String extractTXTitle(Transaction tx) { + String title = '${tx.category} ${tx.amount.toStringAsFixed(8)} SBTC'; + + if (tx.address.isEmpty) { + return '$title in ${tx.txid}'; + } + + if (tx.amount.isNegative || tx.amount == 0) { + return '$title to ${tx.address}'; + } + + return '$title from ${tx.address}'; + } +} + +class ExpandedTXView extends StatelessWidget { + final Map decodedTX; + + const ExpandedTXView({super.key, required this.decodedTX}); + + @override + Widget build(BuildContext context) { + return SailColumn( + spacing: SailStyleValues.padding8, + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: decodedTX.keys.map((key) { + return SingleValueView(label: key, value: decodedTX[key]); + }).toList(), + ); + } +} + +class SingleValueView extends StatelessWidget { + final String label; + final dynamic value; + final Widget? icon; + final bool copyable; + + const SingleValueView({ + super.key, + required this.label, + required this.value, + this.icon, + this.copyable = true, + }); + + @override + Widget build(BuildContext context) { + final theme = SailTheme.of(context); + final messenger = ScaffoldMessenger.of(context); + + return SailRow( + spacing: SailStyleValues.padding8, + children: [ + if (icon != null) + icon! + else + const SizedBox( + width: 13, + ), + SizedBox( + width: 110, + child: SailText.secondary12(label), + ), + SailScaleButton( + onPressed: copyable + ? () { + Clipboard.setData(ClipboardData(text: value.toString())); + showSnackBar(theme, messenger, 'Copied $label'); + } + : null, + child: SailText.primary12(value.toString()), + ), + ], + ); + } +} + class HomePageViewModel extends BaseViewModel { final log = Logger(level: Level.debug); BalanceProvider get _balanceProvider => GetIt.I.get(); diff --git a/packages/sail_ui/assets/svgs/icon_pending.svg b/packages/sail_ui/assets/svgs/icon_pending.svg new file mode 100644 index 00000000..197bfb8d --- /dev/null +++ b/packages/sail_ui/assets/svgs/icon_pending.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/sail_ui/assets/svgs/icon_pending_half.svg b/packages/sail_ui/assets/svgs/icon_pending_half.svg new file mode 100644 index 00000000..b3950d48 --- /dev/null +++ b/packages/sail_ui/assets/svgs/icon_pending_half.svg @@ -0,0 +1,4 @@ + + + + diff --git a/packages/sail_ui/assets/svgs/icon_success.svg b/packages/sail_ui/assets/svgs/icon_success.svg new file mode 100644 index 00000000..02ca2862 --- /dev/null +++ b/packages/sail_ui/assets/svgs/icon_success.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/sail_ui/lib/style/color.dart b/packages/sail_ui/lib/style/color.dart index 34700bdc..1b294195 100644 --- a/packages/sail_ui/lib/style/color.dart +++ b/packages/sail_ui/lib/style/color.dart @@ -78,7 +78,7 @@ class SailColor { shadow: SailColorScheme.greyLight.withOpacity(0.18), text: SailColorScheme.whiteLight, textSecondary: SailColorScheme.darkTextSecondary, - textTertiary: SailColorScheme.greyMiddle, + textTertiary: SailColorScheme.darkTextTertiary, textHint: SailColorScheme.darkTextHint, orange: SailColorScheme.orange, disabledPrimaryButton: SailColorScheme.orange.withOpacity(0.4), diff --git a/packages/sail_ui/lib/style/color_scheme.dart b/packages/sail_ui/lib/style/color_scheme.dart index 8e548cfd..3de3cd65 100644 --- a/packages/sail_ui/lib/style/color_scheme.dart +++ b/packages/sail_ui/lib/style/color_scheme.dart @@ -32,6 +32,7 @@ abstract class SailColorScheme { static const darkDivider = Color(0xff212234); static const darkChip = Color.fromRGBO(124, 124, 164, 0.1); // #7C7CA4 static const darkTextSecondary = Color(0xffD2D3E0); + static const darkTextTertiary = Color(0xff858699); // modal colors static const darkActionModalBackground = Color.fromRGBO(29, 30, 43, 1); static const darkTextHint = Color(0xff4D4F69); diff --git a/packages/sail_ui/lib/widgets/core/sail_snackbar.dart b/packages/sail_ui/lib/widgets/core/sail_snackbar.dart index 14ad5e33..6d6344eb 100644 --- a/packages/sail_ui/lib/widgets/core/sail_snackbar.dart +++ b/packages/sail_ui/lib/widgets/core/sail_snackbar.dart @@ -13,6 +13,7 @@ void showSnackBar( messenger.showSnackBar( SnackBar( + duration: const Duration(seconds: 1), behavior: SnackBarBehavior.fixed, backgroundColor: theme.colors.background, content: SailPadding( diff --git a/packages/sail_ui/lib/widgets/core/sail_svg.dart b/packages/sail_ui/lib/widgets/core/sail_svg.dart index c5537530..77fbbb7c 100644 --- a/packages/sail_ui/lib/widgets/core/sail_svg.dart +++ b/packages/sail_ui/lib/widgets/core/sail_svg.dart @@ -12,7 +12,9 @@ enum SailSVGAsset { iconSidechain, iconCopy, - iconDropdown + iconDropdown, + iconConfirmed, + iconPending } /// If you don't want to overwrite the color of the svg, put it in here! @@ -22,6 +24,8 @@ enum SailSVGAsset { const coloredAssets = [ SailSVGAsset.iconMainchain, SailSVGAsset.iconSidechain, + SailSVGAsset.iconConfirmed, + SailSVGAsset.iconPending, ]; class SailSVG { @@ -78,6 +82,11 @@ extension AsAssetPath on SailSVGAsset { return 'assets/svgs/icon_copy.svg'; case SailSVGAsset.iconDropdown: return 'assets/svgs/icon_dropdown.svg'; + + case SailSVGAsset.iconConfirmed: + return 'assets/svgs/icon_success.svg'; + case SailSVGAsset.iconPending: + return 'assets/svgs/icon_pending.svg'; } } } diff --git a/packages/sail_ui/lib/widgets/core/sail_text.dart b/packages/sail_ui/lib/widgets/core/sail_text.dart index 9b66fcc0..2f6601ee 100644 --- a/packages/sail_ui/lib/widgets/core/sail_text.dart +++ b/packages/sail_ui/lib/widgets/core/sail_text.dart @@ -139,7 +139,7 @@ class SailText { final theme = SailTheme.of(context); return _Text( label: label, - style: SailStyleValues.regular12.copyWith(color: theme.colors.text), + style: SailStyleValues.regular12.copyWith(color: theme.colors.textTertiary), textAlign: textAlign, ); },