From c2841de503c5f19fcbea8aecfad051b78aa269d9 Mon Sep 17 00:00:00 2001 From: Tanner Silva Date: Wed, 28 Oct 2020 14:02:43 -0300 Subject: [PATCH 1/6] Added the ability to view BTC and XMR transactions on web-based block explorers. --- .../transaction_details_page.dart | 49 +++++++++++++------ pubspec.lock | 6 +-- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/lib/src/screens/transaction_details/transaction_details_page.dart b/lib/src/screens/transaction_details/transaction_details_page.dart index 7e9896fa2..b7406b41b 100644 --- a/lib/src/screens/transaction_details/transaction_details_page.dart +++ b/lib/src/screens/transaction_details/transaction_details_page.dart @@ -9,6 +9,7 @@ import 'package:cake_wallet/src/widgets/standart_list_row.dart'; import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/utils/date_formatter.dart'; +import 'package:url_launcher/url_launcher.dart'; class TransactionDetailsPage extends BasePage { TransactionDetailsPage(this.transactionInfo) : _items = [] { @@ -26,7 +27,10 @@ class TransactionDetailsPage extends BasePage { title: S.current.transaction_details_height, value: '${tx.height}'), StandartListItem( title: S.current.transaction_details_amount, - value: tx.amountFormatted()) + value: tx.amountFormatted()), + StandartListItem( + title: "View in Block Explorer", + value: "https://localmonero.co/blocks/search/${tx.id}"), ]; // FIXME // if (widget.settingsStore.shouldSaveRecipientAddress && @@ -57,7 +61,10 @@ class TransactionDetailsPage extends BasePage { title: S.current.transaction_details_height, value: '${tx.height}'), StandartListItem( title: S.current.transaction_details_amount, - value: tx.amountFormatted()) + value: tx.amountFormatted()), + StandartListItem( + title: "View in Block Explorer", + value: "https://www.blockchain.com/btc/tx/${tx.id}"), ]; _items.addAll(items); @@ -88,19 +95,31 @@ class TransactionDetailsPage extends BasePage { itemCount: _items.length, itemBuilder: (context, index) { final item = _items[index]; - final isDrawBottom = index == _items.length - 1 ? true : false; - - return GestureDetector( - onTap: () { - Clipboard.setData(ClipboardData(text: item.value)); - showBar(context, - S.of(context).transaction_details_copied(item.title)); - }, - child: StandartListRow( - title: '${item.title}:', - value: item.value, - isDrawBottom: isDrawBottom), - ); + final isFinalBlockExplorerItem = + index == _items.length - 1 ? true : false; + if (isFinalBlockExplorerItem == true) { + return GestureDetector( + onTap: () { + Clipboard.setData(ClipboardData(text: item.value)); + showBar(context, + S.of(context).transaction_details_copied(item.title)); + }, + child: StandartListRow( + title: '${item.title}:', + value: "", + isDrawBottom: isFinalBlockExplorerItem), + ); + } else { + return GestureDetector( + onTap: () { + launch(item.value); + }, + child: StandartListRow( + title: '${item.title}:', + value: item.value, + isDrawBottom: isFinalBlockExplorerItem), + ); + } }), ); } diff --git a/pubspec.lock b/pubspec.lock index ee3933bc8..8dc688fd7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -140,7 +140,7 @@ packages: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "1.10.3" + version: "1.10.4" build_runner_core: dependency: transitive description: @@ -645,7 +645,7 @@ packages: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "1.6.21" + version: "1.6.22" path_provider_linux: dependency: transitive description: @@ -764,7 +764,7 @@ packages: name: quiver url: "https://pub.dartlang.org" source: hosted - version: "2.1.3" + version: "2.1.4+1" rxdart: dependency: "direct main" description: From 630fd4f236f108e8439f14b38ab3fc4f16446095 Mon Sep 17 00:00:00 2001 From: Tanner Silva Date: Sat, 28 Nov 2020 12:42:18 -0600 Subject: [PATCH 2/6] implemented feedback from tester. XMRchain.net is the new monero block explorer of choice. improved human readability and changed order --- .../transaction_details_page.dart | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/src/screens/transaction_details/transaction_details_page.dart b/lib/src/screens/transaction_details/transaction_details_page.dart index ead36edde..ceb4825f2 100644 --- a/lib/src/screens/transaction_details/transaction_details_page.dart +++ b/lib/src/screens/transaction_details/transaction_details_page.dart @@ -15,6 +15,14 @@ import 'package:url_launcher/url_launcher.dart'; import 'package:hive/hive.dart'; +String blockExplorerName(String inputName) { + if (inputName.contains("xmrchain")) { + return "XMRChain.net"; + } else { + return "Blockchain.com"; + } +} + class TransactionDetailsPage extends BasePage { TransactionDetailsPage(this.transactionInfo, bool showRecipientAddress, Box transactionDescriptionBox) @@ -34,10 +42,10 @@ class TransactionDetailsPage extends BasePage { StandartListItem( title: S.current.transaction_details_amount, value: tx.amountFormatted()), + StandartListItem(title: S.current.send_fee, value: tx.feeFormatted()), StandartListItem( title: "View in Block Explorer", - value: "https://localmonero.co/blocks/search/${tx.id}"), - StandartListItem(title: S.current.send_fee, value: tx.feeFormatted()) + value: "https://xmrchain.net/search?value=${tx.id}") ]; if (showRecipientAddress) { @@ -110,7 +118,7 @@ class TransactionDetailsPage extends BasePage { final item = _items[index]; final isFinalBlockExplorerItem = index == _items.length - 1 ? true : false; - if (isFinalBlockExplorerItem == true) { + if (isFinalBlockExplorerItem == false) { return GestureDetector( onTap: () { Clipboard.setData(ClipboardData(text: item.value)); @@ -119,7 +127,7 @@ class TransactionDetailsPage extends BasePage { }, child: StandartListRow( title: '${item.title}:', - value: "", + value: item.value, isDrawBottom: isFinalBlockExplorerItem), ); } else { @@ -129,7 +137,8 @@ class TransactionDetailsPage extends BasePage { }, child: StandartListRow( title: '${item.title}:', - value: item.value, + value: + "View transaction on ${blockExplorerName(item.value)}", isDrawBottom: isFinalBlockExplorerItem), ); } From 20b5951d3811d8674c4e82dfa1b73f9894ee27be Mon Sep 17 00:00:00 2001 From: Tanner Silva Date: Mon, 30 Nov 2020 11:16:14 -0600 Subject: [PATCH 3/6] Block explorer URL is now shown in its raw form in the user interface --- .../transaction_details/transaction_details_page.dart | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/lib/src/screens/transaction_details/transaction_details_page.dart b/lib/src/screens/transaction_details/transaction_details_page.dart index ceb4825f2..8f93365f6 100644 --- a/lib/src/screens/transaction_details/transaction_details_page.dart +++ b/lib/src/screens/transaction_details/transaction_details_page.dart @@ -15,14 +15,6 @@ import 'package:url_launcher/url_launcher.dart'; import 'package:hive/hive.dart'; -String blockExplorerName(String inputName) { - if (inputName.contains("xmrchain")) { - return "XMRChain.net"; - } else { - return "Blockchain.com"; - } -} - class TransactionDetailsPage extends BasePage { TransactionDetailsPage(this.transactionInfo, bool showRecipientAddress, Box transactionDescriptionBox) @@ -137,8 +129,7 @@ class TransactionDetailsPage extends BasePage { }, child: StandartListRow( title: '${item.title}:', - value: - "View transaction on ${blockExplorerName(item.value)}", + value: item.value, isDrawBottom: isFinalBlockExplorerItem), ); } From 558c6fff2251bb6477993d04ef5528064f0d00e8 Mon Sep 17 00:00:00 2001 From: Tanner Silva Date: Mon, 30 Nov 2020 21:52:16 -0600 Subject: [PATCH 4/6] revised bugs in transaction details screen --- .../transaction_details_page.dart | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/lib/src/screens/transaction_details/transaction_details_page.dart b/lib/src/screens/transaction_details/transaction_details_page.dart index 8f93365f6..ec94278ab 100644 --- a/lib/src/screens/transaction_details/transaction_details_page.dart +++ b/lib/src/screens/transaction_details/transaction_details_page.dart @@ -15,6 +15,19 @@ import 'package:url_launcher/url_launcher.dart'; import 'package:hive/hive.dart'; +String stripURLToTXID(String inputString) { + final RegExp txidRegex = new RegExp('[a-z0-9]{64}'); + return txidRegex.allMatches(inputString).first.group(0); +} + +String blockExplorerName(String inputName) { + if (inputName.contains("xmrchain")) { + return "XMRChain.net"; + } else { + return "Blockchain.com"; + } +} + class TransactionDetailsPage extends BasePage { TransactionDetailsPage(this.transactionInfo, bool showRecipientAddress, Box transactionDescriptionBox) @@ -34,12 +47,8 @@ class TransactionDetailsPage extends BasePage { StandartListItem( title: S.current.transaction_details_amount, value: tx.amountFormatted()), - StandartListItem(title: S.current.send_fee, value: tx.feeFormatted()), - StandartListItem( - title: "View in Block Explorer", - value: "https://xmrchain.net/search?value=${tx.id}") + StandartListItem(title: S.current.send_fee, value: tx.feeFormatted()) ]; - if (showRecipientAddress) { final recipientAddress = transactionDescriptionBox.values .firstWhere((val) => val.id == transactionInfo.id, @@ -52,9 +61,11 @@ class TransactionDetailsPage extends BasePage { value: recipientAddress)); } } + items.add(StandartListItem( + title: "View in Block Explorer", + value: "https://xmrchain.net/search?value=${tx.id}")); if (tx.key?.isNotEmpty ?? null) { - // FIXME: add translation items.add(StandartListItem(title: 'Transaction Key', value: tx.key)); } @@ -129,7 +140,8 @@ class TransactionDetailsPage extends BasePage { }, child: StandartListRow( title: '${item.title}:', - value: item.value, + value: + "View transaction on ${blockExplorerName(item.value)}", isDrawBottom: isFinalBlockExplorerItem), ); } From 01df91c946d6de418659ddd4e65bdb20033ba15c Mon Sep 17 00:00:00 2001 From: Tanner Silva Date: Mon, 21 Dec 2020 18:47:26 -0600 Subject: [PATCH 5/6] Changed how the "View in block explorer" cell is placed in the transaction details page --- .../transaction_details_page.dart | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/src/screens/transaction_details/transaction_details_page.dart b/lib/src/screens/transaction_details/transaction_details_page.dart index ec94278ab..12798ed54 100644 --- a/lib/src/screens/transaction_details/transaction_details_page.dart +++ b/lib/src/screens/transaction_details/transaction_details_page.dart @@ -61,15 +61,10 @@ class TransactionDetailsPage extends BasePage { value: recipientAddress)); } } - items.add(StandartListItem( + _items.addAll(items); + _items.add(StandartListItem( title: "View in Block Explorer", value: "https://xmrchain.net/search?value=${tx.id}")); - - if (tx.key?.isNotEmpty ?? null) { - items.add(StandartListItem(title: 'Transaction Key', value: tx.key)); - } - - _items.addAll(items); } if (tx is BitcoinTransactionInfo) { @@ -92,6 +87,9 @@ class TransactionDetailsPage extends BasePage { ]; _items.addAll(items); + _items.add(StandartListItem( + title: "View in Block Explorer", + value: "https://www.blockchain.com/btc/tx/${tx.id}")); } } From 248cb3a0da3c238e3a613b417cf2bd4e137d4594 Mon Sep 17 00:00:00 2001 From: Tanner Silva Date: Wed, 20 Jan 2021 20:01:49 -0600 Subject: [PATCH 6/6] Block explorer row in transaction details is now implemented as an item subclass rather than being index dependent in the list --- .../blockexplorer_list_item.dart | 8 +++ .../transaction_details_page.dart | 56 ++++++------------- .../transaction_details_view_model.dart | 22 +++++--- 3 files changed, 41 insertions(+), 45 deletions(-) create mode 100644 lib/src/screens/transaction_details/blockexplorer_list_item.dart diff --git a/lib/src/screens/transaction_details/blockexplorer_list_item.dart b/lib/src/screens/transaction_details/blockexplorer_list_item.dart new file mode 100644 index 000000000..4b24e8f1a --- /dev/null +++ b/lib/src/screens/transaction_details/blockexplorer_list_item.dart @@ -0,0 +1,8 @@ +import 'package:flutter/material.dart'; +import 'package:cake_wallet/src/screens/transaction_details/transaction_details_list_item.dart'; + +class BlockExplorerListItem extends TransactionDetailsListItem { + BlockExplorerListItem({String title, String value, this.onTap}) + : super(title: title, value: value); + final Function() onTap; +} diff --git a/lib/src/screens/transaction_details/transaction_details_page.dart b/lib/src/screens/transaction_details/transaction_details_page.dart index ed89d0456..5732856b9 100644 --- a/lib/src/screens/transaction_details/transaction_details_page.dart +++ b/lib/src/screens/transaction_details/transaction_details_page.dart @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/widgets/standart_list_row.dart'; +import 'package:cake_wallet/src/screens/transaction_details/blockexplorer_list_item.dart'; import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/utils/date_formatter.dart'; @@ -15,19 +16,6 @@ import 'package:url_launcher/url_launcher.dart'; import 'package:hive/hive.dart'; -String stripURLToTXID(String inputString) { - final RegExp txidRegex = new RegExp('[a-z0-9]{64}'); - return txidRegex.allMatches(inputString).first.group(0); -} - -String blockExplorerName(String inputName) { - if (inputName.contains("xmrchain")) { - return "XMRChain.net"; - } else { - return "Blockchain.com"; - } -} - class TransactionDetailsPage extends BasePage { TransactionDetailsPage({this.transactionDetailsViewModel}); @@ -45,31 +33,23 @@ class TransactionDetailsPage extends BasePage { final item = transactionDetailsViewModel.items[index]; if (item is StandartListItem) { - final isFinalBlockExplorerItem = - index == transactionDetailsViewModel.items.length - 1 - ? true - : false; - if (isFinalBlockExplorerItem == false) { - return GestureDetector( - onTap: () { - Clipboard.setData(ClipboardData(text: item.value)); - showBar(context, - S.of(context).transaction_details_copied(item.title)); - }, - child: - StandartListRow(title: '${item.title}:', value: item.value), - ); - } else { - return GestureDetector( - onTap: () { - launch(item.value); - }, - child: StandartListRow( - title: '${item.title}:', - value: - "View transaction on ${blockExplorerName(item.value)}"), - ); - } + return GestureDetector( + onTap: () { + Clipboard.setData(ClipboardData(text: item.value)); + showBar(context, + S.of(context).transaction_details_copied(item.title)); + }, + child: + StandartListRow(title: '${item.title}:', value: item.value), + ); + } + + if (item is BlockExplorerListItem) { + return GestureDetector( + onTap: item.onTap, + child: + StandartListRow(title: '${item.title}:', value: item.value), + ); } if (item is TextFieldListItem) { diff --git a/lib/view_model/transaction_details_view_model.dart b/lib/view_model/transaction_details_view_model.dart index f0535994b..67822e207 100644 --- a/lib/view_model/transaction_details_view_model.dart +++ b/lib/view_model/transaction_details_view_model.dart @@ -4,12 +4,14 @@ import 'package:cake_wallet/monero/monero_transaction_info.dart'; import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart'; import 'package:cake_wallet/src/screens/transaction_details/textfield_list_item.dart'; import 'package:cake_wallet/src/screens/transaction_details/transaction_details_list_item.dart'; +import 'package:cake_wallet/src/screens/transaction_details/blockexplorer_list_item.dart'; import 'package:cake_wallet/utils/date_formatter.dart'; import 'package:cake_wallet/entities/transaction_description.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/generated/i18n.dart'; +import 'package:url_launcher/url_launcher.dart'; part 'transaction_details_view_model.g.dart'; @@ -41,6 +43,12 @@ abstract class TransactionDetailsViewModelBase with Store { value: tx.amountFormatted()), StandartListItem( title: S.current.transaction_details_fee, value: tx.feeFormatted()), + BlockExplorerListItem( + title: "View in Block Explorer", + value: "View Transaction on XMRChain.net", + onTap: () { + launch("https://xmrchain.net/search?value=${tx.id}"); + }) ]; if (tx.key?.isNotEmpty ?? null) { @@ -49,9 +57,6 @@ abstract class TransactionDetailsViewModelBase with Store { } items.addAll(_items); - items.add(StandartListItem( - title: "View in Block Explorer", - value: "https://xmrchain.net/search?value=${tx.id}")); } if (tx is BitcoinTransactionInfo) { @@ -72,13 +77,16 @@ abstract class TransactionDetailsViewModelBase with Store { if (tx.feeFormatted()?.isNotEmpty) StandartListItem( title: S.current.transaction_details_fee, - value: tx.feeFormatted()) + value: tx.feeFormatted()), + BlockExplorerListItem( + title: "View in Block Explorer", + value: "View Transaction on Blockchain.com", + onTap: () { + launch("https://www.blockchain.com/btc/tx/${tx.id}"); + }) ]; items.addAll(_items); - items.add(StandartListItem( - title: "View in Block Explorer", - value: "https://www.blockchain.com/btc/tx/${tx.id}")); } if (showRecipientAddress) {