From 3b46e53c4f38c4a6896ab82174c95da0fbd0ad9e Mon Sep 17 00:00:00 2001 From: willy Date: Fri, 19 Mar 2021 23:33:05 +0100 Subject: [PATCH 1/6] make text selectable --- lib/widgets/receive_tab.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/widgets/receive_tab.dart b/lib/widgets/receive_tab.dart index 49128c24..ea44c293 100644 --- a/lib/widgets/receive_tab.dart +++ b/lib/widgets/receive_tab.dart @@ -63,7 +63,7 @@ class _ReceiveTabState extends State { color: Theme.of(context).accentColor, child: Padding( padding: const EdgeInsets.all(8.0), - child: Text( + child: SelectableText( widget._unusedAddress, style: TextStyle(color: Colors.white), ), From ee63e37880e4446dcb156a6b7e94ae1049e0965c Mon Sep 17 00:00:00 2001 From: willy Date: Sat, 20 Mar 2021 13:46:34 +0100 Subject: [PATCH 2/6] broadcast needs to be called before popping of the screen --- lib/widgets/send_tab.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/widgets/send_tab.dart b/lib/widgets/send_tab.dart index 720df327..a408dd7a 100644 --- a/lib/widgets/send_tab.dart +++ b/lib/widgets/send_tab.dart @@ -256,10 +256,6 @@ class _SendTabState extends State { "outFees": _txFee + _destroyedChange }); - //pop message - Navigator.of(context).pop(); - //navigate back to tx list - widget.changeIndex(1); //broadcast Provider.of( context, @@ -267,6 +263,10 @@ class _SendTabState extends State { .broadcastTransaction( _buildResult["hex"], _buildResult["id"]); + //pop message + Navigator.of(context).pop(); + //navigate back to tx list + widget.changeIndex(1); } catch (e) { print("error $e"); ScaffoldMessenger.of(context) From e4d081d165ba6ed752978e0038dffc41dc032bc4 Mon Sep 17 00:00:00 2001 From: willy Date: Sat, 20 Mar 2021 16:01:39 +0100 Subject: [PATCH 3/6] prepare transaction details --- lib/main.dart | 4 +++- lib/providers/activewallets.dart | 8 +++++--- lib/screens/transaction_details.dart | 21 +++++++++++++++++++++ lib/widgets/transactions_list.dart | 4 ++++ pubspec.lock | 2 +- 5 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 lib/screens/transaction_details.dart diff --git a/lib/main.dart b/lib/main.dart index b40ebad9..ef8c6d23 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -10,6 +10,7 @@ import 'package:peercoin/providers/activewallets.dart'; import 'package:peercoin/providers/electrumconnection.dart'; import 'package:peercoin/screens/new_wallet.dart'; import 'package:peercoin/screens/qrcodescanner.dart'; +import 'package:peercoin/screens/transaction_details.dart'; import 'package:peercoin/screens/wallet_home.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -76,7 +77,8 @@ class MyApp extends StatelessWidget { WalletListScreen.routeName: (ctx) => WalletListScreen(), WalletHomeScreen.routeName: (ctx) => WalletHomeScreen(), NewWalletScreen.routeName: (ctx) => NewWalletScreen(), - QRScanner.routeName: (ctx) => QRScanner() + QRScanner.routeName: (ctx) => QRScanner(), + TransactionDetails.routeName: (ctx) => TransactionDetails() }, ), ); diff --git a/lib/providers/activewallets.dart b/lib/providers/activewallets.dart index 81c0e96a..2f1ba73a 100644 --- a/lib/providers/activewallets.dart +++ b/lib/providers/activewallets.dart @@ -364,8 +364,7 @@ class ActiveWallets with ChangeNotifier { final intermediate = tx.build(); var number = ((intermediate.txSize) / 1000 * coin.feePerKb) - .toStringAsFixed( - coin.fractions - 1); //yep -1 is a bit of a magic number here... + .toStringAsFixed(coin.fractions); var asDouble = double.parse(number) * 1000000; int requiredFeeInSatoshis = asDouble.toInt(); print("fee $requiredFeeInSatoshis, size: ${intermediate.txSize}"); @@ -376,7 +375,10 @@ class ActiveWallets with ChangeNotifier { //generate new wallet addr await generateUnusedAddress(identifier); return { - "fee": requiredFeeInSatoshis, + "fee": dryRun == false + ? requiredFeeInSatoshis + : requiredFeeInSatoshis + + 0, //TODO 10 bytes added here because tx virtualsize out of bitcoin_flutter varies by 1 byte "hex": _hex, "id": intermediate.getId(), "destroyedChange": _destroyedChange diff --git a/lib/screens/transaction_details.dart b/lib/screens/transaction_details.dart new file mode 100644 index 00000000..d065941b --- /dev/null +++ b/lib/screens/transaction_details.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; +import 'package:peercoin/models/wallettransaction.dart'; + +class TransactionDetails extends StatelessWidget { + static const routeName = "/tx-detail"; + + @override + Widget build(BuildContext context) { + final WalletTransaction tx = ModalRoute.of(context).settings.arguments; + print(tx); + return Scaffold( + appBar: AppBar( + title: Text( + "Transaction details", + )), + body: Column( + children: [], + ), + ); + } +} diff --git a/lib/widgets/transactions_list.dart b/lib/widgets/transactions_list.dart index 6da79901..9c21f1e8 100644 --- a/lib/widgets/transactions_list.dart +++ b/lib/widgets/transactions_list.dart @@ -1,6 +1,7 @@ import "package:flutter/material.dart"; import 'package:peercoin/models/wallettransaction.dart'; import 'package:intl/intl.dart'; +import 'package:peercoin/screens/transaction_details.dart'; import 'package:step_progress_indicator/step_progress_indicator.dart'; class TransactionList extends StatelessWidget { @@ -23,6 +24,9 @@ class TransactionList extends StatelessWidget { return Card( child: ListTile( + onTap: () => Navigator.of(context).pushNamed( + TransactionDetails.routeName, + arguments: _flippedTx[i]), leading: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ diff --git a/pubspec.lock b/pubspec.lock index d211f8d7..7cdec1a7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -49,7 +49,7 @@ packages: name: bip32 url: "https://pub.dartlang.org" source: hosted - version: "1.0.7" + version: "1.0.5" bip39: dependency: "direct main" description: From d2c9cf6b70f3b3c4cfc0f8ead0609140be6aa543 Mon Sep 17 00:00:00 2001 From: willy Date: Sat, 20 Mar 2021 16:08:18 +0100 Subject: [PATCH 4/6] worst commit ever --- lib/providers/activewallets.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/providers/activewallets.dart b/lib/providers/activewallets.dart index 2f1ba73a..76f705ac 100644 --- a/lib/providers/activewallets.dart +++ b/lib/providers/activewallets.dart @@ -378,7 +378,7 @@ class ActiveWallets with ChangeNotifier { "fee": dryRun == false ? requiredFeeInSatoshis : requiredFeeInSatoshis + - 0, //TODO 10 bytes added here because tx virtualsize out of bitcoin_flutter varies by 1 byte + 10, //TODO 10 satoshis added here because tx virtualsize out of bitcoin_flutter varies by 1 byte "hex": _hex, "id": intermediate.getId(), "destroyedChange": _destroyedChange From 6c6953a9ce7e4b542ed2af2ca437e9c9aa51bd41 Mon Sep 17 00:00:00 2001 From: willy Date: Sat, 20 Mar 2021 16:50:20 +0100 Subject: [PATCH 5/6] add tx details screen --- lib/main.dart | 2 +- lib/screens/transaction_details.dart | 66 ++++++++++++++++++++++++++-- lib/widgets/transactions_list.dart | 8 ++-- 3 files changed, 68 insertions(+), 8 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index ef8c6d23..5e8da821 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -62,7 +62,7 @@ class MyApp extends StatelessWidget { ) ], child: MaterialApp( - title: 'Peercoin Testnet Wallet', + title: 'Peercoin', theme: ThemeData( primaryColor: Color.fromRGBO(60, 176, 84, 1), accentColor: Colors.grey, diff --git a/lib/screens/transaction_details.dart b/lib/screens/transaction_details.dart index d065941b..6a73032d 100644 --- a/lib/screens/transaction_details.dart +++ b/lib/screens/transaction_details.dart @@ -1,4 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:peercoin/models/coinwallet.dart'; import 'package:peercoin/models/wallettransaction.dart'; class TransactionDetails extends StatelessWidget { @@ -6,15 +8,71 @@ class TransactionDetails extends StatelessWidget { @override Widget build(BuildContext context) { - final WalletTransaction tx = ModalRoute.of(context).settings.arguments; - print(tx); + final args = ModalRoute.of(context).settings.arguments as List; + final WalletTransaction _tx = args[0]; + final CoinWallet _coinWallet = args[1]; + return Scaffold( appBar: AppBar( title: Text( "Transaction details", )), - body: Column( - children: [], + body: ListView( + padding: EdgeInsets.all(12), + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [Text("Id"), SelectableText(_tx.txid)], + ), + Divider(), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Time"), + SelectableText(_tx.timestamp != null + ? DateFormat().format( + DateTime.fromMillisecondsSinceEpoch(_tx.timestamp * 1000)) + : "unconfirmed") + ], + ), + Divider(), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Value"), + SelectableText((_tx.value / 1000000).toString() + + " " + + _coinWallet.letterCode) + ], + ), + Divider(), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Fee"), + SelectableText( + (_tx.fee / 1000000).toString() + " " + _coinWallet.letterCode) + ], + ), + Divider(), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [Text("Address"), SelectableText(_tx.address)], + ), + Divider(), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [Text("Direction"), SelectableText(_tx.direction)], + ), + Divider(), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Confirmations"), + SelectableText(_tx.confirmations.toString()) + ], + ), + ], ), ); } diff --git a/lib/widgets/transactions_list.dart b/lib/widgets/transactions_list.dart index 9c21f1e8..df9d7782 100644 --- a/lib/widgets/transactions_list.dart +++ b/lib/widgets/transactions_list.dart @@ -24,9 +24,11 @@ class TransactionList extends StatelessWidget { return Card( child: ListTile( - onTap: () => Navigator.of(context).pushNamed( - TransactionDetails.routeName, - arguments: _flippedTx[i]), + onTap: () => Navigator.of(context) + .pushNamed(TransactionDetails.routeName, arguments: [ + _flippedTx[i], + ModalRoute.of(context).settings.arguments + ]), leading: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ From 628671a2bf3fbadacfe49d29f109f268fb52f3fe Mon Sep 17 00:00:00 2001 From: willy Date: Sat, 20 Mar 2021 18:45:03 +0100 Subject: [PATCH 6/6] implement basic transaction details --- lib/models/availablecoins.dart | 6 ++-- lib/models/coin.dart | 2 ++ lib/screens/transaction_details.dart | 54 +++++++++++++++++++++++----- pubspec.lock | 46 ++++++++++++++++++++++-- pubspec.yaml | 1 + 5 files changed, 96 insertions(+), 13 deletions(-) diff --git a/lib/models/availablecoins.dart b/lib/models/availablecoins.dart index 718c4caf..6608b200 100644 --- a/lib/models/availablecoins.dart +++ b/lib/models/availablecoins.dart @@ -19,7 +19,8 @@ class AvailableCoins { wif: 0xb7), fractions: 6, minimumTxValue: 10000, - feePerKb: 0.01), + feePerKb: 0.01, + explorerTxDetailUrl: "https://blockbook.peercoin.net/tx/"), "peercoinTestnet": Coin( name: "peercoinTestnet", displayName: "Peercoin Testnet", @@ -36,7 +37,8 @@ class AvailableCoins { wif: 0xef), fractions: 6, minimumTxValue: 10000, - feePerKb: 0.01) + feePerKb: 0.01, + explorerTxDetailUrl: "https://tblockbook.peercoin.net/tx/"), }; Map get availableCoins { diff --git a/lib/models/coin.dart b/lib/models/coin.dart index addf2035..cfd13867 100644 --- a/lib/models/coin.dart +++ b/lib/models/coin.dart @@ -12,6 +12,7 @@ class Coin { final int fractions; final int minimumTxValue; final double feePerKb; + final String explorerTxDetailUrl; Coin({ @required this.name, @@ -24,5 +25,6 @@ class Coin { @required this.fractions, @required this.minimumTxValue, @required this.feePerKb, + @required this.explorerTxDetailUrl, }); } diff --git a/lib/screens/transaction_details.dart b/lib/screens/transaction_details.dart index 6a73032d..4a672625 100644 --- a/lib/screens/transaction_details.dart +++ b/lib/screens/transaction_details.dart @@ -1,34 +1,46 @@ import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; +import 'package:peercoin/models/availablecoins.dart'; import 'package:peercoin/models/coinwallet.dart'; import 'package:peercoin/models/wallettransaction.dart'; +import 'package:url_launcher/url_launcher.dart'; class TransactionDetails extends StatelessWidget { static const routeName = "/tx-detail"; + void _launchURL(_url) async { + print(_url); + await canLaunch(_url) ? await launch(_url) : throw 'Could not launch $_url'; + } + @override Widget build(BuildContext context) { final args = ModalRoute.of(context).settings.arguments as List; final WalletTransaction _tx = args[0]; final CoinWallet _coinWallet = args[1]; + final String baseUrl = + AvailableCoins().getSpecificCoin(_coinWallet.name).explorerTxDetailUrl; return Scaffold( appBar: AppBar( - title: Text( + title: const Text( "Transaction details", )), body: ListView( - padding: EdgeInsets.all(12), + padding: EdgeInsets.all(20), children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [Text("Id"), SelectableText(_tx.txid)], + children: [ + const Text("Id", style: TextStyle(fontWeight: FontWeight.bold)), + SelectableText(_tx.txid) + ], ), Divider(), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text("Time"), + const Text("Time", style: TextStyle(fontWeight: FontWeight.bold)), SelectableText(_tx.timestamp != null ? DateFormat().format( DateTime.fromMillisecondsSinceEpoch(_tx.timestamp * 1000)) @@ -39,7 +51,10 @@ class TransactionDetails extends StatelessWidget { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text("Value"), + const Text( + "Value", + style: TextStyle(fontWeight: FontWeight.bold), + ), SelectableText((_tx.value / 1000000).toString() + " " + _coinWallet.letterCode) @@ -49,7 +64,7 @@ class TransactionDetails extends StatelessWidget { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text("Fee"), + const Text("Fee", style: TextStyle(fontWeight: FontWeight.bold)), SelectableText( (_tx.fee / 1000000).toString() + " " + _coinWallet.letterCode) ], @@ -57,21 +72,42 @@ class TransactionDetails extends StatelessWidget { Divider(), Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [Text("Address"), SelectableText(_tx.address)], + children: [ + const Text("Address", + style: TextStyle(fontWeight: FontWeight.bold)), + SelectableText(_tx.address) + ], ), Divider(), Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [Text("Direction"), SelectableText(_tx.direction)], + children: [ + const Text("Direction", + style: TextStyle(fontWeight: FontWeight.bold)), + SelectableText(_tx.direction) + ], ), Divider(), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text("Confirmations"), + const Text("Confirmations", + style: TextStyle(fontWeight: FontWeight.bold)), SelectableText(_tx.confirmations.toString()) ], ), + Center( + child: TextButton.icon( + onPressed: () => _launchURL(baseUrl + "${_tx.txid}"), + icon: Icon( + Icons.search, + color: Theme.of(context).primaryColor, + ), + label: Text( + "View in explorer", + style: TextStyle(color: Theme.of(context).primaryColor), + )), + ) ], ), ); diff --git a/pubspec.lock b/pubspec.lock index 7cdec1a7..fecfc962 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -721,6 +721,48 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.2" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" vector_math: dependency: transitive description: @@ -771,5 +813,5 @@ packages: source: hosted version: "2.2.1" sdks: - dart: ">=2.12.0-0.0 <3.0.0" - flutter: ">=1.20.0" + dart: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.22.0" diff --git a/pubspec.yaml b/pubspec.yaml index 58e87bd0..34eb48dc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -39,6 +39,7 @@ dependencies: intl: ^0.17.0 step_progress_indicator: ^0.2.5+8 qr_code_scanner: ^0.3.5 + url_launcher: ^6.0.2 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.0