From a820533615a764e2e6374a449509306cfc456ecb Mon Sep 17 00:00:00 2001 From: Willy Date: Sat, 20 Apr 2024 17:29:37 +0200 Subject: [PATCH 01/22] version bump --- CHANGELOG.md | 4 ++++ pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a15d87be..670f0827 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +### **1.2.7** (2023-05-xx) + +- + ### **1.2.6** (2023-04-20) - Improved transaction signing handling and error messages diff --git a/pubspec.yaml b/pubspec.yaml index 0805314e..0e12b22c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: peercoin description: A new Peercoin wallet. -version: 1.2.6+138 +version: 1.2.7+139 environment: sdk: '>=3.2.0 <4.0.0' From 23d40a66f70c54a84181869fe23734e8da14e465 Mon Sep 17 00:00:00 2001 From: Willy Date: Sat, 20 Apr 2024 17:29:37 +0200 Subject: [PATCH 02/22] version bump --- CHANGELOG.md | 4 ++++ pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a15d87be..670f0827 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +### **1.2.7** (2023-05-xx) + +- + ### **1.2.6** (2023-04-20) - Improved transaction signing handling and error messages diff --git a/pubspec.yaml b/pubspec.yaml index b20f9ed3..6a9672e9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: peercoin description: A new Peercoin wallet. -version: 1.2.6+139 +version: 1.2.6+140 environment: sdk: '>=3.2.0 <4.0.0' From 428eb52a3ec4e2cc2e1153b5a3d8916506e9b71d Mon Sep 17 00:00:00 2001 From: Willy Date: Sun, 21 Apr 2024 10:24:26 +0200 Subject: [PATCH 03/22] Bump version to 1.2.7+140 in pubspec.yaml --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 6a9672e9..1629543b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: peercoin description: A new Peercoin wallet. -version: 1.2.6+140 +version: 1.2.7+140 environment: sdk: '>=3.2.0 <4.0.0' From 8a0bef241803bbdf82b1fd69e4fcd7c3f4e49348 Mon Sep 17 00:00:00 2001 From: Willy Date: Sat, 20 Apr 2024 17:29:37 +0200 Subject: [PATCH 04/22] version bump --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 6a9672e9..1629543b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: peercoin description: A new Peercoin wallet. -version: 1.2.6+140 +version: 1.2.7+140 environment: sdk: '>=3.2.0 <4.0.0' From 33aa4ed3b8b6100ebc5006a85487a5b0703efd77 Mon Sep 17 00:00:00 2001 From: Willy Date: Thu, 16 May 2024 17:23:21 +0200 Subject: [PATCH 05/22] chore: Update color scheme in various screens --- .../settings/app_settings_default_wallet.dart | 6 +- lib/screens/setup/setup_auth.dart | 2 +- lib/screens/setup/setup_create_wallet.dart | 2 +- lib/screens/setup/setup_import_seed.dart | 4 +- lib/screens/setup/setup_landing.dart | 4 +- lib/screens/wallet/address_selector.dart | 6 +- lib/screens/wallet/wallet_home.dart | 2 +- lib/screens/wallet/wallet_list.dart | 8 +- lib/tools/app_themes.dart | 48 ++- lib/widgets/buttons.dart | 8 +- lib/widgets/loading_indicator.dart | 2 +- lib/widgets/service_container.dart | 4 +- .../addresses_tab_expandable.dart | 27 -- .../addresses_tab_watch_only.dart | 6 +- lib/widgets/wallet/addresses_tab.dart | 300 +++++++++--------- lib/widgets/wallet/transactions_list.dart | 8 +- .../wallet/wallet_home_connection.dart | 4 +- pubspec.lock | 48 +-- pubspec.yaml | 8 +- 19 files changed, 241 insertions(+), 256 deletions(-) diff --git a/lib/screens/settings/app_settings_default_wallet.dart b/lib/screens/settings/app_settings_default_wallet.dart index 2d6f3d0a..fe0c4576 100644 --- a/lib/screens/settings/app_settings_default_wallet.dart +++ b/lib/screens/settings/app_settings_default_wallet.dart @@ -50,13 +50,13 @@ class _AppSettingsDefaultWalletScreenState List generateDefaultWallets() { final inkwells = _availableWallets.map((wallet) { return InkWell( - onTap: () => saveDefaultWallet(wallet.letterCode), + onTap: () => saveDefaultWallet(wallet.name), child: ListTile( title: Text(wallet.title), leading: Radio( - value: wallet.letterCode, + value: wallet.name, groupValue: _defaultWallet, - onChanged: (dynamic _) => saveDefaultWallet(wallet.letterCode), + onChanged: (dynamic _) => saveDefaultWallet(wallet.name), ), ), ); diff --git a/lib/screens/setup/setup_auth.dart b/lib/screens/setup/setup_auth.dart index 31448b72..2c8934aa 100644 --- a/lib/screens/setup/setup_auth.dart +++ b/lib/screens/setup/setup_auth.dart @@ -116,7 +116,7 @@ class _SetupAuthScreenState extends State { ), value: _biometricsAllowed, activeColor: - Theme.of(context).colorScheme.background, + Theme.of(context).colorScheme.surface, inactiveThumbColor: Colors.grey, onChanged: (newState) { if (_biometricsAvailable == false) { diff --git a/lib/screens/setup/setup_create_wallet.dart b/lib/screens/setup/setup_create_wallet.dart index 43f64c91..1f6aca73 100644 --- a/lib/screens/setup/setup_create_wallet.dart +++ b/lib/screens/setup/setup_create_wallet.dart @@ -306,7 +306,7 @@ class _SetupCreateWalletScreenState extends State { ), color: Theme.of(context) .colorScheme - .background, + .surface, border: Border.all( width: 2, color: _sharedYet diff --git a/lib/screens/setup/setup_import_seed.dart b/lib/screens/setup/setup_import_seed.dart index 839a79b9..f3b63aa9 100644 --- a/lib/screens/setup/setup_import_seed.dart +++ b/lib/screens/setup/setup_import_seed.dart @@ -176,7 +176,7 @@ class _SetupImportSeedState extends State { borderRadius: const BorderRadius.all( Radius.circular(20), ), - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.surface, border: Border.all( width: 2, color: Theme.of(context).primaryColor, @@ -223,7 +223,7 @@ class _SetupImportSeedState extends State { filled: true, fillColor: Theme.of(context) .colorScheme - .background, + .surface, suffixIcon: IconButton( onPressed: () async { final focusScope = diff --git a/lib/screens/setup/setup_landing.dart b/lib/screens/setup/setup_landing.dart index bd542618..9aa1f4cf 100644 --- a/lib/screens/setup/setup_landing.dart +++ b/lib/screens/setup/setup_landing.dart @@ -57,7 +57,7 @@ class _SetupLandingScreenState extends State { height: MediaQuery.of(context).size.height / 20, ), Image.asset( - 'assets/icon/ppc-icon-white.png', + 'assets/icon/ppc-icon-white-256.png', height: MediaQuery.of(context).size.height / 5, ), Column( @@ -135,7 +135,7 @@ class _SetupLandingScreenState extends State { }, icon: Icon( Icons.language_rounded, - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.surface, size: 32, ), ), diff --git a/lib/screens/wallet/address_selector.dart b/lib/screens/wallet/address_selector.dart index 84dac5a3..605810ac 100644 --- a/lib/screens/wallet/address_selector.dart +++ b/lib/screens/wallet/address_selector.dart @@ -140,7 +140,7 @@ class _AddressSelectorScreenState extends State { child: TextFormField( autofocus: true, style: TextStyle( - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.surface, ), key: const Key('selectorSearchKey'), textInputAction: TextInputAction.done, @@ -149,7 +149,7 @@ class _AddressSelectorScreenState extends State { hintText: AppLocalizations.instance .translate('addressbook_search'), hintStyle: TextStyle( - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.surface, ), suffixIcon: IconButton( onPressed: () => setState(() { @@ -157,7 +157,7 @@ class _AddressSelectorScreenState extends State { }), icon: Icon( Icons.close, - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.surface, ), ), ), diff --git a/lib/screens/wallet/wallet_home.dart b/lib/screens/wallet/wallet_home.dart index 003a86d2..52d399d8 100644 --- a/lib/screens/wallet/wallet_home.dart +++ b/lib/screens/wallet/wallet_home.dart @@ -791,7 +791,7 @@ class _WalletHomeState extends State Widget build(BuildContext context) { return Scaffold( bottomNavigationBar: _calcBottomNavBar(context), - appBar: _selectedTab == WalletTab.addresses + appBar: _selectedTab == WalletTab.addresses && _wallet.watchOnly ? addressTabWatchOnlySearchAppBar() : AppBar( centerTitle: true, diff --git a/lib/screens/wallet/wallet_list.dart b/lib/screens/wallet/wallet_list.dart index e325a6d7..bfc03a9f 100644 --- a/lib/screens/wallet/wallet_list.dart +++ b/lib/screens/wallet/wallet_list.dart @@ -335,7 +335,7 @@ class _WalletListScreenState extends State borderRadius: const BorderRadius.all(Radius.circular(50.0)), border: Border.all( - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.surface, width: 2, ), ), @@ -365,7 +365,7 @@ class _WalletListScreenState extends State style: TextStyle( letterSpacing: 1.4, fontSize: 24, - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.surface, ), ), ), @@ -386,7 +386,7 @@ class _WalletListScreenState extends State fontSize: 16, fontStyle: FontStyle.italic, color: - Theme.of(context).colorScheme.background, + Theme.of(context).colorScheme.surface, ), ), if (_importedSeed) @@ -438,7 +438,7 @@ class _WalletListScreenState extends State horizontal: 16, ), color: - Theme.of(context).colorScheme.background, + Theme.of(context).colorScheme.surface, child: Column( children: [ InkWell( diff --git a/lib/tools/app_themes.dart b/lib/tools/app_themes.dart index f99142cd..fc04214a 100644 --- a/lib/tools/app_themes.dart +++ b/lib/tools/app_themes.dart @@ -57,24 +57,46 @@ class MyTheme { foregroundColor: LightColors.green, ), ), + sliderTheme: SliderThemeData( + valueIndicatorTextStyle: TextStyle( + color: LightColors.green, + fontWeight: FontWeight.bold, + ), + ), + switchTheme: SwitchThemeData( + thumbColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.selected)) { + return LightColors.white; + } + return LightColors.green; + }), + trackColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.selected)) { + return LightColors.green; + } + return LightColors.white; + }), + trackOutlineColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.selected)) { + return LightColors.white; + } + return LightColors.green; + }), + ), colorScheme: ColorScheme( primary: LightColors.green, primaryContainer: LightColors.darkGreen, secondary: LightColors.grey, secondaryContainer: LightColors.lightGrey, surface: LightColors.white, - background: LightColors.grey, error: LightColors.red, onPrimary: LightColors.white, onSecondary: LightColors.blackGreen, onSurface: LightColors.black, - onBackground: LightColors.green, onError: LightColors.red, brightness: Brightness.light, tertiary: LightColors.white, - ) - .copyWith(background: LightColors.white) - .copyWith(error: LightColors.red), + ).copyWith(surface: LightColors.white).copyWith(error: LightColors.red), bottomAppBarTheme: const BottomAppBarTheme(color: Color(0x003cb054)), ), ThemeMode.dark: ThemeData.dark().copyWith( @@ -95,7 +117,7 @@ class MyTheme { sliderTheme: SliderThemeData(valueIndicatorColor: DarkColors.darkBlue), unselectedWidgetColor: DarkColors.white, radioTheme: RadioThemeData( - fillColor: MaterialStateProperty.all(DarkColors.white), + fillColor: WidgetStateProperty.all(DarkColors.white), ), textTheme: TextTheme( titleLarge: TextStyle(color: DarkColors.white), @@ -150,11 +172,11 @@ class MyTheme { cursorColor: DarkColors.white, ), switchTheme: SwitchThemeData( - thumbColor: MaterialStateProperty.all(DarkColors.white), - trackColor: MaterialStateProperty.all(DarkColors.grey), + thumbColor: WidgetStateProperty.all(DarkColors.white), + trackColor: WidgetStateProperty.all(DarkColors.grey), ), checkboxTheme: CheckboxThemeData( - fillColor: MaterialStateProperty.all(DarkColors.white), + fillColor: WidgetStateProperty.all(DarkColors.white), ), expansionTileTheme: ExpansionTileThemeData( iconColor: DarkColors.white, @@ -164,17 +186,15 @@ class MyTheme { primaryContainer: DarkColors.white, secondary: DarkColors.white, secondaryContainer: DarkColors.grey, - surface: DarkColors.black, - background: DarkColors.green, + surface: DarkColors.green, error: DarkColors.red, onPrimary: DarkColors.green, onSecondary: DarkColors.green, - onSurface: DarkColors.white, - onBackground: DarkColors.green, + onSurface: DarkColors.green, onError: DarkColors.red, brightness: Brightness.dark, tertiary: DarkColors.white, - ).copyWith(background: DarkColors.green).copyWith(error: DarkColors.red), + ).copyWith(surface: DarkColors.green).copyWith(error: DarkColors.red), bottomAppBarTheme: const BottomAppBarTheme(color: Color(0x000D1821)), ), }; diff --git a/lib/widgets/buttons.dart b/lib/widgets/buttons.dart index 9156d8ae..73a2a748 100644 --- a/lib/widgets/buttons.dart +++ b/lib/widgets/buttons.dart @@ -55,8 +55,8 @@ class PeerButtonBorder extends StatelessWidget { Widget build(BuildContext context) { return ElevatedButton( style: ElevatedButton.styleFrom( - foregroundColor: Theme.of(context).colorScheme.background, - backgroundColor: Theme.of(context).colorScheme.background, + foregroundColor: Theme.of(context).colorScheme.surface, + backgroundColor: Theme.of(context).colorScheme.surface, fixedSize: Size( MediaQuery.of(context).size.width > 768 ? MediaQuery.of(context).size.width / 4 @@ -103,7 +103,7 @@ class PeerButtonSetup extends StatelessWidget { style: ElevatedButton.styleFrom( foregroundColor: Theme.of(context).primaryColor, backgroundColor: - active ? Theme.of(context).colorScheme.background : Colors.grey, + active ? Theme.of(context).colorScheme.surface : Colors.grey, fixedSize: Size( MediaQuery.of(context).size.width > 768 ? MediaQuery.of(context).size.width / 4 @@ -148,7 +148,7 @@ class PeerButtonSetupLoading extends StatelessWidget { return ElevatedButton( style: ElevatedButton.styleFrom( foregroundColor: Theme.of(context).primaryColor, - backgroundColor: Theme.of(context).colorScheme.background, + backgroundColor: Theme.of(context).colorScheme.surface, fixedSize: Size( MediaQuery.of(context).size.width > 768 ? MediaQuery.of(context).size.width / 4 diff --git a/lib/widgets/loading_indicator.dart b/lib/widgets/loading_indicator.dart index ebb0408f..598bf72b 100644 --- a/lib/widgets/loading_indicator.dart +++ b/lib/widgets/loading_indicator.dart @@ -7,7 +7,7 @@ class LoadingIndicator extends StatelessWidget { Widget build(BuildContext context) { return LinearProgressIndicator( color: Theme.of(context).primaryColor, - backgroundColor: Theme.of(context).colorScheme.background, + backgroundColor: Theme.of(context).colorScheme.surface, ); } //TODO try to move heavy computation away from Main thread so this animation actually continues diff --git a/lib/widgets/service_container.dart b/lib/widgets/service_container.dart index 1a3845f9..b5e534ae 100644 --- a/lib/widgets/service_container.dart +++ b/lib/widgets/service_container.dart @@ -62,7 +62,7 @@ class PeerContainer extends StatelessWidget { decoration: BoxDecoration( color: isTransparent ? Colors.transparent - : Theme.of(context).colorScheme.background, + : Theme.of(context).colorScheme.surface, borderRadius: BorderRadius.circular(20), ), child: child, @@ -85,7 +85,7 @@ class ModalBottomSheetContainer extends StatelessWidget { ? MediaQuery.of(context).size.width / 2 : MediaQuery.of(context).size.width, decoration: BoxDecoration( - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.surface, borderRadius: const BorderRadius.vertical( top: Radius.circular(20), ), diff --git a/lib/widgets/wallet/address_book/addresses_tab_expandable.dart b/lib/widgets/wallet/address_book/addresses_tab_expandable.dart index 96a1309a..316f26b3 100644 --- a/lib/widgets/wallet/address_book/addresses_tab_expandable.dart +++ b/lib/widgets/wallet/address_book/addresses_tab_expandable.dart @@ -109,33 +109,6 @@ class AddressTabExpandable extends StatelessWidget { const SizedBox( height: 10, ), - // IconSlideAction( - // caption: AppLocalizations.instance - // .translate('addressbook_swipe_edit'), - // color: Theme.of(context).primaryColor, - // icon: Icons.edit, - // onTap: - // ), - // IconSlideAction( - // caption: AppLocalizations.instance - // .translate('addressbook_swipe_share'), - // color: Theme.of(context).colorScheme.background, - // iconWidget: Icon( - // Icons.share, - // color: Theme.of(context).colorScheme.secondary, - // ), - // onTap: - // ), - // IconSlideAction( - // caption: AppLocalizations.instance - // .translate('addressbook_swipe_delete'), - // color: Theme.of(context).colorScheme.error, - // iconWidget: const Icon( - // Icons.delete, - // color: Colors.white, - // ), - // onTap: () async {}, - // ), ], ), ), diff --git a/lib/widgets/wallet/address_book/addresses_tab_watch_only.dart b/lib/widgets/wallet/address_book/addresses_tab_watch_only.dart index 9724e714..22f47708 100644 --- a/lib/widgets/wallet/address_book/addresses_tab_watch_only.dart +++ b/lib/widgets/wallet/address_book/addresses_tab_watch_only.dart @@ -190,9 +190,9 @@ class _AddressesTabWatchOnlyState extends State { child: ElevatedButton( style: ElevatedButton.styleFrom( foregroundColor: - Theme.of(context).colorScheme.background, + Theme.of(context).colorScheme.surface, backgroundColor: - Theme.of(context).colorScheme.background, + Theme.of(context).colorScheme.surface, fixedSize: Size( MediaQuery.of(context).size.width > 1200 ? MediaQuery.of(context).size.width / 5 @@ -239,7 +239,7 @@ class _AddressesTabWatchOnlyState extends State { style: TextStyle( fontSize: 16, fontStyle: FontStyle.italic, - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.surface, ), ), ), diff --git a/lib/widgets/wallet/addresses_tab.dart b/lib/widgets/wallet/addresses_tab.dart index ee94acd0..6603c63a 100644 --- a/lib/widgets/wallet/addresses_tab.dart +++ b/lib/widgets/wallet/addresses_tab.dart @@ -457,107 +457,103 @@ class _AddressTabState extends State { child: ClipRect( child: Slidable( key: Key(addr.address), - actionPane: const SlidableScrollActionPane(), - secondaryActions: [ - IconSlideAction( - caption: AppLocalizations.instance - .translate('addressbook_swipe_edit'), - color: Theme.of(context).primaryColor, - icon: Icons.edit, - onTap: () => _addressEditDialog(context, addr), - ), - IconSlideAction( - caption: AppLocalizations.instance - .translate('addressbook_swipe_share'), - color: Theme.of(context).colorScheme.background, - iconWidget: Icon( - Icons.share, - color: Theme.of(context).colorScheme.secondary, - ), - onTap: () => WalletHomeQr.showQrDialog( - context, - addr.address, - ), - ), - IconSlideAction( - caption: AppLocalizations.instance - .translate('addressbook_swipe_send'), - color: Theme.of(context).colorScheme.secondary, - iconWidget: Icon( - Icons.send, - color: Theme.of(context).colorScheme.background, + endActionPane: ActionPane( + motion: const DrawerMotion(), + extentRatio: 1, + children: [ + SlidableAction( + label: AppLocalizations.instance + .translate('addressbook_swipe_edit'), + backgroundColor: Theme.of(context).primaryColor, + icon: Icons.edit, + onPressed: (ctx) => _addressEditDialog(ctx, addr), ), - onTap: () => widget.changeTab( - WalletTab.send, - addr.address, - addr.addressBookName, + SlidableAction( + label: AppLocalizations.instance + .translate('addressbook_swipe_share'), + backgroundColor: + Theme.of(context).colorScheme.surface, + icon: Icons.share, + onPressed: (ctx) => WalletHomeQr.showQrDialog( + ctx, + addr.address, + ), ), - ), - IconSlideAction( - caption: AppLocalizations.instance - .translate('addressbook_swipe_delete'), - color: Theme.of(context).colorScheme.error, - iconWidget: const Icon( - Icons.delete, - color: Colors.white, + SlidableAction( + label: AppLocalizations.instance + .translate('addressbook_swipe_send'), + backgroundColor: + Theme.of(context).colorScheme.secondary, + icon: Icons.send, + onPressed: (_) => widget.changeTab( + WalletTab.send, + addr.address, + addr.addressBookName, + ), ), - onTap: () async { - await showDialog( - context: context, - builder: (_) => AlertDialog( - title: Text( - AppLocalizations.instance.translate( - 'addressbook_dialog_remove_title', - ), - ), - content: Text(addr.address), - actions: [ - TextButton.icon( - label: Text( - AppLocalizations.instance.translate( - 'server_settings_alert_cancel', - ), + SlidableAction( + label: AppLocalizations.instance + .translate('addressbook_swipe_delete'), + backgroundColor: Theme.of(context).colorScheme.error, + icon: Icons.delete, + onPressed: (ctx) async { + await showDialog( + context: ctx, + builder: (_) => AlertDialog( + title: Text( + AppLocalizations.instance.translate( + 'addressbook_dialog_remove_title', ), - icon: const Icon(Icons.cancel), - onPressed: () { - Navigator.of(context).pop(); - }, ), - TextButton.icon( - label: Text( - AppLocalizations.instance - .translate('jail_dialog_button'), + content: Text(addr.address), + actions: [ + TextButton.icon( + label: Text( + AppLocalizations.instance.translate( + 'server_settings_alert_cancel', + ), + ), + icon: const Icon(Icons.cancel), + onPressed: () { + Navigator.of(context).pop(); + }, ), - icon: const Icon(Icons.check), - onPressed: () { - context - .read() - .removeAddress( - widget.walletName, - addr, - ); - applyFilter(); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - AppLocalizations.instance.translate( - 'addressbook_dialog_remove_snack', + TextButton.icon( + label: Text( + AppLocalizations.instance + .translate('jail_dialog_button'), + ), + icon: const Icon(Icons.check), + onPressed: () { + context + .read() + .removeAddress( + widget.walletName, + addr, + ); + applyFilter(); + ScaffoldMessenger.of(context) + .showSnackBar( + SnackBar( + content: Text( + AppLocalizations.instance.translate( + 'addressbook_dialog_remove_snack', + ), + textAlign: TextAlign.center, ), - textAlign: TextAlign.center, + duration: const Duration(seconds: 5), ), - duration: const Duration(seconds: 5), - ), - ); - Navigator.of(context).pop(); - }, - ), - ], - ), - ); - }, - ), - ], - actionExtentRatio: 0.25, + ); + Navigator.of(context).pop(); + }, + ), + ], + ), + ); + }, + ), + ], + ), child: ListTile( leading: const Column( mainAxisAlignment: MainAxisAlignment.center, @@ -603,62 +599,57 @@ class _AddressTabState extends State { child: ClipRect( child: Slidable( key: Key(addr.address), - actionPane: const SlidableScrollActionPane(), - secondaryActions: [ - IconSlideAction( - caption: AppLocalizations.instance - .translate('addressbook_swipe_edit'), - color: Theme.of(context).primaryColor, - icon: Icons.edit, - onTap: () => _addressEditDialog(context, addr), - ), - IconSlideAction( - caption: AppLocalizations.instance - .translate('addressbook_swipe_share'), - color: Theme.of(context).colorScheme.background, - iconWidget: Icon( - Icons.share, - color: Theme.of(context).colorScheme.secondary, + endActionPane: ActionPane( + motion: const DrawerMotion(), + extentRatio: 1, + children: [ + SlidableAction( + label: AppLocalizations.instance + .translate('addressbook_swipe_edit'), + backgroundColor: Theme.of(context).primaryColor, + icon: Icons.edit, + onPressed: (ctx) => _addressEditDialog(ctx, addr), ), - onTap: () => WalletHomeQr.showQrDialog( - context, - addr.address, - ), - ), - IconSlideAction( - caption: AppLocalizations.instance.translate( - _isWatchedMap[addr.address] == true - ? 'addressbook_swipe_unwatch' - : 'addressbook_swipe_watch', + SlidableAction( + label: AppLocalizations.instance + .translate('addressbook_swipe_share'), + backgroundColor: + Theme.of(context).colorScheme.surface, + icon: Icons.share, + onPressed: (ctx) => WalletHomeQr.showQrDialog( + ctx, + addr.address, + ), ), - color: Theme.of(context).colorScheme.secondary, - iconWidget: Icon( - _isWatchedMap[addr.address] == true + SlidableAction( + label: AppLocalizations.instance.translate( + _isWatchedMap[addr.address] == true + ? 'addressbook_swipe_unwatch' + : 'addressbook_swipe_watch', + ), + backgroundColor: + Theme.of(context).colorScheme.secondary, + icon: _isWatchedMap[addr.address] == true ? Icons.visibility_off : Icons.visibility, - color: Theme.of(context).colorScheme.background, + onPressed: (_) => _toggleWatched(addr), ), - onTap: () => _toggleWatched(addr), - ), - IconSlideAction( - caption: AppLocalizations.instance - .translate('addressbook_swipe_export'), - color: Theme.of(context).colorScheme.error, - iconWidget: Icon( - Icons.vpn_key, - color: Theme.of(context).colorScheme.background, - ), - onTap: () => Auth.requireAuth( - context: context, - biometricsAllowed: context - .read() - .biometricsAllowed, - callback: () => - _showAddressExportDialog(context, addr), + SlidableAction( + label: AppLocalizations.instance + .translate('addressbook_swipe_export'), + backgroundColor: Theme.of(context).colorScheme.error, + icon: Icons.vpn_key, + onPressed: (ctx) => Auth.requireAuth( + context: ctx, + biometricsAllowed: context + .read() + .biometricsAllowed, + callback: () => + _showAddressExportDialog(context, addr), + ), ), - ), - ], - actionExtentRatio: 0.25, + ], + ), child: ListTile( leading: const Column( mainAxisAlignment: MainAxisAlignment.center, @@ -720,7 +711,7 @@ class _AddressTabState extends State { spacing: 10, children: [ ChoiceChip( - backgroundColor: Theme.of(context).colorScheme.background, + backgroundColor: Theme.of(context).colorScheme.surface, selectedColor: Theme.of(context).shadowColor, visualDensity: const VisualDensity( horizontal: 0.0, @@ -743,7 +734,7 @@ class _AddressTabState extends State { }, ), ChoiceChip( - backgroundColor: Theme.of(context).colorScheme.background, + backgroundColor: Theme.of(context).colorScheme.surface, selectedColor: Theme.of(context).shadowColor, visualDensity: const VisualDensity( horizontal: 0.0, @@ -768,7 +759,7 @@ class _AddressTabState extends State { Padding( padding: const EdgeInsets.all(kIsWeb ? 8.0 : 0), child: ChoiceChip( - backgroundColor: Theme.of(context).colorScheme.background, + backgroundColor: Theme.of(context).colorScheme.surface, selectedColor: Theme.of(context).shadowColor, visualDensity: const VisualDensity( horizontal: 0.0, @@ -798,7 +789,7 @@ class _AddressTabState extends State { ), ), ChoiceChip( - backgroundColor: Theme.of(context).colorScheme.background, + backgroundColor: Theme.of(context).colorScheme.surface, selectedColor: Theme.of(context).shadowColor, visualDensity: const VisualDensity( horizontal: 0.0, @@ -822,7 +813,7 @@ class _AddressTabState extends State { }, ), ChoiceChip( - backgroundColor: Theme.of(context).colorScheme.background, + backgroundColor: Theme.of(context).colorScheme.surface, selectedColor: Theme.of(context).shadowColor, visualDensity: const VisualDensity( horizontal: 0.0, @@ -862,7 +853,7 @@ class _AddressTabState extends State { automaticallyImplyLeading: false, floating: true, backgroundColor: _search - ? Theme.of(context).colorScheme.background + ? Theme.of(context).colorScheme.surface : Theme.of(context).primaryColor, title: Container( margin: const EdgeInsets.only(top: 8), @@ -878,10 +869,11 @@ class _AddressTabState extends State { autocorrect: false, decoration: InputDecoration( border: InputBorder.none, + focusColor: Colors.red, hintText: AppLocalizations.instance .translate('addressbook_search'), suffixIcon: IconButton( - icon: const Center(child: Icon(Icons.clear)), + icon: const Icon(Icons.clear), iconSize: 24, onPressed: () { _search = false; @@ -899,9 +891,9 @@ class _AddressTabState extends State { ElevatedButton( style: ElevatedButton.styleFrom( foregroundColor: - Theme.of(context).colorScheme.background, + Theme.of(context).colorScheme.secondary, backgroundColor: - Theme.of(context).colorScheme.background, + Theme.of(context).colorScheme.surface, fixedSize: Size( MediaQuery.of(context).size.width > 1200 ? MediaQuery.of(context).size.width / 5 @@ -938,9 +930,9 @@ class _AddressTabState extends State { ElevatedButton( style: ElevatedButton.styleFrom( foregroundColor: - Theme.of(context).colorScheme.background, + Theme.of(context).colorScheme.surface, backgroundColor: - Theme.of(context).colorScheme.background, + Theme.of(context).colorScheme.surface, fixedSize: Size( MediaQuery.of(context).size.width > 1200 ? MediaQuery.of(context).size.width / 5 diff --git a/lib/widgets/wallet/transactions_list.dart b/lib/widgets/wallet/transactions_list.dart index ba84c365..955ca6ba 100644 --- a/lib/widgets/wallet/transactions_list.dart +++ b/lib/widgets/wallet/transactions_list.dart @@ -132,7 +132,7 @@ class _TransactionListState extends State { style: TextStyle( fontSize: 16, fontStyle: FontStyle.italic, - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.surface, ), ), ), @@ -289,7 +289,7 @@ class _TransactionListState extends State { ChoiceChip( backgroundColor: Theme.of(context) .colorScheme - .background, + .surface, selectedColor: Theme.of(context).shadowColor, visualDensity: const VisualDensity( @@ -311,7 +311,7 @@ class _TransactionListState extends State { ChoiceChip( backgroundColor: Theme.of(context) .colorScheme - .background, + .surface, selectedColor: Theme.of(context).shadowColor, visualDensity: const VisualDensity( @@ -333,7 +333,7 @@ class _TransactionListState extends State { ChoiceChip( backgroundColor: Theme.of(context) .colorScheme - .background, + .surface, selectedColor: Theme.of(context).shadowColor, visualDensity: const VisualDensity( diff --git a/lib/widgets/wallet/wallet_home_connection.dart b/lib/widgets/wallet/wallet_home_connection.dart index caf7e99b..2f71cff5 100644 --- a/lib/widgets/wallet/wallet_home_connection.dart +++ b/lib/widgets/wallet/wallet_home_connection.dart @@ -15,7 +15,7 @@ class WalletHomeConnection extends StatelessWidget { widget = Text( AppLocalizations.instance.translate('wallet_connected'), style: TextStyle( - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.surface, letterSpacing: 1.4, fontSize: 16, ), @@ -24,7 +24,7 @@ class WalletHomeConnection extends StatelessWidget { widget = Text( AppLocalizations.instance.translate('wallet_offline'), style: TextStyle( - color: Theme.of(context).colorScheme.background, + color: Theme.of(context).colorScheme.surface, fontSize: 16, letterSpacing: 1.4, ), diff --git a/pubspec.lock b/pubspec.lock index 3053b6a8..65bb512a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -69,10 +69,10 @@ packages: dependency: "direct main" description: name: background_fetch - sha256: "67d28aa747d344e8ab4cb56f0fba4f957c1d41504fc6be1ef275864000b30eb6" + sha256: "2fe367c9be0e256dadb75b8b637b0b58a2a2d2317b7c8420bb1ae8b41e23fde3" url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.4" bip39: dependency: "direct main" description: @@ -532,10 +532,10 @@ packages: dependency: "direct main" description: name: flutter_screen_lock - sha256: f8e504aa0e5fe61ea13b66692ecdec3e8761118173b51c9b3b5518b8e2911e5b + sha256: "5c09314747a70d8e1259a1d787f49f4f29d6eae224cd9b2f045e513e8408cbcc" url: "https://pub.dev" source: hosted - version: "9.0.2" + version: "9.0.3" flutter_secure_storage: dependency: "direct main" description: @@ -588,10 +588,10 @@ packages: dependency: "direct main" description: name: flutter_slidable - sha256: c7607eb808cdef19c8468246e95a133308aeaeb3971cdd9edfb9d5e31cedfbe9 + sha256: "673403d2eeef1f9e8483bd6d8d92aae73b1d8bd71f382bc3930f699c731bc27c" url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "3.1.0" flutter_test: dependency: "direct dev" description: flutter @@ -744,10 +744,10 @@ packages: dependency: "direct main" description: name: intl - sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf url: "https://pub.dev" source: hosted - version: "0.18.1" + version: "0.19.0" io: dependency: transitive description: @@ -776,26 +776,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" url: "https://pub.dev" source: hosted - version: "10.0.0" + version: "10.0.4" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.3" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.1" lints: dependency: transitive description: @@ -896,10 +896,10 @@ packages: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.12.0" mime: dependency: transitive description: @@ -1357,26 +1357,26 @@ packages: dependency: "direct dev" description: name: test - sha256: a1f7595805820fcc05e5c52e3a231aedd0b72972cb333e8c738a8b1239448b6f + sha256: "7ee446762c2c50b3bd4ea96fe13ffac69919352bd3b4b17bac3f3465edc58073" url: "https://pub.dev" source: hosted - version: "1.24.9" + version: "1.25.2" test_api: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.7.0" test_core: dependency: transitive description: name: test_core - sha256: a757b14fc47507060a162cc2530d9a4a2f92f5100a952c7443b5cad5ef5b106a + sha256: "2bc4b4ecddd75309300d8096f781c0e3280ca1ef85beda558d33fcbedc2eead4" url: "https://pub.dev" source: hosted - version: "0.5.9" + version: "0.6.0" theme_mode_handler: dependency: "direct main" description: @@ -1501,10 +1501,10 @@ packages: dependency: transitive description: name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "14.2.1" wasm_interop: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 1629543b..fdde5156 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -24,24 +24,24 @@ dependencies: provider: ^6.0.3 share_plus: ^7.0.2 qr_flutter: ^4.0.0 - intl: ^0.18.0 + intl: ^0.19.0 step_progress_indicator: ^1.0.0 qr_code_scanner: ^1.0.0 url_launcher: ^6.1.4 flutter_local_notifications: ^17.0.0 - flutter_screen_lock: ^9.0.1 + flutter_screen_lock: ^9.0.3 local_auth: ^2.1.6 local_auth_android: any package_info_plus: ^4.1.0 mailto: ^2.0.0 - flutter_slidable: ^0.6.0 + flutter_slidable: ^3.1.0 flutter_typeahead: ^4.0.0 connectivity_plus: ^3.0.2 theme_mode_handler: ^3.0.0 http: ^0.13.3 collection: ^1.15.0-nullsafety.4 flutter_markdown: ^0.6.6 - background_fetch: ^1.1.2 + background_fetch: ^1.3.4 flutter_logs: ^2.1.11 auto_size_text: ^3.0.0 camera: ^0.10.0+4 From 59f3ba350fab6578ef70f1be0b415db5a16a23e8 Mon Sep 17 00:00:00 2001 From: Willy Date: Thu, 16 May 2024 17:28:22 +0200 Subject: [PATCH 06/22] chore: Trim whitespace in address input field --- .../wallet/address_book/addresses_tab_watch_only.dart | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/widgets/wallet/address_book/addresses_tab_watch_only.dart b/lib/widgets/wallet/address_book/addresses_tab_watch_only.dart index 22f47708..21602539 100644 --- a/lib/widgets/wallet/address_book/addresses_tab_watch_only.dart +++ b/lib/widgets/wallet/address_book/addresses_tab_watch_only.dart @@ -152,7 +152,7 @@ class _AddressesTabWatchOnlyState extends State { formKey.currentState!.save(); context.read().createWatchOnlyAddres( identifier: widget.walletName, - address: addressController.text, + address: addressController.text.trim(), label: labelController.text == '' ? '' : labelController.text, @@ -189,10 +189,8 @@ class _AddressesTabWatchOnlyState extends State { padding: const EdgeInsets.all(20), child: ElevatedButton( style: ElevatedButton.styleFrom( - foregroundColor: - Theme.of(context).colorScheme.surface, - backgroundColor: - Theme.of(context).colorScheme.surface, + foregroundColor: Theme.of(context).colorScheme.surface, + backgroundColor: Theme.of(context).colorScheme.surface, fixedSize: Size( MediaQuery.of(context).size.width > 1200 ? MediaQuery.of(context).size.width / 5 From b3197314542513ee96ae803760df6de045aa906b Mon Sep 17 00:00:00 2001 From: Willy Date: Thu, 16 May 2024 17:35:45 +0200 Subject: [PATCH 07/22] chore: Update switch theme colors in app_themes.dart --- lib/screens/setup/setup_auth.dart | 3 --- lib/tools/app_themes.dart | 22 +++++++++++++++++++--- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/lib/screens/setup/setup_auth.dart b/lib/screens/setup/setup_auth.dart index 2c8934aa..01ebe089 100644 --- a/lib/screens/setup/setup_auth.dart +++ b/lib/screens/setup/setup_auth.dart @@ -115,9 +115,6 @@ class _SetupAuthScreenState extends State { ), ), value: _biometricsAllowed, - activeColor: - Theme.of(context).colorScheme.surface, - inactiveThumbColor: Colors.grey, onChanged: (newState) { if (_biometricsAvailable == false) { ScaffoldMessenger.of(context).showSnackBar( diff --git a/lib/tools/app_themes.dart b/lib/tools/app_themes.dart index fc04214a..c6559091 100644 --- a/lib/tools/app_themes.dart +++ b/lib/tools/app_themes.dart @@ -172,8 +172,24 @@ class MyTheme { cursorColor: DarkColors.white, ), switchTheme: SwitchThemeData( - thumbColor: WidgetStateProperty.all(DarkColors.white), - trackColor: WidgetStateProperty.all(DarkColors.grey), + thumbColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.selected)) { + return DarkColors.white; + } + return DarkColors.grey; + }), + trackColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.selected)) { + return DarkColors.grey; + } + return DarkColors.white; + }), + trackOutlineColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.selected)) { + return DarkColors.white; + } + return DarkColors.grey; + }), ), checkboxTheme: CheckboxThemeData( fillColor: WidgetStateProperty.all(DarkColors.white), @@ -190,7 +206,7 @@ class MyTheme { error: DarkColors.red, onPrimary: DarkColors.green, onSecondary: DarkColors.green, - onSurface: DarkColors.green, + onSurface: DarkColors.black, onError: DarkColors.red, brightness: Brightness.dark, tertiary: DarkColors.white, From d375c3900caee573c98770fa5a9cb50c04cd6187 Mon Sep 17 00:00:00 2001 From: Willy Date: Mon, 20 May 2024 11:02:15 +0200 Subject: [PATCH 08/22] Changelog --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 670f0827..8d4974c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ -### **1.2.7** (2023-05-xx) +### **1.2.7** (2023-05-16) -- +- Various bug fixes and improvements related to flutter upgrade +- Improved flow for transaction signing, now with confirmation and more feedback ### **1.2.6** (2023-04-20) From 06db259a686377bd86ae79118a0bc4e9efba0a71 Mon Sep 17 00:00:00 2001 From: Willy Date: Mon, 20 May 2024 12:31:12 +0200 Subject: [PATCH 09/22] skeleton to push sign transaction results into separate confirmation screen --- .../wallet/wallet_sign_transaction.dart | 210 ++++-------------- .../wallet_sign_transaction_confirmation.dart | 141 ++++++++++++ lib/tools/app_routes.dart | 8 + 3 files changed, 187 insertions(+), 172 deletions(-) create mode 100644 lib/screens/wallet/wallet_sign_transaction_confirmation.dart diff --git a/lib/screens/wallet/wallet_sign_transaction.dart b/lib/screens/wallet/wallet_sign_transaction.dart index 2e93ba96..eeea657f 100644 --- a/lib/screens/wallet/wallet_sign_transaction.dart +++ b/lib/screens/wallet/wallet_sign_transaction.dart @@ -1,9 +1,10 @@ import 'package:coinlib_flutter/coinlib_flutter.dart'; import 'package:collection/collection.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:peercoin/models/available_coins.dart'; import 'package:peercoin/providers/wallet_provider.dart'; +import 'package:peercoin/screens/wallet/wallet_sign_transaction_confirmation.dart'; import 'package:peercoin/tools/app_localizations.dart'; import 'package:peercoin/tools/app_routes.dart'; import 'package:peercoin/tools/logger_wrapper.dart'; @@ -25,12 +26,10 @@ class _WalletSignTransactionScreenState late String _walletName; late WalletProvider _walletProvider; bool _initial = true; - bool _signingDone = false; String _signingError = ''; - String _signedTx = ''; String _signingAddress = ''; + final List _successfullySignedInputs = []; final TextEditingController _txInputController = TextEditingController(); - final Map _checkedInputs = {}; @override void didChangeDependencies() { @@ -76,86 +75,6 @@ class _WalletSignTransactionScreenState } } - Future _showInputSelector(int inputN) async { - return await showModalBottomSheet( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(20.0), - ), - isDismissible: false, - context: context, - enableDrag: false, - builder: (BuildContext context) { - return StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return ModalBottomSheetContainer( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - AppLocalizations.instance.translate( - 'sign_transaction_input_selector_title', - ), - style: TextStyle( - letterSpacing: 1.4, - fontSize: 24, - color: Theme.of(context).colorScheme.primary, - ), - ), - const SizedBox( - height: 30, - ), - Expanded( - child: ListView.builder( - itemBuilder: (ctx, n) => CheckboxListTile( - title: Text('Input $n'), - value: _checkedInputs[n] ?? false, - onChanged: (value) { - setState(() { - _checkedInputs[n] = value!; - }); - }, - ), - itemCount: inputN, - ), - ), - const SizedBox( - height: 20, - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - TextButton.icon( - label: Text( - AppLocalizations.instance - .translate('server_settings_alert_cancel'), - ), - icon: const Icon(Icons.cancel), - onPressed: () { - Navigator.of(context).pop(false); - }, - ), - TextButton.icon( - label: Text( - AppLocalizations.instance - .translate('jail_dialog_button'), - ), - icon: const Icon(Icons.check), - onPressed: () { - Navigator.of(context).pop(true); - }, - ), - ], - ), - ], - ), - ); - }, - ); - }, - ); - } - Future _handleSign() async { LoggerWrapper.logInfo( 'WalletTransactionSigning', @@ -171,18 +90,10 @@ class _WalletSignTransactionScreenState final privKey = WIF.fromString(wif).privkey; Transaction tx = Transaction.fromHex(_txInputController.text); - final selectedInputResult = await _showInputSelector(tx.inputs.length); - if (selectedInputResult == false) return; - if (_checkedInputs.values.every((element) => element == false)) return; // conversion step for cointoolkit start tx = Transaction( inputs: tx.inputs.mapIndexed((i, input) { - if (!_checkedInputs.containsKey(i) || _checkedInputs[i]! == false) { - //don't convert this unselected input, return as is - return input; - } - // Determine program from cointoolkit input script data final program = Program.decompile(input.scriptSig); @@ -209,26 +120,43 @@ class _WalletSignTransactionScreenState // conversion step for cointoolkit end Transaction txToSign = tx; - _checkedInputs.forEach((key, value) { - if (value) { + //try to sign all inputs + tx.inputs.mapIndexed((i, input) { + try { txToSign = txToSign.sign( - inputN: key, + inputN: i, key: privKey, ); + _successfullySignedInputs.add(i); + } catch (e) { + LoggerWrapper.logError( + 'WalletTransactionSigning', + 'handleSign', + 'failed to sign input $i: $e', + ); } }); final signedTx = txToSign.toHex(); - setState(() { - _signedTx = signedTx; - _signingDone = true; - }); - LoggerWrapper.logInfo( 'WalletTransactionSigning', 'handleSign', 'tx produced $signedTx', ); + + //show confirmation + if (!mounted) return; + await Navigator.of(context).pushNamed( + Routes.walletTransactionSigningConfirmation, + arguments: WalletSignTransactionConfirmationArguments( + tx: tx, + decimalProduct: AvailableCoins.getDecimalProduct( + identifier: _walletName, + ), + coinLetterCode: "ppc", + selectedInputs: _successfullySignedInputs, + ), + ); } catch (e) { LoggerWrapper.logError( 'WalletTransactionSigning', @@ -358,17 +286,15 @@ class _WalletSignTransactionScreenState ), ), PeerButton( - action: () => - _signingDone ? null : _showAddressSelector(), + action: () => _showAddressSelector(), text: AppLocalizations.instance.translate( _signingAddress == '' ? 'sign_step_1_button' : 'sign_step_1_button_alt', ), small: true, - active: !_signingDone, ), - _signingAddress.isNotEmpty && !_signingDone + _signingAddress.isNotEmpty ? PeerButton( action: () => _copyPubKeyToClipboard( _signingAddress, @@ -377,7 +303,6 @@ class _WalletSignTransactionScreenState 'sign_transaction_step_1_copy_pubkey', ), small: true, - active: !_signingDone, ) : Container(), const SizedBox( @@ -401,7 +326,6 @@ class _WalletSignTransactionScreenState key: const Key('transactionHexInput'), controller: _txInputController, autocorrect: false, - readOnly: _signingDone, minLines: 5, maxLines: 5, onChanged: (_) => setState( @@ -410,7 +334,6 @@ class _WalletSignTransactionScreenState decoration: InputDecoration( suffixIcon: IconButton( onPressed: () async { - if (_signingDone) return; final data = await Clipboard.getData('text/plain'); setState(() { @@ -419,9 +342,7 @@ class _WalletSignTransactionScreenState }, icon: Icon( Icons.paste_rounded, - color: _signingDone - ? Theme.of(context).colorScheme.secondary - : Theme.of(context).primaryColor, + color: Theme.of(context).primaryColor, ), ), icon: Icon( @@ -446,57 +367,14 @@ class _WalletSignTransactionScreenState const SizedBox( height: 10, ), - _signedTx.isNotEmpty - ? Column( - children: [ - DoubleTabToClipboard( - clipBoardData: _signedTx, - child: SelectableText( - _signedTx, - key: const Key('signature'), - ), - ), - const SizedBox( - height: 10, - ), - Text( - AppLocalizations.instance.translate( - 'sign_transaction_step_3_description', - ), - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 12, - color: - Theme.of(context).colorScheme.secondary, - ), - ), - ], - ) - : Container(), - const SizedBox( - height: 10, + PeerButton( + action: () => _handleSign(), + text: AppLocalizations.instance + .translate('sign_step_3_button'), + small: true, + active: _signingAddress.isNotEmpty && + _txInputController.text.isNotEmpty, ), - _signedTx.isNotEmpty - ? PeerButton( - action: () => DoubleTabToClipboard.tapEvent( - context, - _signedTx, - ), - text: AppLocalizations.instance.translate( - 'sign_transaction_step_3_button_alt', - ), - small: true, - active: _signingAddress.isNotEmpty && - _txInputController.text.isNotEmpty, - ) - : PeerButton( - action: () => _handleSign(), - text: AppLocalizations.instance - .translate('sign_step_3_button'), - small: true, - active: _signingAddress.isNotEmpty && - _txInputController.text.isNotEmpty, - ), _signingError.isNotEmpty ? Padding( padding: const EdgeInsets.symmetric(vertical: 10), @@ -512,18 +390,6 @@ class _WalletSignTransactionScreenState ), ) : Container(), - if (kIsWeb) - const SizedBox( - height: 20, - ), - _signingDone - ? PeerButton( - text: AppLocalizations.instance - .translate('sign_reset_button'), - small: true, - action: () async => await _performReset(context), - ) - : Container(), ], ), ), diff --git a/lib/screens/wallet/wallet_sign_transaction_confirmation.dart b/lib/screens/wallet/wallet_sign_transaction_confirmation.dart new file mode 100644 index 00000000..65cb76a5 --- /dev/null +++ b/lib/screens/wallet/wallet_sign_transaction_confirmation.dart @@ -0,0 +1,141 @@ +import 'package:coinlib_flutter/coinlib_flutter.dart'; +import 'package:flutter/material.dart'; +import 'package:peercoin/screens/wallet/transaction_details.dart'; +import 'package:peercoin/tools/app_localizations.dart'; +import 'package:peercoin/widgets/service_container.dart'; + +class WalletSignTransactionConfirmationArguments { + Transaction tx; + List selectedInputs; + int decimalProduct; + String coinLetterCode; + + WalletSignTransactionConfirmationArguments({ + required this.tx, + required this.selectedInputs, + required this.decimalProduct, + required this.coinLetterCode, + }); +} + +class WalletSignTransactionConfirmationScreen extends StatelessWidget { + const WalletSignTransactionConfirmationScreen({super.key}); + List renderRecipients({ + required Map recipients, + required String letterCode, + required int decimalProduct, + }) { + List list = []; + + recipients.forEach( + (addr, value) => list.add( + const TransactionDetails().renderRow( + addr, + value / decimalProduct, + letterCode, + ), + ), + ); + return list; + } + + @override + Widget build(BuildContext context) { + final WalletSignTransactionConfirmationArguments arguments = + ModalRoute.of(context)!.settings.arguments + as WalletSignTransactionConfirmationArguments; + final Transaction tx = arguments.tx; + final totalAmount = tx.outputs.map((e) => e.value).reduce((a, b) => a + b); + final decimalProduct = arguments.decimalProduct; + final selectedInputs = arguments.selectedInputs; + final coinLetterCode = arguments.coinLetterCode; + + return Scaffold( + appBar: AppBar( + centerTitle: true, + title: Text( + AppLocalizations.instance.translate('send_confirm_transaction'), + ), + ), + body: Column( + children: [ + Expanded( + child: SingleChildScrollView( + child: Align( + child: PeerContainer( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + AppLocalizations.instance.translate('tx_value'), + style: const TextStyle( + fontWeight: FontWeight.bold, + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SelectableText( + '${totalAmount.toInt() / decimalProduct} $coinLetterCode', + ), + ], + ), + ], + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + AppLocalizations.instance + .translate('send_total_amount'), + style: const TextStyle( + fontWeight: FontWeight.bold, + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SelectableText( + '${totalAmount.toInt() / decimalProduct} $coinLetterCode', + ), + ], + ), + ], + ), + const Divider(), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + AppLocalizations.instance + .translate('tx_recipients'), + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ...renderRecipients( + recipients: {"asdf": 0}, + letterCode: coinLetterCode, + decimalProduct: decimalProduct, + ), + ], + ), + const SizedBox( + height: 20, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [], + ), + ], + ), + ), + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/tools/app_routes.dart b/lib/tools/app_routes.dart index e0d76912..88516a79 100644 --- a/lib/tools/app_routes.dart +++ b/lib/tools/app_routes.dart @@ -1,6 +1,7 @@ import 'package:flutter/widgets.dart'; import 'package:peercoin/screens/wallet/transaction_confirmation.dart'; import 'package:peercoin/screens/wallet/wallet_sign_transaction.dart'; +import 'package:peercoin/screens/wallet/wallet_sign_transaction_confirmation.dart'; import 'package:peercoin/screens/wallet/wallet_verify_message.dart'; import '../screens/settings/app_settings_app_theme.dart'; @@ -62,6 +63,8 @@ class Routes { static const String walletMessageVerification = '/wallet-message-verification'; static const String walletTransactionSigning = '/wallet-transaction-signing'; + static const String walletTransactionSigningConfirmation = + '/wallet-transaction-signing-confirmation'; static const String importPaperWallet = '/import-paperwallet'; static const String importWif = '/import-wif'; static const String authJail = '/auth-jail'; @@ -202,6 +205,11 @@ class Routes { widget: WalletSignTransactionScreen(), routeType: RouteTypes.requiresArguments, ), + Routes.walletTransactionSigningConfirmation: (context) => + const RouterMaster( + widget: WalletSignTransactionConfirmationScreen(), + routeType: RouteTypes.requiresArguments, + ), }; } } From 550874b496166903cd6bc39a32ca74ff21f942bc Mon Sep 17 00:00:00 2001 From: Willy Date: Mon, 20 May 2024 12:33:57 +0200 Subject: [PATCH 10/22] better argument and prop handling --- lib/screens/wallet/wallet_home.dart | 6 +++++- .../wallet/wallet_sign_transaction.dart | 18 ++++++++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/lib/screens/wallet/wallet_home.dart b/lib/screens/wallet/wallet_home.dart index 52d399d8..d903a6d4 100644 --- a/lib/screens/wallet/wallet_home.dart +++ b/lib/screens/wallet/wallet_home.dart @@ -6,6 +6,7 @@ import 'package:flutter/material.dart'; import 'package:loader_overlay/loader_overlay.dart'; import 'package:peercoin/data_sources/electrum_backend.dart'; import 'package:peercoin/providers/server_provider.dart'; +import 'package:peercoin/screens/wallet/wallet_sign_transaction.dart'; import 'package:peercoin/widgets/wallet/address_book/addresses_tab_watch_only.dart'; import 'package:peercoin/widgets/wallet/wallet_reset_bottom_sheet.dart'; import 'package:provider/provider.dart'; @@ -465,7 +466,10 @@ class _WalletHomeState extends State case 'transaction_signing': Navigator.of(context).pushNamed( Routes.walletTransactionSigning, - arguments: _wallet.name, + arguments: WalletSignTransactionArguments( + walletName: _wallet.name, + coinLetterCode: _wallet.letterCode, + ), ); break; default: diff --git a/lib/screens/wallet/wallet_sign_transaction.dart b/lib/screens/wallet/wallet_sign_transaction.dart index eeea657f..a8ddd117 100644 --- a/lib/screens/wallet/wallet_sign_transaction.dart +++ b/lib/screens/wallet/wallet_sign_transaction.dart @@ -13,6 +13,15 @@ import 'package:peercoin/widgets/double_tab_to_clipboard.dart'; import 'package:peercoin/widgets/service_container.dart'; import 'package:provider/provider.dart'; +class WalletSignTransactionArguments { + final String walletName; + final String coinLetterCode; + WalletSignTransactionArguments({ + required this.walletName, + required this.coinLetterCode, + }); +} + class WalletSignTransactionScreen extends StatefulWidget { const WalletSignTransactionScreen({super.key}); @@ -24,6 +33,7 @@ class WalletSignTransactionScreen extends StatefulWidget { class _WalletSignTransactionScreenState extends State { late String _walletName; + late String _coinLetterCode; late WalletProvider _walletProvider; bool _initial = true; String _signingError = ''; @@ -34,8 +44,12 @@ class _WalletSignTransactionScreenState @override void didChangeDependencies() { if (_initial == true) { - _walletName = ModalRoute.of(context)!.settings.arguments as String; + final args = ModalRoute.of(context)!.settings.arguments + as WalletSignTransactionArguments; _walletProvider = Provider.of(context); + _walletName = args.walletName; + _coinLetterCode = args.coinLetterCode; + setState(() { _initial = false; }); @@ -153,7 +167,7 @@ class _WalletSignTransactionScreenState decimalProduct: AvailableCoins.getDecimalProduct( identifier: _walletName, ), - coinLetterCode: "ppc", + coinLetterCode: _coinLetterCode, selectedInputs: _successfullySignedInputs, ), ); From 724614954ae17c3634df80904d3dbec0889f93c2 Mon Sep 17 00:00:00 2001 From: Willy Date: Mon, 20 May 2024 13:27:06 +0200 Subject: [PATCH 11/22] todos --- .../wallet_sign_transaction_confirmation.dart | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/screens/wallet/wallet_sign_transaction_confirmation.dart b/lib/screens/wallet/wallet_sign_transaction_confirmation.dart index 65cb76a5..cd6a5f33 100644 --- a/lib/screens/wallet/wallet_sign_transaction_confirmation.dart +++ b/lib/screens/wallet/wallet_sign_transaction_confirmation.dart @@ -2,6 +2,7 @@ import 'package:coinlib_flutter/coinlib_flutter.dart'; import 'package:flutter/material.dart'; import 'package:peercoin/screens/wallet/transaction_details.dart'; import 'package:peercoin/tools/app_localizations.dart'; +import 'package:peercoin/widgets/double_tab_to_clipboard.dart'; import 'package:peercoin/widgets/service_container.dart'; class WalletSignTransactionConfirmationArguments { @@ -45,6 +46,13 @@ class WalletSignTransactionConfirmationScreen extends StatelessWidget { ModalRoute.of(context)!.settings.arguments as WalletSignTransactionConfirmationArguments; final Transaction tx = arguments.tx; + print(tx.outputs.first.program!.script.asm); + // print( + // Address.fromString( + // hexToBytes("ff9296d92c5efc397d0e0b9ebe94d95a532270c4").toString(), + // Network.testnet), + // ); + final totalAmount = tx.outputs.map((e) => e.value).reduce((a, b) => a + b); final decimalProduct = arguments.decimalProduct; final selectedInputs = arguments.selectedInputs; @@ -124,10 +132,10 @@ class WalletSignTransactionConfirmationScreen extends StatelessWidget { const SizedBox( height: 20, ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [], - ), + DoubleTabToClipboard( + clipBoardData: tx.toHex(), + child: Text(tx.toHex()), + ) ], ), ), @@ -138,4 +146,5 @@ class WalletSignTransactionConfirmationScreen extends StatelessWidget { ), ); } + //TODO Show signed transaction inputs } From f04060d90914d1eec1b91385985ebaec0f4effaf Mon Sep 17 00:00:00 2001 From: Josh Edward Fairbank Date: Tue, 21 May 2024 07:57:21 +0000 Subject: [PATCH 12/22] Added translation using Weblate (English (Middle)) --- assets/translations/enm.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 assets/translations/enm.json diff --git a/assets/translations/enm.json b/assets/translations/enm.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/assets/translations/enm.json @@ -0,0 +1 @@ +{} From 245e66e846002a93a786a16b93252c55939319f0 Mon Sep 17 00:00:00 2001 From: Willy Date: Fri, 24 May 2024 08:31:01 +0200 Subject: [PATCH 13/22] chore: Update wallet sign transaction confirmation screen to include network information and recipient details --- .../wallet/wallet_sign_transaction.dart | 3 ++ .../wallet_sign_transaction_confirmation.dart | 23 ++++++++++----- lib/tools/address_from_asm.dart | 29 +++++++++++++++++++ 3 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 lib/tools/address_from_asm.dart diff --git a/lib/screens/wallet/wallet_sign_transaction.dart b/lib/screens/wallet/wallet_sign_transaction.dart index a8ddd117..ba709fe6 100644 --- a/lib/screens/wallet/wallet_sign_transaction.dart +++ b/lib/screens/wallet/wallet_sign_transaction.dart @@ -167,6 +167,9 @@ class _WalletSignTransactionScreenState decimalProduct: AvailableCoins.getDecimalProduct( identifier: _walletName, ), + network: AvailableCoins.getSpecificCoin( + _walletName, + ).networkType, coinLetterCode: _coinLetterCode, selectedInputs: _successfullySignedInputs, ), diff --git a/lib/screens/wallet/wallet_sign_transaction_confirmation.dart b/lib/screens/wallet/wallet_sign_transaction_confirmation.dart index cd6a5f33..17165c6a 100644 --- a/lib/screens/wallet/wallet_sign_transaction_confirmation.dart +++ b/lib/screens/wallet/wallet_sign_transaction_confirmation.dart @@ -1,6 +1,7 @@ import 'package:coinlib_flutter/coinlib_flutter.dart'; import 'package:flutter/material.dart'; import 'package:peercoin/screens/wallet/transaction_details.dart'; +import 'package:peercoin/tools/address_from_asm.dart'; import 'package:peercoin/tools/app_localizations.dart'; import 'package:peercoin/widgets/double_tab_to_clipboard.dart'; import 'package:peercoin/widgets/service_container.dart'; @@ -10,12 +11,14 @@ class WalletSignTransactionConfirmationArguments { List selectedInputs; int decimalProduct; String coinLetterCode; + Network network; WalletSignTransactionConfirmationArguments({ required this.tx, required this.selectedInputs, required this.decimalProduct, required this.coinLetterCode, + required this.network, }); } @@ -46,12 +49,18 @@ class WalletSignTransactionConfirmationScreen extends StatelessWidget { ModalRoute.of(context)!.settings.arguments as WalletSignTransactionConfirmationArguments; final Transaction tx = arguments.tx; - print(tx.outputs.first.program!.script.asm); - // print( - // Address.fromString( - // hexToBytes("ff9296d92c5efc397d0e0b9ebe94d95a532270c4").toString(), - // Network.testnet), - // ); + final Map recipients = tx.outputs + .map( + (e) => MapEntry( + GenericAddress.fromAsm(e.program!.script.asm, arguments.network) + .toString(), + e.value, + ), + ) + .fold>({}, (prev, element) { + prev[element.key] = element.value.toInt(); + return prev; + }); final totalAmount = tx.outputs.map((e) => e.value).reduce((a, b) => a + b); final decimalProduct = arguments.decimalProduct; @@ -123,7 +132,7 @@ class WalletSignTransactionConfirmationScreen extends StatelessWidget { style: const TextStyle(fontWeight: FontWeight.bold), ), ...renderRecipients( - recipients: {"asdf": 0}, + recipients: recipients, letterCode: coinLetterCode, decimalProduct: decimalProduct, ), diff --git a/lib/tools/address_from_asm.dart b/lib/tools/address_from_asm.dart new file mode 100644 index 00000000..8e5a2fa1 --- /dev/null +++ b/lib/tools/address_from_asm.dart @@ -0,0 +1,29 @@ +import 'package:coinlib_flutter/coinlib_flutter.dart'; + +class GenericAddress { + static Address fromAsm(String asm, Network network) { + final program = Program.fromAsm(asm); + if (program is P2PKH) { + return P2PKHAddress.fromHash( + program.pkHash, + version: network.p2pkhPrefix, + ); + } else if (program is P2SH) { + return P2SHAddress.fromHash( + program.scriptHash, + version: network.p2shPrefix, + ); + } else if (program is P2WPKH) { + return P2WPKHAddress.fromHash( + program.pkHash, + hrp: network.bech32Hrp, + ); + } else if (program is P2WSH) { + return P2WSHAddress.fromHash(program.scriptHash, hrp: network.bech32Hrp); + } else if (program is P2TR) { + throw Exception('P2TR not supported here'); + } else { + throw Exception('Unknown program type'); + } + } +} From c71a9bf5bd0cb90632833f44e8aa9850f70136bc Mon Sep 17 00:00:00 2001 From: Willy Date: Fri, 24 May 2024 08:40:05 +0200 Subject: [PATCH 14/22] chore: Refactor address_from_asm to generic_address and add tests --- .../wallet_sign_transaction_confirmation.dart | 2 +- ...ess_from_asm.dart => generic_address.dart} | 0 test/generic_address_test.dart | 32 +++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) rename lib/tools/{address_from_asm.dart => generic_address.dart} (100%) create mode 100644 test/generic_address_test.dart diff --git a/lib/screens/wallet/wallet_sign_transaction_confirmation.dart b/lib/screens/wallet/wallet_sign_transaction_confirmation.dart index 17165c6a..79337f83 100644 --- a/lib/screens/wallet/wallet_sign_transaction_confirmation.dart +++ b/lib/screens/wallet/wallet_sign_transaction_confirmation.dart @@ -1,7 +1,7 @@ import 'package:coinlib_flutter/coinlib_flutter.dart'; import 'package:flutter/material.dart'; import 'package:peercoin/screens/wallet/transaction_details.dart'; -import 'package:peercoin/tools/address_from_asm.dart'; +import 'package:peercoin/tools/generic_address.dart'; import 'package:peercoin/tools/app_localizations.dart'; import 'package:peercoin/widgets/double_tab_to_clipboard.dart'; import 'package:peercoin/widgets/service_container.dart'; diff --git a/lib/tools/address_from_asm.dart b/lib/tools/generic_address.dart similarity index 100% rename from lib/tools/address_from_asm.dart rename to lib/tools/generic_address.dart diff --git a/test/generic_address_test.dart b/test/generic_address_test.dart new file mode 100644 index 00000000..0c4b3ec4 --- /dev/null +++ b/test/generic_address_test.dart @@ -0,0 +1,32 @@ +import 'package:coinlib_flutter/coinlib_flutter.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:peercoin/tools/generic_address.dart'; + +void main() { + group('GenericAddress', () { + test('fromAsm - P2PKH', () { + const asm = + 'OP_DUP OP_HASH160 ff9296d92c5efc397d0e0b9ebe94d95a532270c4 OP_EQUALVERIFY OP_CHECKSIG'; + + final address = GenericAddress.fromAsm(asm, Network.testnet); + expect(address is P2PKHAddress, true); + expect(address.toString(), 'n4pJDAqsagWbouT7G7xRH8548s9pZpQwtG'); + }); + + test('fromAsm - P2SH', () { + const asm = + 'OP_HASH160 1123c89acd257e796c209f6f1914ed999f45076d OP_EQUAL'; + final address = GenericAddress.fromAsm(asm, Network.mainnet); + expect(address is P2SHAddress, true); + expect(address.toString(), 'p77CZFn9jvg9waCzKBzkQfSvBBzPH1nRre'); + }); + + test('fromAsm - Unknown program type', () { + const asm = 'OP_RETURN'; + expect( + () => GenericAddress.fromAsm(asm, Network.mainnet), throwsException); + }); + + //TODO - Implement P2WPKH, P2WSH and P2TR + }); +} From 4e704618c2580d66735e37f6304ee72f8f262e09 Mon Sep 17 00:00:00 2001 From: Willy Date: Fri, 24 May 2024 08:57:04 +0200 Subject: [PATCH 15/22] Refactor signing inputs in wallet_sign_transaction.dart to use index instead of input object --- .../wallet/wallet_sign_transaction.dart | 11 ++++--- .../wallet_sign_transaction_confirmation.dart | 31 +++++++++++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/lib/screens/wallet/wallet_sign_transaction.dart b/lib/screens/wallet/wallet_sign_transaction.dart index ba709fe6..ab90ab8d 100644 --- a/lib/screens/wallet/wallet_sign_transaction.dart +++ b/lib/screens/wallet/wallet_sign_transaction.dart @@ -135,13 +135,14 @@ class _WalletSignTransactionScreenState Transaction txToSign = tx; //try to sign all inputs - tx.inputs.mapIndexed((i, input) { + for (var i in tx.inputs) { + final index = tx.inputs.indexOf(i); try { txToSign = txToSign.sign( - inputN: i, + inputN: index, key: privKey, ); - _successfullySignedInputs.add(i); + _successfullySignedInputs.add(index); } catch (e) { LoggerWrapper.logError( 'WalletTransactionSigning', @@ -149,7 +150,7 @@ class _WalletSignTransactionScreenState 'failed to sign input $i: $e', ); } - }); + } final signedTx = txToSign.toHex(); LoggerWrapper.logInfo( @@ -163,7 +164,7 @@ class _WalletSignTransactionScreenState await Navigator.of(context).pushNamed( Routes.walletTransactionSigningConfirmation, arguments: WalletSignTransactionConfirmationArguments( - tx: tx, + tx: txToSign, decimalProduct: AvailableCoins.getDecimalProduct( identifier: _walletName, ), diff --git a/lib/screens/wallet/wallet_sign_transaction_confirmation.dart b/lib/screens/wallet/wallet_sign_transaction_confirmation.dart index 79337f83..e68b3c2c 100644 --- a/lib/screens/wallet/wallet_sign_transaction_confirmation.dart +++ b/lib/screens/wallet/wallet_sign_transaction_confirmation.dart @@ -43,6 +43,21 @@ class WalletSignTransactionConfirmationScreen extends StatelessWidget { return list; } + List renderInputs({ + required List selectedInputs, + required String letterCode, + required int decimalProduct, + }) { + List list = []; + + for (var input in selectedInputs) { + list.add( + Text(input.toString()), + ); + } + return list; + } + @override Widget build(BuildContext context) { final WalletSignTransactionConfirmationArguments arguments = @@ -123,6 +138,22 @@ class WalletSignTransactionConfirmationScreen extends StatelessWidget { ], ), const Divider(), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + AppLocalizations.instance + .translate('tx_recipients'), + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ...renderInputs( + selectedInputs: selectedInputs, + letterCode: coinLetterCode, + decimalProduct: decimalProduct, + ), + ], + ), + const Divider(), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ From f425a8816782516395371dab759d3d6b25519758 Mon Sep 17 00:00:00 2001 From: Willy Date: Fri, 24 May 2024 08:57:40 +0200 Subject: [PATCH 16/22] feat: Add handling for no signed inputs in WalletSignTransactionConfirmationScreen --- lib/screens/wallet/wallet_sign_transaction_confirmation.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/screens/wallet/wallet_sign_transaction_confirmation.dart b/lib/screens/wallet/wallet_sign_transaction_confirmation.dart index e68b3c2c..2c5c64a8 100644 --- a/lib/screens/wallet/wallet_sign_transaction_confirmation.dart +++ b/lib/screens/wallet/wallet_sign_transaction_confirmation.dart @@ -187,4 +187,5 @@ class WalletSignTransactionConfirmationScreen extends StatelessWidget { ); } //TODO Show signed transaction inputs + //TODO handle no signed inputs case } From 73fb56c229a964ddd69997deb73435582c60c083 Mon Sep 17 00:00:00 2001 From: Willy Date: Fri, 24 May 2024 21:25:52 +0200 Subject: [PATCH 17/22] Refactor P2TR address handling in generic_address.dart --- lib/tools/generic_address.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/tools/generic_address.dart b/lib/tools/generic_address.dart index 8e5a2fa1..bd686040 100644 --- a/lib/tools/generic_address.dart +++ b/lib/tools/generic_address.dart @@ -21,7 +21,10 @@ class GenericAddress { } else if (program is P2WSH) { return P2WSHAddress.fromHash(program.scriptHash, hrp: network.bech32Hrp); } else if (program is P2TR) { - throw Exception('P2TR not supported here'); + return P2TRAddress.fromTweakedKey( + program.tweakedKey, + hrp: network.bech32Hrp, + ); } else { throw Exception('Unknown program type'); } From dfaa73fb8134dfce41cab8540acb3059423a86f1 Mon Sep 17 00:00:00 2001 From: Willy Date: Fri, 24 May 2024 22:00:45 +0200 Subject: [PATCH 18/22] feat: Add transaction input signing status to confirmation screen --- assets/translations/en.json | 6 +- lib/screens/wallet/transaction_details.dart | 2 +- .../wallet_sign_transaction_confirmation.dart | 74 ++++++++++++------- 3 files changed, 55 insertions(+), 27 deletions(-) diff --git a/assets/translations/en.json b/assets/translations/en.json index 4df6e355..d2f08871 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -510,5 +510,9 @@ "sign_transaction_step_3_button_alt": "Copy hex to clipboard", "sign_transaction_step_3_description": "This is your signed transaction hex. You may double tap to copy it to the clipboard.", "sign_transaction_input_selector_title": "Select which inputs to sign", - "sign_transaction_signing_failed": "Transaction signing failed." + "sign_transaction_signing_failed": "Transaction signing failed.", + "sign_transaction_inputs": "Inputs", + "sign_transaction_confirmation_title": "Please review transaction", + "sign_transaction_confirmation_input_signed": "Signed", + "sign_transaction_confirmation_input_unsigned": "Not signed" } diff --git a/lib/screens/wallet/transaction_details.dart b/lib/screens/wallet/transaction_details.dart index 9629f588..8e36e76e 100644 --- a/lib/screens/wallet/transaction_details.dart +++ b/lib/screens/wallet/transaction_details.dart @@ -165,7 +165,7 @@ class TransactionDetails extends StatelessWidget { children: [ DoubleTabToClipboard( clipBoardData: tx.broadcastHex, - child: Text( + child: SelectableText( tx.broadcastHex, ), ), diff --git a/lib/screens/wallet/wallet_sign_transaction_confirmation.dart b/lib/screens/wallet/wallet_sign_transaction_confirmation.dart index 2c5c64a8..69f2a049 100644 --- a/lib/screens/wallet/wallet_sign_transaction_confirmation.dart +++ b/lib/screens/wallet/wallet_sign_transaction_confirmation.dart @@ -1,3 +1,4 @@ +import 'dart:typed_data'; import 'package:coinlib_flutter/coinlib_flutter.dart'; import 'package:flutter/material.dart'; import 'package:peercoin/screens/wallet/transaction_details.dart'; @@ -47,12 +48,43 @@ class WalletSignTransactionConfirmationScreen extends StatelessWidget { required List selectedInputs, required String letterCode, required int decimalProduct, + required Transaction tx, + required BuildContext context, }) { List list = []; for (var input in selectedInputs) { + final inputTxId = bytesToHex( + Uint8List.fromList(tx.inputs[input].prevOut.hash.reversed.toList()), + ); list.add( - Text(input.toString()), + Row( + key: Key(input.toString()), + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + flex: 2, + child: Text( + inputTxId, + style: const TextStyle( + fontSize: 13, + ), + overflow: TextOverflow.ellipsis, + ), + ), + Flexible( + child: Text( + selectedInputs.contains(input) ? 'Signed' : 'Not signed', + style: TextStyle( + fontWeight: FontWeight.bold, + color: selectedInputs.contains(input) + ? Theme.of(context).primaryColor + : Theme.of(context).colorScheme.error, + ), + ), + ), + ], + ), ); } return list; @@ -86,7 +118,8 @@ class WalletSignTransactionConfirmationScreen extends StatelessWidget { appBar: AppBar( centerTitle: true, title: Text( - AppLocalizations.instance.translate('send_confirm_transaction'), + AppLocalizations.instance + .translate('sign_transaction_confirmation_title'), ), ), body: Column( @@ -98,25 +131,6 @@ class WalletSignTransactionConfirmationScreen extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - AppLocalizations.instance.translate('tx_value'), - style: const TextStyle( - fontWeight: FontWeight.bold, - ), - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - SelectableText( - '${totalAmount.toInt() / decimalProduct} $coinLetterCode', - ), - ], - ), - ], - ), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -143,13 +157,15 @@ class WalletSignTransactionConfirmationScreen extends StatelessWidget { children: [ Text( AppLocalizations.instance - .translate('tx_recipients'), + .translate('sign_transaction_inputs'), style: const TextStyle(fontWeight: FontWeight.bold), ), ...renderInputs( selectedInputs: selectedInputs, letterCode: coinLetterCode, decimalProduct: decimalProduct, + tx: tx, + context: context, ), ], ), @@ -172,10 +188,19 @@ class WalletSignTransactionConfirmationScreen extends StatelessWidget { const SizedBox( height: 20, ), + const Divider(), + Text( + AppLocalizations.instance + .translate('sign_transaction_step_3_description'), + style: const TextStyle(fontWeight: FontWeight.bold), + ), + const SizedBox( + height: 20, + ), DoubleTabToClipboard( clipBoardData: tx.toHex(), - child: Text(tx.toHex()), - ) + child: SelectableText(tx.toHex()), + ), ], ), ), @@ -186,6 +211,5 @@ class WalletSignTransactionConfirmationScreen extends StatelessWidget { ), ); } - //TODO Show signed transaction inputs //TODO handle no signed inputs case } From 549256a8505b984ec6f6ead87251c8aa551e13d1 Mon Sep 17 00:00:00 2001 From: Willy Date: Fri, 24 May 2024 22:11:39 +0200 Subject: [PATCH 19/22] feat: Improve error handling for signing inputs in WalletSignTransactionScreenState --- .../wallet/wallet_sign_transaction.dart | 33 +++++++++++++++++-- .../wallet_sign_transaction_confirmation.dart | 1 - 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/lib/screens/wallet/wallet_sign_transaction.dart b/lib/screens/wallet/wallet_sign_transaction.dart index ab90ab8d..e65521fc 100644 --- a/lib/screens/wallet/wallet_sign_transaction.dart +++ b/lib/screens/wallet/wallet_sign_transaction.dart @@ -1,5 +1,6 @@ import 'package:coinlib_flutter/coinlib_flutter.dart'; import 'package:collection/collection.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:peercoin/models/available_coins.dart'; @@ -135,6 +136,7 @@ class _WalletSignTransactionScreenState Transaction txToSign = tx; //try to sign all inputs + String errorMessage = ''; for (var i in tx.inputs) { final index = tx.inputs.indexOf(i); try { @@ -149,16 +151,24 @@ class _WalletSignTransactionScreenState 'handleSign', 'failed to sign input $i: $e', ); + errorMessage = e.toString(); } } final signedTx = txToSign.toHex(); - LoggerWrapper.logInfo( 'WalletTransactionSigning', 'handleSign', 'tx produced $signedTx', ); + //if no inputs were signed, show error + if (_successfullySignedInputs.isEmpty) { + setState(() { + _signingError = errorMessage; + }); + return; + } + //show confirmation if (!mounted) return; await Navigator.of(context).pushNamed( @@ -175,6 +185,12 @@ class _WalletSignTransactionScreenState selectedInputs: _successfullySignedInputs, ), ); + + //reset state + setState(() { + _successfullySignedInputs.clear(); + _signingError = ''; + }); } catch (e) { LoggerWrapper.logError( 'WalletTransactionSigning', @@ -249,7 +265,10 @@ class _WalletSignTransactionScreenState } return false; }, - arguments: _walletName, + arguments: WalletSignTransactionArguments( + walletName: _walletName, + coinLetterCode: _coinLetterCode, + ), ); }, ), @@ -408,6 +427,16 @@ class _WalletSignTransactionScreenState ), ) : Container(), + if (kIsWeb) + const SizedBox( + height: 20, + ), + PeerButton( + text: AppLocalizations.instance + .translate('sign_reset_button'), + small: true, + action: () async => await _performReset(context), + ), ], ), ), diff --git a/lib/screens/wallet/wallet_sign_transaction_confirmation.dart b/lib/screens/wallet/wallet_sign_transaction_confirmation.dart index 69f2a049..48dd70f7 100644 --- a/lib/screens/wallet/wallet_sign_transaction_confirmation.dart +++ b/lib/screens/wallet/wallet_sign_transaction_confirmation.dart @@ -211,5 +211,4 @@ class WalletSignTransactionConfirmationScreen extends StatelessWidget { ), ); } - //TODO handle no signed inputs case } From 55d01ab96646e7a7dfa66657ce1f2f12f139c299 Mon Sep 17 00:00:00 2001 From: Willy Date: Fri, 24 May 2024 22:12:56 +0200 Subject: [PATCH 20/22] Refactor generic_address_test.dart to improve error handling for unknown program types in fromAsm method --- test/generic_address_test.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/generic_address_test.dart b/test/generic_address_test.dart index 0c4b3ec4..8fc77dad 100644 --- a/test/generic_address_test.dart +++ b/test/generic_address_test.dart @@ -24,7 +24,9 @@ void main() { test('fromAsm - Unknown program type', () { const asm = 'OP_RETURN'; expect( - () => GenericAddress.fromAsm(asm, Network.mainnet), throwsException); + () => GenericAddress.fromAsm(asm, Network.mainnet), + throwsException, + ); }); //TODO - Implement P2WPKH, P2WSH and P2TR From 9194b6fd1da47e8995c605aded3984c50225301c Mon Sep 17 00:00:00 2001 From: Willy Date: Fri, 24 May 2024 22:22:13 +0200 Subject: [PATCH 21/22] Refactor key_new.dart to improve transaction signing flow --- test_driver/key_new.dart | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/test_driver/key_new.dart b/test_driver/key_new.dart index af47caee..a08811fd 100644 --- a/test_driver/key_new.dart +++ b/test_driver/key_new.dart @@ -141,8 +141,6 @@ void main() { '0300000001d8af09713b116ecce194add86bd6def0e2dc3abe99c53bfbcd34576061baca9f000000002221022ef8df0bfd68434e2db934e88a7e30b06b88507dac60fa7cc2b732a1b5147ef7ffffffff010a8f9800000000001976a914ff9296d92c5efc397d0e0b9ebe94d95a532270c488ac00000000', ); await driver.tap(find.text('Sign')); - await driver.tap(find.text('Input 0')); - await driver.tap(find.text('Okay')); await driver.waitFor( find.text( '0300000001d8af09713b116ecce194add86bd6def0e2dc3abe99c53bfbcd34576061baca9f000000006a47304402200455cf81bde046213814387da5bde30e657fe7977c4c35ffe78edd3fe5cada7b0220186524598ac87de9b944f61e819b29c8a9a331c8a52b1694b8559cd9ec3395800121022ef8df0bfd68434e2db934e88a7e30b06b88507dac60fa7cc2b732a1b5147ef7ffffffff010a8f9800000000001976a914ff9296d92c5efc397d0e0b9ebe94d95a532270c488ac00000000', @@ -152,13 +150,8 @@ void main() { test('Transaction signing, fail', () async { await driver.tap(find.pageBack()); - await driver.tap(find.byTooltip('Transactions')); - await driver.tap(find.byTooltip('Show menu')); - await driver.runUnsynchronized( - () async { - await driver.tap(find.text('Sign Transaction')); - }, - ); + await driver.tap(find.text('Reset')); + await driver.tap(find.text('Reset')); //yes, twice to reset await driver.tap(find.text('Select')); await driver.tap(find.text('mm5pM9sJzVjsafctQJJrJuhGsw1CTucZ2v')); await driver.tap(find.pageBack()); From e311a0397b98c0bf80dbf968e4de564f424fc7fa Mon Sep 17 00:00:00 2001 From: Willy Date: Fri, 24 May 2024 22:24:46 +0200 Subject: [PATCH 22/22] chore: Update CHANGELOG.md with latest release date --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d4974c2..80b31f78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### **1.2.7** (2023-05-16) +### **1.2.7** (2023-05-24) - Various bug fixes and improvements related to flutter upgrade - Improved flow for transaction signing, now with confirmation and more feedback