diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 8a1bb7be5..040935cee 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -354,7 +354,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 12; + CURRENT_PROJECT_VERSION = 13; DEVELOPMENT_TEAM = 32J6BB6VUS; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -494,7 +494,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 12; + CURRENT_PROJECT_VERSION = 13; DEVELOPMENT_TEAM = 32J6BB6VUS; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -528,7 +528,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 12; + CURRENT_PROJECT_VERSION = 13; DEVELOPMENT_TEAM = 32J6BB6VUS; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( diff --git a/lib/bitcoin/bitcoin_address_record.dart b/lib/bitcoin/bitcoin_address_record.dart index 98cd1c9da..80ab750cf 100644 --- a/lib/bitcoin/bitcoin_address_record.dart +++ b/lib/bitcoin/bitcoin_address_record.dart @@ -1,19 +1,17 @@ import 'dart:convert'; class BitcoinAddressRecord { - BitcoinAddressRecord(this.address, {this.label, this.index}); + BitcoinAddressRecord(this.address, {this.index}); factory BitcoinAddressRecord.fromJSON(String jsonSource) { final decoded = json.decode(jsonSource) as Map; return BitcoinAddressRecord(decoded['address'] as String, - label: decoded['label'] as String, index: decoded['index'] as int); + index: decoded['index'] as int); } final String address; int index; - String label; - String toJSON() => - json.encode({'label': label, 'address': address, 'index': index}); + String toJSON() => json.encode({'address': address, 'index': index}); } diff --git a/lib/bitcoin/bitcoin_wallet.dart b/lib/bitcoin/bitcoin_wallet.dart index de5ef2119..223fb697b 100644 --- a/lib/bitcoin/bitcoin_wallet.dart +++ b/lib/bitcoin/bitcoin_wallet.dart @@ -167,21 +167,31 @@ abstract class BitcoinWalletBase extends WalletBase with Store { Map> _scripthashesUpdateSubject; Future init() async { - if (addresses.isEmpty) { - final index = 0; - addresses - .add(BitcoinAddressRecord(_getAddress(index: index), index: index)); + if (addresses.isEmpty || addresses.length < 33) { + final addressesCount = 33 - addresses.length; + await generateNewAddresses(addressesCount, startIndex: _accountIndex); } - address = addresses.first.address; + address = addresses[_accountIndex].address; transactionHistory.wallet = this; await transactionHistory.init(); } - Future generateNewAddress({String label}) async { + @action + void nextAddress() { + _accountIndex += 1; + + if (_accountIndex >= addresses.length) { + _accountIndex = 0; + } + + address = addresses[_accountIndex].address; + } + + Future generateNewAddress() async { _accountIndex += 1; final address = BitcoinAddressRecord(_getAddress(index: _accountIndex), - index: _accountIndex, label: label); + index: _accountIndex); addresses.add(address); await save(); @@ -189,13 +199,12 @@ abstract class BitcoinWalletBase extends WalletBase with Store { return address; } - Future> generateNewAddresses(int count) async { + Future> generateNewAddresses(int count, + {int startIndex = 0}) async { final list = []; - for (var i = 0; i < count; i++) { - _accountIndex += 1; - final address = BitcoinAddressRecord(_getAddress(index: _accountIndex), - index: _accountIndex, label: null); + for (var i = startIndex; i < count + startIndex; i++) { + final address = BitcoinAddressRecord(_getAddress(index: i), index: i); list.add(address); } @@ -205,10 +214,9 @@ abstract class BitcoinWalletBase extends WalletBase with Store { return list; } - Future updateAddress(String address, {String label}) async { + Future updateAddress(String address) async { for (final addr in addresses) { if (addr.address == address) { - addr.label = label; await save(); break; } @@ -368,7 +376,7 @@ abstract class BitcoinWalletBase extends WalletBase with Store { } @override - void close() async{ + void close() async { await eclient.close(); } diff --git a/lib/src/screens/dashboard/widgets/address_page.dart b/lib/src/screens/dashboard/widgets/address_page.dart index c3fb5ae7c..a14f485c9 100644 --- a/lib/src/screens/dashboard/widgets/address_page.dart +++ b/lib/src/screens/dashboard/widgets/address_page.dart @@ -1,68 +1,101 @@ +import 'package:cake_wallet/src/widgets/keyboard_done_button.dart'; +import 'package:cake_wallet/src/widgets/primary_button.dart'; import 'package:flutter/material.dart'; import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart'; import 'package:cake_wallet/src/screens/receive/widgets/qr_widget.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; +import 'package:keyboard_actions/keyboard_actions.dart'; class AddressPage extends StatelessWidget { - AddressPage({@required this.addressListViewModel}); + AddressPage({@required this.addressListViewModel}) + : _cryptoAmountFocus = FocusNode(); final WalletAddressListViewModel addressListViewModel; + final FocusNode _cryptoAmountFocus; + @override Widget build(BuildContext context) { - return Container( - padding: EdgeInsets.fromLTRB(24, 24, 24, 32), - child: Column( - children: [ - Expanded( - child: Center( - child: QRWidget(addressListViewModel: addressListViewModel), - )), - GestureDetector( - onTap: () => Navigator.of(context).pushNamed(Routes.receive), - child: Container( - height: 50, - padding: EdgeInsets.only(left: 24, right: 12), - alignment: Alignment.center, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(25)), - border: Border.all( - color: Theme.of(context).textTheme.subhead.color, - width: 1), - color: Theme.of(context).buttonColor), - child: Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Observer( - builder: (_) => Text( - addressListViewModel.hasAccounts - ? S.of(context).accounts_subaddresses - : S.of(context).addresses, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Theme.of(context) - .accentTextTheme - .display3 - .backgroundColor), - )), - Icon( - Icons.arrow_forward_ios, - size: 14, - color: Theme.of(context) - .accentTextTheme - .display3 - .backgroundColor, - ) - ], - ), - ), - ) - ], - ), - ); + return KeyboardActions( + config: KeyboardActionsConfig( + keyboardActionsPlatform: KeyboardActionsPlatform.IOS, + keyboardBarColor: + Theme.of(context).accentTextTheme.body2.backgroundColor, + nextFocus: false, + actions: [ + KeyboardActionsItem( + focusNode: _cryptoAmountFocus, + toolbarButtons: [(_) => KeyboardDoneButton()], + ) + ]), + child: Container( + height: 1, + padding: EdgeInsets.fromLTRB(24, 24, 24, 32), + child: Column( + children: [ + Expanded( + child: Center( + child: QRWidget( + addressListViewModel: addressListViewModel, + amountTextFieldFocusNode: _cryptoAmountFocus, + isAmountFieldShow: !addressListViewModel.hasAccounts), + )), + addressListViewModel.hasAddressList + ? GestureDetector( + onTap: () => + Navigator.of(context).pushNamed(Routes.receive), + child: Container( + height: 50, + padding: EdgeInsets.only(left: 24, right: 12), + alignment: Alignment.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(25)), + border: Border.all( + color: + Theme.of(context).textTheme.subhead.color, + width: 1), + color: Theme.of(context).buttonColor), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Observer( + builder: (_) => Text( + addressListViewModel.hasAccounts + ? S.of(context).accounts_subaddresses + : S.of(context).addresses, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Theme.of(context) + .accentTextTheme + .display3 + .backgroundColor), + )), + Icon( + Icons.arrow_forward_ios, + size: 14, + color: Theme.of(context) + .accentTextTheme + .display3 + .backgroundColor, + ) + ], + ), + ), + ) + : PrimaryButton( + onPressed: () => addressListViewModel.nextAddress(), + text: 'Next address', + color: Theme.of(context).buttonColor, + textColor: Theme.of(context) + .accentTextTheme + .display3 + .backgroundColor) + ], + ), + )); } } diff --git a/lib/view_model/wallet_address_list/wallet_address_edit_or_create_view_model.dart b/lib/view_model/wallet_address_list/wallet_address_edit_or_create_view_model.dart index dfec65d9a..b06a00e99 100644 --- a/lib/view_model/wallet_address_list/wallet_address_edit_or_create_view_model.dart +++ b/lib/view_model/wallet_address_list/wallet_address_edit_or_create_view_model.dart @@ -63,7 +63,7 @@ abstract class WalletAddressEditOrCreateViewModelBase with Store { final wallet = _wallet; if (wallet is BitcoinWallet) { - await wallet.generateNewAddress(label: label); + await wallet.generateNewAddress(); } if (wallet is MoneroWallet) { @@ -77,7 +77,7 @@ abstract class WalletAddressEditOrCreateViewModelBase with Store { final wallet = _wallet; if (wallet is BitcoinWallet) { - await wallet.updateAddress(_item.address as String, label: label); + await wallet.updateAddress(_item.address as String); } if (wallet is MoneroWallet) { diff --git a/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart b/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart index 4fc9a45b1..d9fd6f312 100644 --- a/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart +++ b/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart @@ -119,7 +119,7 @@ abstract class WalletAddressListViewModelBase with Store { return WalletAddressListItem( isPrimary: isPrimary, - name: addr.label, + name: null, address: addr.address); }); addressList.addAll(bitcoinAddresses); @@ -131,15 +131,6 @@ abstract class WalletAddressListViewModelBase with Store { @observable bool hasAccounts; - @observable - WalletBase _wallet; - - List _baseItems; - - AppStore _appStore; - - ReactionDisposer _onWalletChangeReaction; - @computed String get accountLabel { final wallet = _wallet; @@ -151,6 +142,18 @@ abstract class WalletAddressListViewModelBase with Store { return null; } + bool get hasAddressList => _wallet.type == WalletType.monero; + + @observable + WalletBase _wallet; + + List _baseItems; + + AppStore _appStore; + + ReactionDisposer _onWalletChangeReaction; + + @action void setAddress(WalletAddressListItem address) => _wallet.address = address.address; @@ -164,4 +167,13 @@ abstract class WalletAddressListViewModelBase with Store { _baseItems.add(WalletAddressListHeader()); } + + @action + void nextAddress() { + final wallet = _wallet; + + if (wallet is BitcoinWallet) { + wallet.nextAddress(); + } + } } diff --git a/pubspec.yaml b/pubspec.yaml index adfdf3db9..2a619159f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,7 +11,7 @@ description: Cake Wallet. # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 4.1.0+28 +version: 4.1.0+29 environment: sdk: ">=2.7.0 <3.0.0"