active account stored in db

Fix Home page shortcuts
This commit is contained in:
Hanh 2023-01-04 18:40:36 +08:00
parent 6b7045934a
commit 130e0b9642
12 changed files with 164 additions and 126 deletions

View File

@ -1,5 +1,4 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:flutter_speed_dial/flutter_speed_dial.dart';
import 'package:warp_api/warp_api.dart'; import 'package:warp_api/warp_api.dart';
@ -60,7 +59,7 @@ class AccountManagerState extends State<AccountManagerPage> {
itemCount: _accounts.list.length, itemCount: _accounts.list.length,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
final a = _accounts.list[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 zbal = a.balance / ZECUNIT;
final tbal = a.tbalance / ZECUNIT; final tbal = a.tbalance / ZECUNIT;
final balance = zbal + tbal; final balance = zbal + tbal;
@ -165,7 +164,6 @@ class AccountManagerState extends State<AccountManagerPage> {
_selectAccount(Account account) async { _selectAccount(Account account) async {
active.setActiveAccount(account.coin, account.id); active.setActiveAccount(account.coin, account.id);
active.refreshAccount();
if (syncStatus.accountRestored) { if (syncStatus.accountRestored) {
syncStatus.setAccountRestored(false); syncStatus.setAccountRestored(false);
final height = await rescanDialog(context); final height = await rescanDialog(context);

View File

@ -6,9 +6,7 @@ import 'package:mobx/mobx.dart';
import 'db.dart'; import 'db.dart';
import 'package:warp_api/warp_api.dart'; import 'package:warp_api/warp_api.dart';
import 'backup.dart';
import 'coin/coin.dart'; import 'coin/coin.dart';
import 'coin/zcash.dart';
import 'main.dart'; import 'main.dart';
import 'store.dart'; import 'store.dart';
@ -19,6 +17,7 @@ class Account {
final int id; final int id;
final String name; final String name;
final int balance; final int balance;
bool active = false;
int tbalance = 0; int tbalance = 0;
Account(this.coin, this.id, this.name, this.balance, this.tbalance); Account(this.coin, this.id, this.name, this.balance, this.tbalance);
@ -40,9 +39,14 @@ class AccountList {
void refresh() { void refresh() {
List<Account> _list = []; List<Account> _list = [];
for (var coin in coins) { for (var coin in coins) {
_list.addAll(WarpApi.getAccountList(coin.coin).map((a) => Account( var accounts = WarpApi.getAccountList(coin.coin).map((a) => Account(
coin.coin, a.id, a.name!, a.balance, 0) 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; list = _list;
} }
@ -66,15 +70,6 @@ class AccountList {
refresh(); 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); 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()) { else if (aid != active.toId()) {
setActiveAccount(aid.coin, aid.id); setActiveAccount(aid.coin, aid.id);
refreshAccount();
} }
} }
AccountId? getAvailableId(AccountId aid) { AccountId? getAvailableId(AccountId aid) {
final nid = getAvailableIdForCoin(aid.coin, aid.id); final nid = getActiveAccountId(aid.coin);
if (nid.id != 0) return nid; if (nid.id != 0) return nid;
for (var coin_data in settings.coins) { for (var coin_data in settings.coins) {
// look for an account in any other coin // look for an account in any other coin
if (coin_data.coin != 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) if (nid.id != 0)
return nid; return nid;
} }
@ -158,30 +152,27 @@ abstract class _ActiveAccount with Store {
return null; return null;
} }
// check that the account still exists AccountId getActiveAccountId(int coin) {
// if not, pick any account final id = WarpApi.getActiveAccountId(coin);
// if there are none, return 0 return AccountId(coin, id);
AccountId getAvailableIdForCoin(int coin, int id) {
final newId = WarpApi.getAvailableAccountId(coin, id);
return AccountId(coin, newId);
} }
@action @action
void setActiveAccount(int _coin, int _id) { void setActiveAccount(int coin, int id) {
coin = _coin; WarpApi.setActiveAccount(coin, id);
id = _id;
Future.microtask(() async { Future.microtask(() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
prefs.setInt('coin', coin); prefs.setInt('coin', coin);
prefs.setInt('account', id); 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() {
void refreshAccount() {
final dbr = DbReader(coin, id);
coinDef = settings.coins[coin].def; coinDef = settings.coins[coin].def;
final accounts = AccountList(); final accounts = AccountList();
@ -221,7 +212,6 @@ abstract class _ActiveAccount with Store {
@action @action
void updateBalances() { void updateBalances() {
final dbr = DbReader(coin, id);
final initialized = balances.initialized; final initialized = balances.initialized;
final prevBalance = balances.balance; final prevBalance = balances.balance;
final b = WarpApi.getBalance(coin, id, syncStatus.confirmHeight); final b = WarpApi.getBalance(coin, id, syncStatus.confirmHeight);

View File

@ -85,12 +85,11 @@ StreamSubscription? subUniLinks;
void handleUri(BuildContext context, Uri uri) { void handleUri(BuildContext context, Uri uri) {
final scheme = uri.scheme; final scheme = uri.scheme;
final coinDef = settings.coins.firstWhere((c) => c.def.currency == scheme); final coinDef = settings.coins.firstWhere((c) => c.def.currency == scheme);
final id = settings.coins[coinDef.coin].active; final coin = coinDef.coin;
if (id != 0) { final id = WarpApi.getActiveAccountId(coin);
active.setActiveAccount(coinDef.coin, id); active.setActiveAccount(coin, id);
Navigator.of(context).pushNamed( Navigator.of(context).pushNamed(
'/send', arguments: SendPageArgs(uri: uri.toString())); '/send', arguments: SendPageArgs(uri: uri.toString()));
}
} }
Future<void> initUniLinks(BuildContext context) async { Future<void> initUniLinks(BuildContext context) async {
@ -112,18 +111,15 @@ void handleQuickAction(BuildContext context, String type) {
final t = type.split("."); final t = type.split(".");
final coin = int.parse(t[0]); final coin = int.parse(t[0]);
final shortcut = t[1]; final shortcut = t[1];
final a = settings.coins[coin].active; final id = WarpApi.getActiveAccountId(coin);
active.setActiveAccount(coin, id);
if (a != 0) { switch (shortcut) {
active.setActiveAccount(coin, a); case 'receive':
switch (shortcut) { Navigator.of(context).pushNamed('/receive');
case 'receive': break;
Navigator.of(context).pushNamed('/receive'); case 'send':
break; Navigator.of(context).pushNamed('/send');
case 'send': break;
Navigator.of(context).pushNamed('/send');
break;
}
} }
} }

View File

@ -188,7 +188,6 @@ class _AddAccountPageState extends State<AddAccountPage> {
])); ]));
} else { } else {
active.setActiveAccount(_coin, account); active.setActiveAccount(_coin, account);
active.refreshAccount();
final nav = Navigator.of(context); final nav = Navigator.of(context);
if (_keyController.text != "") { if (_keyController.text != "") {
syncStatus.setAccountRestored(true); syncStatus.setAccountRestored(true);

View File

@ -89,25 +89,18 @@ class SendState extends State<SendPage> {
final recipients = widget.args?.recipients ?? []; final recipients = widget.args?.recipients ?? [];
_usedBalance = recipients.fold(0, (acc, r) => acc + r.amount); _usedBalance = recipients.fold(0, (acc, r) => acc + r.amount);
_newBlockAutorunDispose = autorun((_) {
syncStatus.latestHeight;
setState(() {});
});
Future.microtask(syncStatus.update);
final uri = widget.args?.uri; final uri = widget.args?.uri;
if (uri != null) if (uri != null)
Future.microtask(() { Future.microtask(() {
_setPaymentURI(uri); _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(); final templateIds = active.dbReader.loadTemplates();
_templates = templateIds; _templates = templateIds;
} }
@ -139,8 +132,20 @@ class SendState extends State<SendPage> {
_memoInitialized = true; _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)); final addReset = _template != null ? IconButton(onPressed: _resetTemplate, icon: Icon(Icons.close)) : IconButton(onPressed: _addTemplate, icon: Icon(Icons.add));
return Scaffold( return Scaffold(

View File

@ -97,7 +97,6 @@ class CoinData = _CoinData with _$CoinData;
abstract class _CoinData with Store { abstract class _CoinData with Store {
final int coin; final int coin;
int active = 0;
int syncedHeight = 0; int syncedHeight = 0;
final CoinBase def; final CoinBase def;
@observable bool contactsSaved = true; @observable bool contactsSaved = true;
@ -269,7 +268,6 @@ abstract class _Settings with Store {
for (var c in coins) { for (var c in coins) {
final ticker = c.def.ticker; final ticker = c.def.ticker;
c.active = prefs.getInt("$ticker.active") ?? 0;
c.contactsSaved = prefs.getBool("$ticker.contacts_saved") ?? true; c.contactsSaved = prefs.getBool("$ticker.contacts_saved") ?? true;
} }
@ -1119,12 +1117,15 @@ class DecodedPaymentURI {
} }
class SendPageArgs { class SendPageArgs {
final bool isMulti; final bool isMulti; // use multi ...
final ContactT? contact; final List<Recipient> recipients; // recipients
final String? address;
final String? subject; final ContactT? contact; // send to contact
final String? uri;
final List<Recipient> recipients; 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[]}); SendPageArgs({this.isMulti = false, this.contact, this.address, this.subject, this.uri, this.recipients = const[]});
} }

@ -1 +1 @@
Subproject commit 43c348408b3f673be66863f92e61597e552cd8ce Subproject commit b9726bf29323140f07732ea664fdc1f3447048d7

View File

@ -426,8 +426,12 @@ class WarpApi {
return AccountVec(r).accounts!; return AccountVec(r).accounts!;
} }
static int getAvailableAccountId(int coin, int id) { static int getActiveAccountId(int coin) {
return unwrapResultU32(warp_api_lib.get_available_account_id(coin, id)); 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) { static String getTAddr(int coin, int id) {

View File

@ -124,21 +124,6 @@ class NativeLibrary {
late final _dart_set_active _set_active = late final _dart_set_active _set_active =
_set_active_ptr.asFunction<_dart_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<ffi.NativeFunction<_c_set_active_account>>('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( void set_coin_lwd_url(
int coin, int coin,
ffi.Pointer<ffi.Int8> lwd_url, ffi.Pointer<ffi.Int8> lwd_url,
@ -920,22 +905,33 @@ class NativeLibrary {
late final _dart_get_account_list _get_account_list = late final _dart_get_account_list _get_account_list =
_get_account_list_ptr.asFunction<_dart_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<ffi.NativeFunction<_c_get_active_account>>('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 coin,
int id, int id,
) { ) {
return _get_available_account_id( return _set_active_account(
coin, coin,
id, id,
); );
} }
late final _get_available_account_id_ptr = late final _set_active_account_ptr =
_lookup<ffi.NativeFunction<_c_get_available_account_id>>( _lookup<ffi.NativeFunction<_c_set_active_account>>('set_active_account');
'get_available_account_id'); late final _dart_set_active_account _set_active_account =
late final _dart_get_available_account_id _get_available_account_id = _set_active_account_ptr.asFunction<_dart_set_active_account>();
_get_available_account_id_ptr
.asFunction<_dart_get_available_account_id>();
CResult_____c_char get_t_addr( CResult_____c_char get_t_addr(
int coin, int coin,
@ -1462,16 +1458,6 @@ typedef _dart_set_active = void Function(
int active, 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( typedef _c_set_coin_lwd_url = ffi.Void Function(
ffi.Uint8 coin, ffi.Uint8 coin,
ffi.Pointer<ffi.Int8> lwd_url, ffi.Pointer<ffi.Int8> lwd_url,
@ -1984,12 +1970,20 @@ typedef _dart_get_account_list = CResult______u8 Function(
int coin, 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.Uint8 coin,
ffi.Uint32 id, ffi.Uint32 id,
); );
typedef _dart_get_available_account_id = CResult_u32 Function( typedef _dart_set_active_account = CResult_u8 Function(
int coin, int coin,
int id, int id,
); );

View File

@ -1085,21 +1085,14 @@ packages:
name: sensors_plus name: sensors_plus
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.3.1" version: "2.0.1"
sensors_plus_platform_interface: sensors_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: sensors_plus_platform_interface name: sensors_plus_platform_interface
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.0" version: "1.1.3"
sensors_plus_web:
dependency: transitive
description:
name: sensors_plus_web
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
share_plus: share_plus:
dependency: "direct main" dependency: "direct main"
description: description:
@ -1464,4 +1457,4 @@ packages:
version: "3.1.1" version: "3.1.1"
sdks: sdks:
dart: ">=2.18.0 <3.0.0" dart: ">=2.18.0 <3.0.0"
flutter: ">=2.10.0" flutter: ">=2.11.0"

View File

@ -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. # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at # Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.2.17+344 version: 1.2.17+345
environment: environment:
sdk: ">=2.12.0 <3.0.0" sdk: ">=2.12.0 <3.0.0"
@ -64,7 +64,7 @@ dependencies:
ref: c2c79def4f7fa8c17e9432ca43d307ba0b4a75a3 ref: c2c79def4f7fa8c17e9432ca43d307ba0b4a75a3
flutter_speed_dial: ^5.0.0 flutter_speed_dial: ^5.0.0
currency_text_input_formatter: ^2.1.2 currency_text_input_formatter: ^2.1.2
sensors_plus: ^1.1.0 sensors_plus: ^2.0.0
connectivity_plus: ^2.2.1 connectivity_plus: ^2.2.1
uni_links: ^0.5.1 uni_links: ^0.5.1
quick_actions: ^0.6.0 quick_actions: ^0.6.0

58
smoke-test.md Normal file
View File

@ -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