From 130e0b964246f26d6e83ab96a74655978801c900 Mon Sep 17 00:00:00 2001 From: Hanh Date: Wed, 4 Jan 2023 18:40:36 +0800 Subject: [PATCH] active account stored in db Fix Home page shortcuts --- lib/account_manager.dart | 4 +- lib/accounts.dart | 54 +++++++--------- lib/main.dart | 32 ++++------ lib/restore.dart | 1 - lib/send.dart | 33 ++++++---- lib/store.dart | 17 ++--- native/zcash-sync | 2 +- packages/warp_api_ffi/lib/warp_api.dart | 8 ++- .../warp_api_ffi/lib/warp_api_generated.dart | 64 +++++++++---------- pubspec.lock | 13 +--- pubspec.yaml | 4 +- smoke-test.md | 58 +++++++++++++++++ 12 files changed, 164 insertions(+), 126 deletions(-) create mode 100644 smoke-test.md diff --git a/lib/account_manager.dart b/lib/account_manager.dart index d07c1b7..a928ff2 100644 --- a/lib/account_manager.dart +++ b/lib/account_manager.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_svg/svg.dart'; import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:warp_api/warp_api.dart'; @@ -60,7 +59,7 @@ class AccountManagerState extends State { itemCount: _accounts.list.length, itemBuilder: (BuildContext context, int index) { final a = _accounts.list[index]; - final weight = settings.coins[a.coin].active == a.id ? FontWeight.bold : FontWeight.normal; + final weight = a.active ? FontWeight.bold : FontWeight.normal; final zbal = a.balance / ZECUNIT; final tbal = a.tbalance / ZECUNIT; final balance = zbal + tbal; @@ -165,7 +164,6 @@ class AccountManagerState extends State { _selectAccount(Account account) async { active.setActiveAccount(account.coin, account.id); - active.refreshAccount(); if (syncStatus.accountRestored) { syncStatus.setAccountRestored(false); final height = await rescanDialog(context); diff --git a/lib/accounts.dart b/lib/accounts.dart index 44c509a..a2c8ca1 100644 --- a/lib/accounts.dart +++ b/lib/accounts.dart @@ -6,9 +6,7 @@ import 'package:mobx/mobx.dart'; import 'db.dart'; import 'package:warp_api/warp_api.dart'; -import 'backup.dart'; import 'coin/coin.dart'; -import 'coin/zcash.dart'; import 'main.dart'; import 'store.dart'; @@ -19,6 +17,7 @@ class Account { final int id; final String name; final int balance; + bool active = false; int tbalance = 0; Account(this.coin, this.id, this.name, this.balance, this.tbalance); @@ -40,9 +39,14 @@ class AccountList { void refresh() { List _list = []; for (var coin in coins) { - _list.addAll(WarpApi.getAccountList(coin.coin).map((a) => Account( - coin.coin, a.id, a.name!, a.balance, 0) - )); + var accounts = WarpApi.getAccountList(coin.coin).map((a) => Account( + coin.coin, a.id, a.name!, a.balance, 0) + ).toList(); + final id = WarpApi.getActiveAccountId(coin.coin); + if (id != 0) { + accounts.firstWhere((a) => a.id == id).active = true; + } + _list.addAll(accounts); } list = _list; } @@ -66,15 +70,6 @@ class AccountList { refresh(); } - void saveActive(int coin, int id) { - settings.coins[coin].active = id; - Future.microtask(() async { - final prefs = await SharedPreferences.getInstance(); - final def = settings.coins[coin].def; - prefs.setInt("${def.ticker}.active", id); - }); - } - Account get(int coin, int id) => list.firstWhere((e) => e.coin == coin && e.id == id, orElse: () => emptyAccount); } @@ -139,17 +134,16 @@ abstract class _ActiveAccount with Store { } else if (aid != active.toId()) { setActiveAccount(aid.coin, aid.id); - refreshAccount(); } } AccountId? getAvailableId(AccountId aid) { - final nid = getAvailableIdForCoin(aid.coin, aid.id); + final nid = getActiveAccountId(aid.coin); if (nid.id != 0) return nid; for (var coin_data in settings.coins) { // look for an account in any other coin if (coin_data.coin != coin) { - final nid = getAvailableIdForCoin(coin_data.coin, coin_data.active); + final nid = getActiveAccountId(coin_data.coin); if (nid.id != 0) return nid; } @@ -158,30 +152,27 @@ abstract class _ActiveAccount with Store { return null; } - // check that the account still exists - // if not, pick any account - // if there are none, return 0 - AccountId getAvailableIdForCoin(int coin, int id) { - final newId = WarpApi.getAvailableAccountId(coin, id); - return AccountId(coin, newId); + AccountId getActiveAccountId(int coin) { + final id = WarpApi.getActiveAccountId(coin); + return AccountId(coin, id); } @action - void setActiveAccount(int _coin, int _id) { - coin = _coin; - id = _id; - + void setActiveAccount(int coin, int id) { + WarpApi.setActiveAccount(coin, id); Future.microtask(() async { final prefs = await SharedPreferences.getInstance(); prefs.setInt('coin', coin); prefs.setInt('account', id); }); - WarpApi.setActiveAccount(coin, id); + if (coin != this.coin || id != this.id) { + this.coin = coin; + this.id = id; + _refreshAccount(); + } } - @action - void refreshAccount() { - final dbr = DbReader(coin, id); + void _refreshAccount() { coinDef = settings.coins[coin].def; final accounts = AccountList(); @@ -221,7 +212,6 @@ abstract class _ActiveAccount with Store { @action void updateBalances() { - final dbr = DbReader(coin, id); final initialized = balances.initialized; final prevBalance = balances.balance; final b = WarpApi.getBalance(coin, id, syncStatus.confirmHeight); diff --git a/lib/main.dart b/lib/main.dart index 8dc3bb9..544eaa7 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -85,12 +85,11 @@ StreamSubscription? subUniLinks; void handleUri(BuildContext context, Uri uri) { final scheme = uri.scheme; final coinDef = settings.coins.firstWhere((c) => c.def.currency == scheme); - final id = settings.coins[coinDef.coin].active; - if (id != 0) { - active.setActiveAccount(coinDef.coin, id); - Navigator.of(context).pushNamed( - '/send', arguments: SendPageArgs(uri: uri.toString())); - } + final coin = coinDef.coin; + final id = WarpApi.getActiveAccountId(coin); + active.setActiveAccount(coin, id); + Navigator.of(context).pushNamed( + '/send', arguments: SendPageArgs(uri: uri.toString())); } Future initUniLinks(BuildContext context) async { @@ -112,18 +111,15 @@ void handleQuickAction(BuildContext context, String type) { final t = type.split("."); final coin = int.parse(t[0]); final shortcut = t[1]; - final a = settings.coins[coin].active; - - if (a != 0) { - active.setActiveAccount(coin, a); - switch (shortcut) { - case 'receive': - Navigator.of(context).pushNamed('/receive'); - break; - case 'send': - Navigator.of(context).pushNamed('/send'); - break; - } + final id = WarpApi.getActiveAccountId(coin); + active.setActiveAccount(coin, id); + switch (shortcut) { + case 'receive': + Navigator.of(context).pushNamed('/receive'); + break; + case 'send': + Navigator.of(context).pushNamed('/send'); + break; } } diff --git a/lib/restore.dart b/lib/restore.dart index 2235f4e..cb18f0e 100644 --- a/lib/restore.dart +++ b/lib/restore.dart @@ -188,7 +188,6 @@ class _AddAccountPageState extends State { ])); } else { active.setActiveAccount(_coin, account); - active.refreshAccount(); final nav = Navigator.of(context); if (_keyController.text != "") { syncStatus.setAccountRestored(true); diff --git a/lib/send.dart b/lib/send.dart index 10bdb33..711602e 100644 --- a/lib/send.dart +++ b/lib/send.dart @@ -89,25 +89,18 @@ class SendState extends State { final recipients = widget.args?.recipients ?? []; _usedBalance = recipients.fold(0, (acc, r) => acc + r.amount); + _newBlockAutorunDispose = autorun((_) { + syncStatus.latestHeight; + setState(() {}); + }); + Future.microtask(syncStatus.update); + final uri = widget.args?.uri; if (uri != null) Future.microtask(() { _setPaymentURI(uri); }); - active.updateBalances(); - final balances = active.balances; - final sBalance = balances.shieldedBalance; - final tBalance = active.tbalance; - final excludedBalance = balances.excludedBalance; - final underConfirmedBalance = balances.underConfirmedBalance; - int? unconfirmedBalance = unconfirmedBalanceStream.value; - _sBalance = sBalance; - _tBalance = tBalance; - _excludedBalance = excludedBalance; - _underConfirmedBalance = underConfirmedBalance; - _unconfirmedBalance = unconfirmedBalance ?? 0; - final templateIds = active.dbReader.loadTemplates(); _templates = templateIds; } @@ -139,8 +132,20 @@ class SendState extends State { _memoInitialized = true; } - var templates = _templates.map((t) => DropdownMenuItem(child: Text(t.title!), value: t)).toList(); + active.updateBalances(); + final balances = active.balances; + final sBalance = balances.shieldedBalance; + final tBalance = active.tbalance; + final excludedBalance = balances.excludedBalance; + final underConfirmedBalance = balances.underConfirmedBalance; + int? unconfirmedBalance = unconfirmedBalanceStream.value; + _sBalance = sBalance; + _tBalance = tBalance; + _excludedBalance = excludedBalance; + _underConfirmedBalance = underConfirmedBalance; + _unconfirmedBalance = unconfirmedBalance ?? 0; + var templates = _templates.map((t) => DropdownMenuItem(child: Text(t.title!), value: t)).toList(); final addReset = _template != null ? IconButton(onPressed: _resetTemplate, icon: Icon(Icons.close)) : IconButton(onPressed: _addTemplate, icon: Icon(Icons.add)); return Scaffold( diff --git a/lib/store.dart b/lib/store.dart index 904e18b..c49b659 100644 --- a/lib/store.dart +++ b/lib/store.dart @@ -97,7 +97,6 @@ class CoinData = _CoinData with _$CoinData; abstract class _CoinData with Store { final int coin; - int active = 0; int syncedHeight = 0; final CoinBase def; @observable bool contactsSaved = true; @@ -269,7 +268,6 @@ abstract class _Settings with Store { for (var c in coins) { final ticker = c.def.ticker; - c.active = prefs.getInt("$ticker.active") ?? 0; c.contactsSaved = prefs.getBool("$ticker.contacts_saved") ?? true; } @@ -1119,12 +1117,15 @@ class DecodedPaymentURI { } class SendPageArgs { - final bool isMulti; - final ContactT? contact; - final String? address; - final String? subject; - final String? uri; - final List recipients; + final bool isMulti; // use multi ... + final List recipients; // recipients + + final ContactT? contact; // send to contact + + final String? address; // reply to ... + final String? subject; // message + + final String? uri; // send to payment URI SendPageArgs({this.isMulti = false, this.contact, this.address, this.subject, this.uri, this.recipients = const[]}); } diff --git a/native/zcash-sync b/native/zcash-sync index 43c3484..b9726bf 160000 --- a/native/zcash-sync +++ b/native/zcash-sync @@ -1 +1 @@ -Subproject commit 43c348408b3f673be66863f92e61597e552cd8ce +Subproject commit b9726bf29323140f07732ea664fdc1f3447048d7 diff --git a/packages/warp_api_ffi/lib/warp_api.dart b/packages/warp_api_ffi/lib/warp_api.dart index 27a890d..7f23a76 100644 --- a/packages/warp_api_ffi/lib/warp_api.dart +++ b/packages/warp_api_ffi/lib/warp_api.dart @@ -426,8 +426,12 @@ class WarpApi { return AccountVec(r).accounts!; } - static int getAvailableAccountId(int coin, int id) { - return unwrapResultU32(warp_api_lib.get_available_account_id(coin, id)); + static int getActiveAccountId(int coin) { + return unwrapResultU32(warp_api_lib.get_active_account(coin)); + } + + static void setActiveAccountId(int coin, int id) { + unwrapResultU8(warp_api_lib.set_active_account(coin, id)); } static String getTAddr(int coin, int id) { diff --git a/packages/warp_api_ffi/lib/warp_api_generated.dart b/packages/warp_api_ffi/lib/warp_api_generated.dart index 54a9549..e08dc3b 100644 --- a/packages/warp_api_ffi/lib/warp_api_generated.dart +++ b/packages/warp_api_ffi/lib/warp_api_generated.dart @@ -124,21 +124,6 @@ class NativeLibrary { late final _dart_set_active _set_active = _set_active_ptr.asFunction<_dart_set_active>(); - void set_active_account( - int coin, - int id, - ) { - return _set_active_account( - coin, - id, - ); - } - - late final _set_active_account_ptr = - _lookup>('set_active_account'); - late final _dart_set_active_account _set_active_account = - _set_active_account_ptr.asFunction<_dart_set_active_account>(); - void set_coin_lwd_url( int coin, ffi.Pointer lwd_url, @@ -920,22 +905,33 @@ class NativeLibrary { late final _dart_get_account_list _get_account_list = _get_account_list_ptr.asFunction<_dart_get_account_list>(); - CResult_u32 get_available_account_id( + CResult_u32 get_active_account( + int coin, + ) { + return _get_active_account( + coin, + ); + } + + late final _get_active_account_ptr = + _lookup>('get_active_account'); + late final _dart_get_active_account _get_active_account = + _get_active_account_ptr.asFunction<_dart_get_active_account>(); + + CResult_u8 set_active_account( int coin, int id, ) { - return _get_available_account_id( + return _set_active_account( coin, id, ); } - late final _get_available_account_id_ptr = - _lookup>( - 'get_available_account_id'); - late final _dart_get_available_account_id _get_available_account_id = - _get_available_account_id_ptr - .asFunction<_dart_get_available_account_id>(); + late final _set_active_account_ptr = + _lookup>('set_active_account'); + late final _dart_set_active_account _set_active_account = + _set_active_account_ptr.asFunction<_dart_set_active_account>(); CResult_____c_char get_t_addr( int coin, @@ -1462,16 +1458,6 @@ typedef _dart_set_active = void Function( int active, ); -typedef _c_set_active_account = ffi.Void Function( - ffi.Uint8 coin, - ffi.Uint32 id, -); - -typedef _dart_set_active_account = void Function( - int coin, - int id, -); - typedef _c_set_coin_lwd_url = ffi.Void Function( ffi.Uint8 coin, ffi.Pointer lwd_url, @@ -1984,12 +1970,20 @@ typedef _dart_get_account_list = CResult______u8 Function( int coin, ); -typedef _c_get_available_account_id = CResult_u32 Function( +typedef _c_get_active_account = CResult_u32 Function( + ffi.Uint8 coin, +); + +typedef _dart_get_active_account = CResult_u32 Function( + int coin, +); + +typedef _c_set_active_account = CResult_u8 Function( ffi.Uint8 coin, ffi.Uint32 id, ); -typedef _dart_get_available_account_id = CResult_u32 Function( +typedef _dart_set_active_account = CResult_u8 Function( int coin, int id, ); diff --git a/pubspec.lock b/pubspec.lock index e804e56..c13502f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1085,21 +1085,14 @@ packages: name: sensors_plus url: "https://pub.dartlang.org" source: hosted - version: "1.3.1" + version: "2.0.1" sensors_plus_platform_interface: dependency: transitive description: name: sensors_plus_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" - sensors_plus_web: - dependency: transitive - description: - name: sensors_plus_web - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" + version: "1.1.3" share_plus: dependency: "direct main" description: @@ -1464,4 +1457,4 @@ packages: version: "3.1.1" sdks: dart: ">=2.18.0 <3.0.0" - flutter: ">=2.10.0" + flutter: ">=2.11.0" diff --git a/pubspec.yaml b/pubspec.yaml index 155fa9a..fed6e36 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # 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: 1.2.17+344 +version: 1.2.17+345 environment: sdk: ">=2.12.0 <3.0.0" @@ -64,7 +64,7 @@ dependencies: ref: c2c79def4f7fa8c17e9432ca43d307ba0b4a75a3 flutter_speed_dial: ^5.0.0 currency_text_input_formatter: ^2.1.2 - sensors_plus: ^1.1.0 + sensors_plus: ^2.0.0 connectivity_plus: ^2.2.1 uni_links: ^0.5.1 quick_actions: ^0.6.0 diff --git a/smoke-test.md b/smoke-test.md new file mode 100644 index 0000000..619bc92 --- /dev/null +++ b/smoke-test.md @@ -0,0 +1,58 @@ +# Send YEC & ZEC +- Address: Contact, account, address or QR code +- Amount in coin & fiat +- Max button +- Slider +- Checkbox "include fee" +- Memo + - Subject + - Body + - Reply-To +- Send Templates + +# Execution Plan + - t2t, t2z, z2t, z2z + +# Receive +- Payment URI + - T, Z, O address types + - Amount & Memo +- Diversified Address +- Copy address to clipboard + +# Transparent Account +- Override derivation path +- Shield + +# Synchronization +- Recan by date & height + +# Accounts +- New, Edit, Delete +- Select default +- Import seed phrase, sk, vk + +# Backup +- Backup data +- Save/Load full backup +- Convert to Watchonly + +# Contacts +- New, Edit, Delete +- Save to Blockchain + +# Settings +- Fiat currency +- number of confirmations + +# Desktop integrations +- Send/Receive +- QR code reader + +# Cold Wallet +- by QR +- by File +- Broadcast + +# Derivation Tool +