Fixes for backups for Android. Fixes for send almost all amount.

M committed Jan 29, 2021 at 22:18 UTC 2ce34919bfb18443c30db1baae285e4f3c4b7278
10 files changed +60 -21
android/app/build.gradle
+1 -1
@@ -31,7 +31,7 @@ if (keystorePropertiesFile.exists()) {
31 }
32
33 android {
34 - compileSdkVersion 28
34 + compileSdkVersion 29
35
36 lintOptions {
37 disable 'InvalidPackage'
android/app/src/main/AndroidManifest.xml
+3 -1
@@ -4,12 +4,14 @@
4 <uses-permission android:name="android.permission.INTERNET"/>
5 <uses-permission android:name="android.permission.USE_FINGERPRINT"/>
6 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
7 + <uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
8
9 <application
10 android:label="Cake Wallet"
11 android:allowBackup="false"
12 android:fullBackupContent="false"
12 - android:icon="@mipmap/ic_launcher">
13 + android:icon="@mipmap/ic_launcher"
14 + android:requestLegacyExternalStorage="true">
15 <activity
16 android:name=".MainActivity"
17 android:launchMode="singleTop"
ios/Podfile.lock
+6
@@ -72,6 +72,8 @@ PODS:
72 - Flutter
73 - path_provider (0.0.1):
74 - Flutter
75 + - "permission_handler (5.0.1+1)":
76 + - Flutter
77 - Reachability (3.2)
78 - SDWebImage (5.9.1):
79 - SDWebImage/Core (= 5.9.1)
@@ -98,6 +100,7 @@ DEPENDENCIES:
100 - local_auth (from `.symlinks/plugins/local_auth/ios`)
101 - package_info (from `.symlinks/plugins/package_info/ios`)
102 - path_provider (from `.symlinks/plugins/path_provider/ios`)
103 + - permission_handler (from `.symlinks/plugins/permission_handler/ios`)
104 - share (from `.symlinks/plugins/share/ios`)
105 - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
106 - url_launcher (from `.symlinks/plugins/url_launcher/ios`)
@@ -136,6 +139,8 @@ EXTERNAL SOURCES:
139 :path: ".symlinks/plugins/package_info/ios"
140 path_provider:
141 :path: ".symlinks/plugins/path_provider/ios"
142 + permission_handler:
143 + :path: ".symlinks/plugins/permission_handler/ios"
144 share:
145 :path: ".symlinks/plugins/share/ios"
146 shared_preferences:
@@ -159,6 +164,7 @@ SPEC CHECKSUMS:
164 MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
165 package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
166 path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
167 + permission_handler: eac8e15b4a1a3fba55b761d19f3f4e6b005d15b6
168 Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
169 SDWebImage: a990c053fff71e388a10f3357edb0be17929c9c5
170 share: 0b2c3e82132f5888bccca3351c504d0003b3b410
lib/bitcoin/bitcoin_wallet.dart
+14 -7
@@ -261,14 +261,20 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
261 @override
262 Future<PendingBitcoinTransaction> createTransaction(
263 Object credentials) async {
264 + const minAmount = 546;
265 final transactionCredentials = credentials as BitcoinTransactionCredentials;
266 final inputs = <BitcoinUnspent>[];
267 final allAmountFee =
268 calculateEstimatedFee(transactionCredentials.priority, null);
269 + final allAmount = balance.confirmed - allAmountFee;
270 var fee = 0;
269 - final amount = transactionCredentials.amount != null
271 + final credentialsAmount = transactionCredentials.amount != null
272 ? stringDoubleToBitcoinAmount(transactionCredentials.amount)
271 - : balance.confirmed - allAmountFee;
273 + : 0;
274 + final amount = transactionCredentials.amount == null ||
275 + allAmount - credentialsAmount < minAmount
276 + ? allAmount
277 + : credentialsAmount;
278 final txb = bitcoin.TransactionBuilder(network: bitcoin.bitcoin);
279 final changeAddress = address;
280 var leftAmount = amount;
@@ -294,8 +300,8 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
300
301 final totalAmount = amount + fee;
302 fee = transactionCredentials.amount != null
297 - ? feeAmountForPriority(
298 - transactionCredentials.priority, inputs.length, 2)
303 + ? feeAmountForPriority(transactionCredentials.priority, inputs.length,
304 + amount == allAmount ? 1 : 2)
305 : allAmountFee;
306
307 if (totalAmount > balance.confirmed) {
@@ -329,7 +335,7 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
335 final feeAmount = transactionCredentials.priority.rate * estimatedSize;
336 final changeValue = totalInputAmount - amount - feeAmount;
337
332 - if (changeValue > 0) {
338 + if (changeValue > minAmount) {
339 txb.addOutput(changeAddress, changeValue);
340 }
341
@@ -375,8 +381,9 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
381 } else {
382 inputsCount = _unspent.length;
383 }
378 -
379 - return feeAmountForPriority(priority, inputsCount, 2);
384 + // If send all, then we have no change value
385 + return feeAmountForPriority(
386 + priority, inputsCount, amount != null ? 2 : 1);
387 }
388
389 return 0;
lib/src/screens/backup/backup_page.dart
+9 -3
@@ -14,6 +14,7 @@ import 'package:cake_wallet/utils/show_pop_up.dart';
14 import 'package:cake_wallet/view_model/backup_view_model.dart';
15 import 'package:cake_wallet/core/execution_state.dart';
16 import 'package:cake_wallet/src/screens/base_page.dart';
17 +import 'package:permission_handler/permission_handler.dart';
18
19 class BackupPage extends BasePage {
20 BackupPage(this.backupViewModelBase);
@@ -99,8 +100,6 @@ class BackupPage extends BasePage {
100 actionRightButton: () async {
101 Navigator.of(dialogContext).pop();
102 final backup = await backupViewModelBase.exportBackup();
102 - await backupViewModelBase.saveToDownload(
103 - backup.name, backup.content);
103
104 if (Platform.isAndroid) {
105 onExportAndroid(context, backup);
@@ -123,9 +122,16 @@ class BackupPage extends BasePage {
122 rightButtonText: 'Save to Downloads',
123 leftButtonText: 'Share',
124 actionRightButton: () async {
126 - Navigator.of(dialogContext).pop();
125 + final permission = await Permission.storage.request();
126 +
127 + if (permission.isDenied) {
128 + Navigator.of(dialogContext).pop();
129 + return;
130 + }
131 +
132 await backupViewModelBase.saveToDownload(
133 backup.name, backup.content);
134 + Navigator.of(dialogContext).pop();
135 },
136 actionLeftButton: () {
137 Navigator.of(dialogContext).pop();
lib/src/screens/exchange_trade/exchange_trade_page.dart
+6 -6
@@ -255,11 +255,11 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
255 .pendingTransaction.feeFormatted,
256 rightButtonText: S.of(context).ok,
257 leftButtonText: S.of(context).cancel,
258 - actionRightButton: () {
258 + actionRightButton: () async {
259 Navigator.of(context).pop();
260 - widget.exchangeTradeViewModel.sendViewModel
260 + await widget.exchangeTradeViewModel.sendViewModel
261 .commitTransaction();
262 - showPopUp<void>(
262 + await showPopUp<void>(
263 context: context,
264 builder: (BuildContext context) {
265 return Observer(builder: (_) {
@@ -359,10 +359,10 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
359 });
360 },
361 actionLeftButton: () => Navigator.of(context).pop(),
362 - feeFiatAmount: widget.exchangeTradeViewModel.sendViewModel
363 - .pendingTransaction.feeFormatted,
362 + feeFiatAmount: widget.exchangeTradeViewModel.sendViewModel.pendingTransactionFeeFiatAmount
363 + + ' ' + widget.exchangeTradeViewModel.sendViewModel.fiat.title,
364 fiatAmountValue: widget.exchangeTradeViewModel.sendViewModel
365 - .pendingTransactionFeeFiatAmount +
365 + .pendingTransactionFiatAmount +
366 ' ' +
367 widget.exchangeTradeViewModel.sendViewModel.fiat.title,
368 recipientTitle: S.of(context).recipient_address,
lib/view_model/backup_view_model.dart
+4 -2
@@ -1,5 +1,4 @@
1 import 'dart:io';
2 -
2 import 'package:cake_wallet/core/backup_service.dart';
3 import 'package:cake_wallet/core/execution_state.dart';
4 import 'package:cake_wallet/entities/secret_store_key.dart';
@@ -7,6 +6,7 @@ import 'package:cake_wallet/store/secret_store.dart';
6 import 'package:flutter/foundation.dart';
7 import 'package:flutter_secure_storage/flutter_secure_storage.dart';
8 import 'package:mobx/mobx.dart';
9 +import 'package:intl/intl.dart';
10
11 part 'backup_view_model.g.dart';
12
@@ -56,9 +56,11 @@ abstract class BackupViewModelBase with Store {
56 state = IsExecutingState();
57 final backupContent = await backupService.exportBackup(backupPassword);
58 state = ExecutedSuccessfullyState();
59 + final now = DateTime.now();
60 + final formatter = DateFormat('yyyy-MM-dd_Hm');
61
62 return BackupExportFile(backupContent.toList(),
61 - name: 'backup_${DateTime.now().toString()}.zip');
63 + name: 'cake_wallet_backup_${formatter.format(now)}');
64 } catch (e) {
65 print(e.toString());
66 state = FailureState(e.toString());
lib/view_model/send/send_view_model.dart
+1
@@ -167,6 +167,7 @@ abstract class SendViewModelBase with Store {
167
168 Validator get templateValidator => TemplateValidator();
169
170 + @observable
171 PendingTransaction pendingTransaction;
172
173 @computed
pubspec.lock
+14
@@ -695,6 +695,20 @@ packages:
695 url: "https://pub.dartlang.org"
696 source: hosted
697 version: "1.9.2"
698 + permission_handler:
699 + dependency: "direct main"
700 + description:
701 + name: permission_handler
702 + url: "https://pub.dartlang.org"
703 + source: hosted
704 + version: "5.0.1+1"
705 + permission_handler_platform_interface:
706 + dependency: transitive
707 + description:
708 + name: permission_handler_platform_interface
709 + url: "https://pub.dartlang.org"
710 + source: hosted
711 + version: "2.0.1"
712 petitparser:
713 dependency: transitive
714 description:
pubspec.yaml
+2 -1
@@ -11,7 +11,7 @@ description: Cake Wallet.
11 # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
12 # Read more about iOS versioning at
13 # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
14 -version: 4.1.0+37
14 +version: 4.1.0+38
15
16 environment:
17 sdk: ">=2.7.0 <3.0.0"
@@ -72,6 +72,7 @@ dependencies:
72 cryptography: ^1.4.0
73 file_picker: ^2.1.4
74 unorm_dart: ^0.1.2
75 + permission_handler: ^5.0.1+1
76
77 dev_dependencies:
78 flutter_test: