Fix: Changing account does not update budget & wallet pnl
This commit is contained in:
parent
aeee969542
commit
a6580baa48
|
@ -24,8 +24,7 @@ class AccountManagerState extends State<AccountManagerPage> {
|
|||
super.initState();
|
||||
Future.microtask(() async {
|
||||
await _accounts.updateTBalance();
|
||||
if (mounted)
|
||||
setState(() {});
|
||||
if (mounted) setState(() {});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -38,7 +37,6 @@ class AccountManagerState extends State<AccountManagerPage> {
|
|||
compute(_markAsSynced, null);
|
||||
Future.microtask(() async {
|
||||
nav.pushNamedAndRemoveUntil('/welcome', (route) => false);
|
||||
|
||||
});
|
||||
return SizedBox();
|
||||
}
|
||||
|
@ -54,73 +52,76 @@ class AccountManagerState extends State<AccountManagerPage> {
|
|||
],
|
||||
onSelected: _onMenu)
|
||||
]),
|
||||
body: Padding(padding: EdgeInsets.all(8), child: ListView.builder(
|
||||
itemCount: _accounts.list.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final a = _accounts.list[index];
|
||||
final weight = a.active ? FontWeight.bold : FontWeight.normal;
|
||||
final zbal = a.balance / ZECUNIT;
|
||||
final tbal = a.tbalance / ZECUNIT;
|
||||
final balance = zbal + tbal;
|
||||
return Card(
|
||||
child: Dismissible(
|
||||
key: Key(a.name),
|
||||
child: ListTile(
|
||||
leading: CircleAvatar(backgroundImage: settings.coins[a.coin].def.image),
|
||||
title: Text(a.name,
|
||||
style: theme.textTheme.headlineSmall
|
||||
?.merge(TextStyle(fontWeight: weight))
|
||||
.apply(color: a.coin == 0 ? theme.colorScheme.primary : theme.colorScheme.secondary,
|
||||
)),
|
||||
subtitle: Text("${decimalFormat(zbal, 3)} + ${decimalFormat(tbal, 3)}"),
|
||||
trailing: Text(decimalFormat(balance, 3)),
|
||||
onTap: () {
|
||||
_selectAccount(a);
|
||||
},
|
||||
onLongPress: () {
|
||||
_editAccount(a);
|
||||
},
|
||||
),
|
||||
confirmDismiss: (d) => _onAccountDelete(a),
|
||||
onDismissed: (d) =>
|
||||
_onDismissed(index, a),
|
||||
));
|
||||
}),
|
||||
),
|
||||
floatingActionButton: SpeedDial(
|
||||
icon: Icons.add,
|
||||
onPress: _onAddAccount,
|
||||
children: [
|
||||
SpeedDialChild(
|
||||
child: Icon(Icons.download),
|
||||
backgroundColor: Colors.red,
|
||||
foregroundColor: Colors.white,
|
||||
label: 'Restore Batch',
|
||||
onTap: _onFullRestore,
|
||||
),
|
||||
SpeedDialChild(
|
||||
child: Icon(Icons.upload),
|
||||
backgroundColor: Colors.blue,
|
||||
foregroundColor: Colors.white,
|
||||
label: 'Save Batch',
|
||||
onTap: _onFullBackup,
|
||||
),
|
||||
SpeedDialChild(
|
||||
child: Icon(Icons.subdirectory_arrow_right),
|
||||
backgroundColor: Colors.green,
|
||||
foregroundColor: Colors.white,
|
||||
label: 'New Sub-account',
|
||||
onTap: _onNewSubaccount,
|
||||
),
|
||||
SpeedDialChild(
|
||||
child: Icon(Icons.scanner),
|
||||
backgroundColor: Colors.yellow,
|
||||
foregroundColor: Colors.white,
|
||||
label: 'Scan Accounts',
|
||||
onTap: _onScanSubAccounts,
|
||||
),
|
||||
]
|
||||
));
|
||||
body: Padding(
|
||||
padding: EdgeInsets.all(8),
|
||||
child: ListView.builder(
|
||||
itemCount: _accounts.list.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final a = _accounts.list[index];
|
||||
final weight = a.active ? FontWeight.bold : FontWeight.normal;
|
||||
final zbal = a.balance / ZECUNIT;
|
||||
final tbal = a.tbalance / ZECUNIT;
|
||||
final balance = zbal + tbal;
|
||||
return Card(
|
||||
child: Dismissible(
|
||||
key: Key(a.name),
|
||||
child: ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundImage: settings.coins[a.coin].def.image),
|
||||
title: Text(a.name,
|
||||
style: theme.textTheme.headlineSmall
|
||||
?.merge(TextStyle(fontWeight: weight))
|
||||
.apply(
|
||||
color: a.coin == 0
|
||||
? theme.colorScheme.primary
|
||||
: theme.colorScheme.secondary,
|
||||
)),
|
||||
subtitle: Text(
|
||||
"${decimalFormat(zbal, 3)} + ${decimalFormat(tbal, 3)}"),
|
||||
trailing: Text(decimalFormat(balance, 3)),
|
||||
onTap: () {
|
||||
_selectAccount(a);
|
||||
},
|
||||
onLongPress: () {
|
||||
_editAccount(a);
|
||||
},
|
||||
),
|
||||
confirmDismiss: (d) => _onAccountDelete(a),
|
||||
onDismissed: (d) => _onDismissed(index, a),
|
||||
));
|
||||
}),
|
||||
),
|
||||
floatingActionButton:
|
||||
SpeedDial(icon: Icons.add, onPress: _onAddAccount, children: [
|
||||
SpeedDialChild(
|
||||
child: Icon(Icons.download),
|
||||
backgroundColor: Colors.red,
|
||||
foregroundColor: Colors.white,
|
||||
label: 'Restore Batch',
|
||||
onTap: _onFullRestore,
|
||||
),
|
||||
SpeedDialChild(
|
||||
child: Icon(Icons.upload),
|
||||
backgroundColor: Colors.blue,
|
||||
foregroundColor: Colors.white,
|
||||
label: 'Save Batch',
|
||||
onTap: _onFullBackup,
|
||||
),
|
||||
SpeedDialChild(
|
||||
child: Icon(Icons.subdirectory_arrow_right),
|
||||
backgroundColor: Colors.green,
|
||||
foregroundColor: Colors.white,
|
||||
label: 'New Sub-account',
|
||||
onTap: _onNewSubaccount,
|
||||
),
|
||||
SpeedDialChild(
|
||||
child: Icon(Icons.scanner),
|
||||
backgroundColor: Colors.yellow,
|
||||
foregroundColor: Colors.white,
|
||||
label: 'Scan Accounts',
|
||||
onTap: _onScanSubAccounts,
|
||||
),
|
||||
]));
|
||||
}
|
||||
|
||||
Future<bool> _onAccountDelete(Account account) async {
|
||||
|
@ -145,7 +146,8 @@ class AccountManagerState extends State<AccountManagerPage> {
|
|||
barrierDismissible: false,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text(S.of(context).deleteAccount),
|
||||
content: Text(S.of(context).accountHasSomeBalanceAreYouSureYouWantTo),
|
||||
content:
|
||||
Text(S.of(context).accountHasSomeBalanceAreYouSureYouWantTo),
|
||||
actions: confirmButtons(context, () {
|
||||
Navigator.of(context).pop(true);
|
||||
}, okLabel: S.of(context).delete, cancelValue: false)),
|
||||
|
@ -163,13 +165,12 @@ class AccountManagerState extends State<AccountManagerPage> {
|
|||
|
||||
_selectAccount(Account account) async {
|
||||
active.setActiveAccount(account.coin, account.id);
|
||||
await syncStatus.update();
|
||||
if (syncStatus.accountRestored) {
|
||||
syncStatus.setAccountRestored(false);
|
||||
final height = await rescanDialog(context);
|
||||
if (height != null)
|
||||
syncStatus.rescan(height);
|
||||
if (height != null) syncStatus.rescan(height);
|
||||
}
|
||||
await syncStatus.update();
|
||||
|
||||
final navigator = Navigator.of(context);
|
||||
navigator.pushNamedAndRemoveUntil('/account', (route) => false);
|
||||
|
@ -182,11 +183,14 @@ class AccountManagerState extends State<AccountManagerPage> {
|
|||
builder: (context) => AlertDialog(
|
||||
title: Text(S.of(context).changeAccountName),
|
||||
content: TextField(controller: _accountNameController),
|
||||
actions: confirmButtons(context, () { _changeAccountName(account); })));
|
||||
actions: confirmButtons(context, () {
|
||||
_changeAccountName(account);
|
||||
})));
|
||||
}
|
||||
|
||||
_changeAccountName(Account account) {
|
||||
_accounts.changeAccountName(account.coin, account.id, _accountNameController.text);
|
||||
_accounts.changeAccountName(
|
||||
account.coin, account.id, _accountNameController.text);
|
||||
Navigator.of(context).pop();
|
||||
setState(() {});
|
||||
}
|
||||
|
@ -233,8 +237,8 @@ class AccountManagerState extends State<AccountManagerPage> {
|
|||
title: Text(s.newSubAccount),
|
||||
content: Column(mainAxisSize: MainAxisSize.min, children: [
|
||||
TextField(
|
||||
decoration: InputDecoration(label: Text(s.accountName)),
|
||||
controller: _accountNameController),
|
||||
decoration: InputDecoration(label: Text(s.accountName)),
|
||||
controller: _accountNameController),
|
||||
TextField(
|
||||
decoration: InputDecoration(label: Text(s.count)),
|
||||
controller: _countController,
|
||||
|
@ -245,8 +249,8 @@ class AccountManagerState extends State<AccountManagerPage> {
|
|||
Navigator.of(context).pop(true);
|
||||
})));
|
||||
if (confirmed == true) {
|
||||
WarpApi.newSubAccount(_accountNameController.text, -1,
|
||||
int.parse(_countController.text));
|
||||
WarpApi.newSubAccount(
|
||||
_accountNameController.text, -1, int.parse(_countController.text));
|
||||
}
|
||||
await _refresh();
|
||||
}
|
||||
|
@ -255,7 +259,7 @@ class AccountManagerState extends State<AccountManagerPage> {
|
|||
_accounts.refresh();
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
|
||||
_onFullBackup() {
|
||||
Navigator.of(context).pushNamed('/fullBackup');
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:warp_api/data_fb_generated.dart' ;
|
||||
import 'package:warp_api/data_fb_generated.dart';
|
||||
import 'coin/coins.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'db.dart';
|
||||
|
@ -22,7 +22,9 @@ class Account {
|
|||
Account(this.coin, this.id, this.name, this.balance, this.tbalance);
|
||||
|
||||
String get address {
|
||||
return id != 0 ? WarpApi.getAddress(this.coin, this.id, settings.uaType) : "";
|
||||
return id != 0
|
||||
? WarpApi.getAddress(this.coin, this.id, settings.uaType)
|
||||
: "";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,9 +40,9 @@ class AccountList {
|
|||
void refresh() {
|
||||
List<Account> _list = [];
|
||||
for (var coin in coins) {
|
||||
var accounts = WarpApi.getAccountList(coin.coin).map((a) => Account(
|
||||
coin.coin, a.id, a.name!, a.balance, 0)
|
||||
).toList();
|
||||
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;
|
||||
|
@ -50,7 +52,9 @@ class AccountList {
|
|||
list = _list;
|
||||
}
|
||||
|
||||
bool get isEmpty { return list.isEmpty; }
|
||||
bool get isEmpty {
|
||||
return list.isEmpty;
|
||||
}
|
||||
|
||||
Future<void> updateTBalance() async {
|
||||
for (var a in list) {
|
||||
|
@ -69,14 +73,16 @@ class AccountList {
|
|||
refresh();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
AccountId? getAvailableId(int coin) {
|
||||
final nid = getActiveAccountId(coin);
|
||||
if (nid.id != 0) return nid;
|
||||
for (var coinData in settings.coins) {
|
||||
// look for an account in any other coin
|
||||
// look for an account in any other coin
|
||||
if (coinData.coin != coin) {
|
||||
final nid = getActiveAccountId(coinData.coin);
|
||||
if (nid.id != 0) return nid;
|
||||
|
@ -94,27 +100,39 @@ AccountId getActiveAccountId(int coin) {
|
|||
class ActiveAccount = _ActiveAccount with _$ActiveAccount;
|
||||
|
||||
abstract class _ActiveAccount with Store {
|
||||
@observable int dataEpoch = 0;
|
||||
@observable
|
||||
int dataEpoch = 0;
|
||||
|
||||
@observable int coin = 0;
|
||||
@observable int id = 0;
|
||||
@observable
|
||||
int coin = 0;
|
||||
@observable
|
||||
int id = 0;
|
||||
|
||||
Account account = emptyAccount;
|
||||
CoinBase coinDef = zcash;
|
||||
bool canPay = false;
|
||||
Balances balances = Balances();
|
||||
@observable String taddress = "";
|
||||
@observable
|
||||
String taddress = "";
|
||||
int tbalance = 0;
|
||||
PoolBalances poolBalances = PoolBalances();
|
||||
|
||||
@observable List<Note> notes = [];
|
||||
@observable List<Tx> txs = [];
|
||||
@observable List<Spending> spendings = [];
|
||||
@observable List<TimeSeriesPoint<double>> accountBalances = [];
|
||||
@observable List<PnL> pnls = [];
|
||||
@observable ObservableList<ZMessage> messages = ObservableList();
|
||||
@observable int unread = 0;
|
||||
@observable String banner = "";
|
||||
@observable
|
||||
List<Note> notes = [];
|
||||
@observable
|
||||
List<Tx> txs = [];
|
||||
@observable
|
||||
List<Spending> spendings = [];
|
||||
@observable
|
||||
List<TimeSeriesPoint<double>> accountBalances = [];
|
||||
@observable
|
||||
List<PnL> pnls = [];
|
||||
@observable
|
||||
ObservableList<ZMessage> messages = ObservableList();
|
||||
@observable
|
||||
int unread = 0;
|
||||
@observable
|
||||
String banner = "";
|
||||
|
||||
@observable
|
||||
bool showTAddr = false;
|
||||
|
@ -134,15 +152,16 @@ abstract class _ActiveAccount with Store {
|
|||
@observable
|
||||
Recipient? draftRecipient;
|
||||
|
||||
AccountId toId() { return AccountId(coin, id); }
|
||||
AccountId toId() {
|
||||
return AccountId(coin, id);
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> restore() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final coin = prefs.getInt('coin') ?? 0;
|
||||
var id = prefs.getInt('account') ?? 0;
|
||||
if (WarpApi.checkAccount(coin, id))
|
||||
setActiveAccount(coin, id);
|
||||
if (WarpApi.checkAccount(coin, id)) setActiveAccount(coin, id);
|
||||
checkAndUpdate();
|
||||
}
|
||||
|
||||
|
@ -150,25 +169,27 @@ abstract class _ActiveAccount with Store {
|
|||
final aid = getAvailableId(active.coin);
|
||||
if (aid == null) {
|
||||
setActiveAccount(0, 0);
|
||||
}
|
||||
else if (aid != active.toId()) {
|
||||
} else if (aid != active.toId()) {
|
||||
setActiveAccount(aid.coin, aid.id);
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
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);
|
||||
});
|
||||
if (coin != this.coin || id != this.id) {
|
||||
this.coin = coin;
|
||||
this.id = id;
|
||||
_refreshAccount();
|
||||
}
|
||||
Future(Action(() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
prefs.setInt('coin', coin);
|
||||
prefs.setInt('account', id);
|
||||
await priceStore.updateChart(force: true);
|
||||
dataEpoch += 1;
|
||||
}));
|
||||
Future(() => priceStore.fetchCoinPrice(active.coin));
|
||||
dataEpoch += 1;
|
||||
}
|
||||
|
||||
void _refreshAccount() {
|
||||
|
@ -205,8 +226,7 @@ abstract class _ActiveAccount with Store {
|
|||
void updateTBalance() {
|
||||
try {
|
||||
tbalance = WarpApi.getTBalance();
|
||||
}
|
||||
on String {}
|
||||
} on String {}
|
||||
}
|
||||
|
||||
@action
|
||||
|
@ -214,7 +234,8 @@ abstract class _ActiveAccount with Store {
|
|||
final initialized = balances.initialized;
|
||||
final prevBalance = balances.balance;
|
||||
final b = WarpApi.getBalance(coin, id, syncStatus.confirmHeight);
|
||||
balances.update(b.balance, b.shielded, b.unconfirmedSpent, b.underConfirmed, b.excluded);
|
||||
balances.update(b.balance, b.shielded, b.unconfirmedSpent, b.underConfirmed,
|
||||
b.excluded);
|
||||
if (initialized && prevBalance != balances.balance) {
|
||||
showBalanceNotification(prevBalance, balances.balance);
|
||||
}
|
||||
|
@ -283,8 +304,8 @@ abstract class _ActiveAccount with Store {
|
|||
case "txid":
|
||||
return _sort(txs2, (Tx tx) => tx.txid, txSortConfig.order);
|
||||
case "address":
|
||||
return _sort(
|
||||
txs2, (Tx tx) => tx.contact ?? tx.address ?? '', txSortConfig.order);
|
||||
return _sort(txs2, (Tx tx) => tx.contact ?? tx.address ?? '',
|
||||
txSortConfig.order);
|
||||
case "memo":
|
||||
return _sort(txs2, (Tx tx) => tx.memo ?? '', txSortConfig.order);
|
||||
}
|
||||
|
@ -352,7 +373,8 @@ abstract class _ActiveAccount with Store {
|
|||
final dbr = active.dbReader;
|
||||
pnls = dbr.getPNL(active.id);
|
||||
spendings = dbr.getSpending(active.id);
|
||||
accountBalances = dbr.getAccountBalanceTimeSeries(active.id, active.balances.balance);
|
||||
accountBalances =
|
||||
dbr.getAccountBalanceTimeSeries(active.id, active.balances.balance);
|
||||
}
|
||||
|
||||
@action
|
||||
|
@ -375,13 +397,15 @@ abstract class _ActiveAccount with Store {
|
|||
|
||||
int prevInThread(int index) {
|
||||
final message = messages[index];
|
||||
final pn = WarpApi.getPrevNextMessage(coin, id, message.subject, message.height);
|
||||
final pn =
|
||||
WarpApi.getPrevNextMessage(coin, id, message.subject, message.height);
|
||||
return pn.prev;
|
||||
}
|
||||
|
||||
int nextInThread(int index) {
|
||||
final message = messages[index];
|
||||
final pn = WarpApi.getPrevNextMessage(coin, id, message.subject, message.height);
|
||||
final pn =
|
||||
WarpApi.getPrevNextMessage(coin, id, message.subject, message.height);
|
||||
return pn.next;
|
||||
}
|
||||
|
||||
|
@ -401,14 +425,20 @@ class Balances = _Balances with _$Balances;
|
|||
|
||||
abstract class _Balances with Store {
|
||||
bool initialized = false;
|
||||
@observable int balance = 0;
|
||||
@observable int shieldedBalance = 0;
|
||||
@observable int unconfirmedSpentBalance = 0;
|
||||
@observable int underConfirmedBalance = 0;
|
||||
@observable int excludedBalance = 0;
|
||||
@observable
|
||||
int balance = 0;
|
||||
@observable
|
||||
int shieldedBalance = 0;
|
||||
@observable
|
||||
int unconfirmedSpentBalance = 0;
|
||||
@observable
|
||||
int underConfirmedBalance = 0;
|
||||
@observable
|
||||
int excludedBalance = 0;
|
||||
|
||||
@action
|
||||
void update(int balance, int shieldedBalance, int unconfirmedSpentBalance, int underConfirmedBalance, int excludedBalance) {
|
||||
void update(int balance, int shieldedBalance, int unconfirmedSpentBalance,
|
||||
int underConfirmedBalance, int excludedBalance) {
|
||||
this.balance = balance;
|
||||
this.shieldedBalance = shieldedBalance;
|
||||
this.unconfirmedSpentBalance = unconfirmedSpentBalance;
|
||||
|
@ -427,12 +457,16 @@ class AccountId {
|
|||
class PoolBalances = _PoolBalances with _$PoolBalances;
|
||||
|
||||
abstract class _PoolBalances with Store {
|
||||
@observable int transparent = 0;
|
||||
@observable int sapling = 0;
|
||||
@observable int orchard = 0;
|
||||
@observable
|
||||
int transparent = 0;
|
||||
@observable
|
||||
int sapling = 0;
|
||||
@observable
|
||||
int orchard = 0;
|
||||
|
||||
void update() {
|
||||
final b = WarpApi.getBalance(active.coin, active.id, syncStatus.confirmHeight);
|
||||
final b =
|
||||
WarpApi.getBalance(active.coin, active.id, syncStatus.confirmHeight);
|
||||
_update(active.tbalance, b.sapling, b.orchard);
|
||||
}
|
||||
|
||||
|
|
|
@ -646,12 +646,14 @@ abstract class _PriceStore with Store {
|
|||
coinPrice = await getFxRate(c.currency, settings.currency) ?? 0.0;
|
||||
}
|
||||
|
||||
Future<void> updateChart() async {
|
||||
Future<void> updateChart({bool? force}) async {
|
||||
final f = force ?? false;
|
||||
try {
|
||||
final _lastChartUpdateTime = lastChartUpdateTime;
|
||||
final now = DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
||||
await fetchCoinPrice(active.coin);
|
||||
if (_lastChartUpdateTime == null || now > _lastChartUpdateTime + 5 * 60) {
|
||||
if (f ||
|
||||
_lastChartUpdateTime == null ||
|
||||
now > _lastChartUpdateTime + 5 * 60) {
|
||||
await WarpApi.syncHistoricalPrices(settings.currency);
|
||||
active.fetchChartData();
|
||||
lastChartUpdateTime = now;
|
||||
|
|
|
@ -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.3.6+407
|
||||
version: 1.3.6+408
|
||||
|
||||
environment:
|
||||
sdk: ">=2.12.0 <3.0.0"
|
||||
|
|
Loading…
Reference in New Issue