mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-03-12 09:27:01 +00:00
Merge pull request #286 from cypherstack/xmr-sync
Xmr/wow wallet loading
This commit is contained in:
commit
02ab644baf
10 changed files with 236 additions and 62 deletions
|
@ -1 +1 @@
|
|||
Subproject commit 66eaa2f3c7133f1dbf0b1fc950e7a9e3cc611185
|
||||
Subproject commit 201ebc2ca4ef003b2b264af47467868a00fcbd73
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/add_wallet_text.dart';
|
||||
|
@ -37,11 +39,19 @@ class _AddWalletViewState extends State<AddWalletView> {
|
|||
|
||||
final List<Coin> coins = [...Coin.values];
|
||||
|
||||
final bool isDesktop = Util.isDesktop;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_searchFieldController = TextEditingController();
|
||||
_searchFocusNode = FocusNode();
|
||||
coins.remove(Coin.firoTestNet);
|
||||
if (isDesktop) {
|
||||
coins.remove(Coin.wownero);
|
||||
if (Platform.isWindows) {
|
||||
coins.remove(Coin.monero);
|
||||
}
|
||||
}
|
||||
super.initState();
|
||||
}
|
||||
|
||||
|
@ -56,7 +66,7 @@ class _AddWalletViewState extends State<AddWalletView> {
|
|||
Widget build(BuildContext context) {
|
||||
debugPrint("BUILD: $runtimeType");
|
||||
|
||||
if (Util.isDesktop) {
|
||||
if (isDesktop) {
|
||||
return DesktopScaffold(
|
||||
appBar: const DesktopAppBar(
|
||||
isCompactHeight: false,
|
||||
|
|
|
@ -60,6 +60,14 @@ class CoinWalletsTable extends ConsumerWidget {
|
|||
ref.read(currentWalletIdProvider.state).state =
|
||||
walletIds[i];
|
||||
|
||||
final manager = ref
|
||||
.read(walletsChangeNotifierProvider)
|
||||
.getManager(walletIds[i]);
|
||||
if (manager.coin == Coin.monero ||
|
||||
manager.coin == Coin.wownero) {
|
||||
await manager.initializeExisting();
|
||||
}
|
||||
|
||||
await Navigator.of(context).pushNamed(
|
||||
DesktopWalletView.routeName,
|
||||
arguments: walletIds[i],
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
|
@ -46,10 +48,18 @@ class _NodesSettings extends ConsumerState<NodesSettings> {
|
|||
.toList();
|
||||
}
|
||||
|
||||
final bool isDesktop = Util.isDesktop;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_coins = _coins.toList();
|
||||
_coins.remove(Coin.firoTestNet);
|
||||
if (isDesktop) {
|
||||
_coins.remove(Coin.wownero);
|
||||
if (Platform.isWindows) {
|
||||
_coins.remove(Coin.monero);
|
||||
}
|
||||
}
|
||||
|
||||
searchNodeController = TextEditingController();
|
||||
searchNodeFocusNode = FocusNode();
|
||||
|
@ -128,8 +138,8 @@ class _NodesSettings extends ConsumerState<NodesSettings> {
|
|||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
child: TextField(
|
||||
autocorrect: Util.isDesktop ? false : true,
|
||||
enableSuggestions: Util.isDesktop ? false : true,
|
||||
autocorrect: !isDesktop,
|
||||
enableSuggestions: !isDesktop,
|
||||
controller: searchNodeController,
|
||||
focusNode: searchNodeFocusNode,
|
||||
onChanged: (newString) {
|
||||
|
|
|
@ -781,7 +781,7 @@ class MoneroWallet extends CoinServiceAPI {
|
|||
await refresh();
|
||||
_autoSaveTimer?.cancel();
|
||||
_autoSaveTimer = Timer.periodic(
|
||||
const Duration(seconds: 93),
|
||||
const Duration(seconds: 193),
|
||||
(_) async => await walletBase?.save(),
|
||||
);
|
||||
} else {
|
||||
|
@ -792,27 +792,48 @@ class MoneroWallet extends CoinServiceAPI {
|
|||
}
|
||||
};
|
||||
|
||||
Future<void> _updateCachedBalance(int sats) async {
|
||||
await DB.instance.put<dynamic>(
|
||||
boxName: walletId,
|
||||
key: "cachedMoneroBalanceSats",
|
||||
value: sats,
|
||||
);
|
||||
}
|
||||
|
||||
int _getCachedBalance() =>
|
||||
DB.instance.get<dynamic>(
|
||||
boxName: walletId,
|
||||
key: "cachedMoneroBalanceSats",
|
||||
) as int? ??
|
||||
0;
|
||||
|
||||
@override
|
||||
Future<Decimal> get totalBalance async {
|
||||
final balanceEntries = walletBase?.balance?.entries;
|
||||
if (balanceEntries != null) {
|
||||
int bal = 0;
|
||||
for (var element in balanceEntries) {
|
||||
bal = bal + element.value.fullBalance;
|
||||
}
|
||||
return Format.satoshisToAmount(bal, coin: coin);
|
||||
} else {
|
||||
final transactions = walletBase!.transactionHistory!.transactions;
|
||||
int transactionBalance = 0;
|
||||
for (var tx in transactions!.entries) {
|
||||
if (tx.value.direction == TransactionDirection.incoming) {
|
||||
transactionBalance += tx.value.amount!;
|
||||
} else {
|
||||
transactionBalance += -tx.value.amount! - tx.value.fee!;
|
||||
try {
|
||||
final balanceEntries = walletBase?.balance?.entries;
|
||||
if (balanceEntries != null) {
|
||||
int bal = 0;
|
||||
for (var element in balanceEntries) {
|
||||
bal = bal + element.value.fullBalance;
|
||||
}
|
||||
await _updateCachedBalance(bal);
|
||||
return Format.satoshisToAmount(bal, coin: coin);
|
||||
} else {
|
||||
final transactions = walletBase!.transactionHistory!.transactions;
|
||||
int transactionBalance = 0;
|
||||
for (var tx in transactions!.entries) {
|
||||
if (tx.value.direction == TransactionDirection.incoming) {
|
||||
transactionBalance += tx.value.amount!;
|
||||
} else {
|
||||
transactionBalance += -tx.value.amount! - tx.value.fee!;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Format.satoshisToAmount(transactionBalance, coin: coin);
|
||||
await _updateCachedBalance(transactionBalance);
|
||||
return Format.satoshisToAmount(transactionBalance, coin: coin);
|
||||
}
|
||||
} catch (_) {
|
||||
return Format.satoshisToAmount(_getCachedBalance(), coin: coin);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1098,6 +1119,7 @@ class MoneroWallet extends CoinServiceAPI {
|
|||
print("=============================");
|
||||
print("New Block! :: $walletName");
|
||||
print("=============================");
|
||||
_refreshTxDataHelper();
|
||||
}
|
||||
|
||||
void onNewTransaction() {
|
||||
|
@ -1115,6 +1137,48 @@ class MoneroWallet extends CoinServiceAPI {
|
|||
);
|
||||
}
|
||||
|
||||
bool _txRefreshLock = false;
|
||||
int _lastCheckedHeight = -1;
|
||||
int _txCount = 0;
|
||||
|
||||
Future<void> _refreshTxDataHelper() async {
|
||||
if (_txRefreshLock) return;
|
||||
_txRefreshLock = true;
|
||||
|
||||
final syncStatus = walletBase?.syncStatus;
|
||||
|
||||
if (syncStatus != null && syncStatus is SyncingSyncStatus) {
|
||||
final int blocksLeft = syncStatus.blocksLeft;
|
||||
final tenKChange = blocksLeft ~/ 10000;
|
||||
|
||||
// only refresh transactions periodically during a sync
|
||||
if (_lastCheckedHeight == -1 || tenKChange < _lastCheckedHeight) {
|
||||
_lastCheckedHeight = tenKChange;
|
||||
await _refreshTxData();
|
||||
}
|
||||
} else {
|
||||
await _refreshTxData();
|
||||
}
|
||||
|
||||
_txRefreshLock = false;
|
||||
}
|
||||
|
||||
Future<void> _refreshTxData() async {
|
||||
final txnData = await _fetchTransactionData();
|
||||
final count = txnData.getAllTransactions().length;
|
||||
|
||||
if (count > _txCount) {
|
||||
_txCount = count;
|
||||
_transactionData = Future(() => txnData);
|
||||
GlobalEventBus.instance.fire(
|
||||
UpdatedInBackgroundEvent(
|
||||
"New transaction data found in $walletId $walletName!",
|
||||
walletId,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void syncStatusChanged() async {
|
||||
final syncStatus = walletBase?.syncStatus;
|
||||
if (syncStatus != null) {
|
||||
|
|
|
@ -812,7 +812,7 @@ class WowneroWallet extends CoinServiceAPI {
|
|||
await refresh();
|
||||
_autoSaveTimer?.cancel();
|
||||
_autoSaveTimer = Timer.periodic(
|
||||
const Duration(seconds: 93),
|
||||
const Duration(seconds: 193),
|
||||
(_) async => await walletBase?.save(),
|
||||
);
|
||||
} else {
|
||||
|
@ -820,27 +820,48 @@ class WowneroWallet extends CoinServiceAPI {
|
|||
}
|
||||
};
|
||||
|
||||
Future<void> _updateCachedBalance(int sats) async {
|
||||
await DB.instance.put<dynamic>(
|
||||
boxName: walletId,
|
||||
key: "cachedWowneroBalanceSats",
|
||||
value: sats,
|
||||
);
|
||||
}
|
||||
|
||||
int _getCachedBalance() =>
|
||||
DB.instance.get<dynamic>(
|
||||
boxName: walletId,
|
||||
key: "cachedWowneroBalanceSats",
|
||||
) as int? ??
|
||||
0;
|
||||
|
||||
@override
|
||||
Future<Decimal> get totalBalance async {
|
||||
final balanceEntries = walletBase?.balance?.entries;
|
||||
if (balanceEntries != null) {
|
||||
int bal = 0;
|
||||
for (var element in balanceEntries) {
|
||||
bal = bal + element.value.fullBalance;
|
||||
}
|
||||
return Format.satoshisToAmount(bal, coin: coin);
|
||||
} else {
|
||||
final transactions = walletBase!.transactionHistory!.transactions;
|
||||
int transactionBalance = 0;
|
||||
for (var tx in transactions!.entries) {
|
||||
if (tx.value.direction == TransactionDirection.incoming) {
|
||||
transactionBalance += tx.value.amount!;
|
||||
} else {
|
||||
transactionBalance += -tx.value.amount! - tx.value.fee!;
|
||||
try {
|
||||
final balanceEntries = walletBase?.balance?.entries;
|
||||
if (balanceEntries != null) {
|
||||
int bal = 0;
|
||||
for (var element in balanceEntries) {
|
||||
bal = bal + element.value.fullBalance;
|
||||
}
|
||||
await _updateCachedBalance(bal);
|
||||
return Format.satoshisToAmount(bal, coin: coin);
|
||||
} else {
|
||||
final transactions = walletBase!.transactionHistory!.transactions;
|
||||
int transactionBalance = 0;
|
||||
for (var tx in transactions!.entries) {
|
||||
if (tx.value.direction == TransactionDirection.incoming) {
|
||||
transactionBalance += tx.value.amount!;
|
||||
} else {
|
||||
transactionBalance += -tx.value.amount! - tx.value.fee!;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Format.satoshisToAmount(transactionBalance, coin: coin);
|
||||
await _updateCachedBalance(transactionBalance);
|
||||
return Format.satoshisToAmount(transactionBalance, coin: coin);
|
||||
}
|
||||
} catch (_) {
|
||||
return Format.satoshisToAmount(_getCachedBalance(), coin: coin);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1142,6 +1163,49 @@ class WowneroWallet extends CoinServiceAPI {
|
|||
print("=============================");
|
||||
print("New Wownero Block! :: $walletName");
|
||||
print("=============================");
|
||||
_refreshTxDataHelper();
|
||||
}
|
||||
|
||||
bool _txRefreshLock = false;
|
||||
int _lastCheckedHeight = -1;
|
||||
int _txCount = 0;
|
||||
|
||||
Future<void> _refreshTxDataHelper() async {
|
||||
if (_txRefreshLock) return;
|
||||
_txRefreshLock = true;
|
||||
|
||||
final syncStatus = walletBase?.syncStatus;
|
||||
|
||||
if (syncStatus != null && syncStatus is SyncingSyncStatus) {
|
||||
final int blocksLeft = syncStatus.blocksLeft;
|
||||
final tenKChange = blocksLeft ~/ 10000;
|
||||
|
||||
// only refresh transactions periodically during a sync
|
||||
if (_lastCheckedHeight == -1 || tenKChange < _lastCheckedHeight) {
|
||||
_lastCheckedHeight = tenKChange;
|
||||
await _refreshTxData();
|
||||
}
|
||||
} else {
|
||||
await _refreshTxData();
|
||||
}
|
||||
|
||||
_txRefreshLock = false;
|
||||
}
|
||||
|
||||
Future<void> _refreshTxData() async {
|
||||
final txnData = await _fetchTransactionData();
|
||||
final count = txnData.getAllTransactions().length;
|
||||
|
||||
if (count > _txCount) {
|
||||
_txCount = count;
|
||||
_transactionData = Future(() => txnData);
|
||||
GlobalEventBus.instance.fire(
|
||||
UpdatedInBackgroundEvent(
|
||||
"New transaction data found in $walletId $walletName!",
|
||||
walletId,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void onNewTransaction() {
|
||||
|
|
|
@ -238,7 +238,7 @@ class Wallets extends ChangeNotifier {
|
|||
walletIdsToEnableAutoSync.contains(manager.walletId);
|
||||
|
||||
if (manager.coin == Coin.monero || manager.coin == Coin.wownero) {
|
||||
walletsToInitLinearly.add(Tuple2(manager, shouldSetAutoSync));
|
||||
// walletsToInitLinearly.add(Tuple2(manager, shouldSetAutoSync));
|
||||
} else {
|
||||
walletInitFutures.add(manager.initializeExisting().then((value) {
|
||||
if (shouldSetAutoSync) {
|
||||
|
@ -328,7 +328,7 @@ class Wallets extends ChangeNotifier {
|
|||
walletIdsToEnableAutoSync.contains(manager.walletId);
|
||||
|
||||
if (manager.coin == Coin.monero || manager.coin == Coin.wownero) {
|
||||
walletsToInitLinearly.add(Tuple2(manager, shouldSetAutoSync));
|
||||
// walletsToInitLinearly.add(Tuple2(manager, shouldSetAutoSync));
|
||||
} else {
|
||||
walletInitFutures.add(manager.initializeExisting().then((value) {
|
||||
if (shouldSetAutoSync) {
|
||||
|
|
|
@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
import 'package:stackwallet/widgets/wallet_info_row/wallet_info_row.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
@ -31,7 +32,14 @@ class WalletSheetCard extends ConsumerWidget {
|
|||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
onPressed: () async {
|
||||
final manager = ref
|
||||
.read(walletsChangeNotifierProvider)
|
||||
.getManager(walletId);
|
||||
if (manager.coin == Coin.monero ||
|
||||
manager.coin == Coin.wownero) {
|
||||
await manager.initializeExisting();
|
||||
}
|
||||
if (popPrevious) Navigator.of(context).pop();
|
||||
Navigator.of(context).pushNamed(
|
||||
WalletView.routeName,
|
||||
|
|
45
pubspec.lock
45
pubspec.lock
|
@ -42,7 +42,7 @@ packages:
|
|||
name: archive
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.3.0"
|
||||
version: "3.1.11"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -63,7 +63,7 @@ packages:
|
|||
name: async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.9.0"
|
||||
version: "2.8.2"
|
||||
barcode_scan2:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -190,7 +190,14 @@ packages:
|
|||
name: characters
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
version: "1.2.0"
|
||||
charcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: charcode
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
checked_yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -211,7 +218,7 @@ packages:
|
|||
name: clock
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
version: "1.1.0"
|
||||
code_builder:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -281,7 +288,7 @@ packages:
|
|||
name: coverage
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.5.0"
|
||||
version: "1.2.0"
|
||||
cross_file:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -435,7 +442,7 @@ packages:
|
|||
name: fake_async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
version: "1.3.0"
|
||||
ffi:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -864,21 +871,21 @@ packages:
|
|||
name: matcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.12.12"
|
||||
version: "0.12.11"
|
||||
material_color_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.5"
|
||||
version: "0.1.4"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.0"
|
||||
version: "1.7.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -990,7 +997,7 @@ packages:
|
|||
name: path
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.2"
|
||||
version: "1.8.1"
|
||||
path_drawing:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1366,7 +1373,7 @@ packages:
|
|||
name: source_span
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.9.0"
|
||||
version: "1.8.2"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1410,7 +1417,7 @@ packages:
|
|||
name: string_scanner
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
version: "1.1.0"
|
||||
string_validator:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -1424,35 +1431,35 @@ packages:
|
|||
name: sync_http
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.1"
|
||||
version: "0.3.0"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: term_glyph
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
version: "1.2.0"
|
||||
test:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.21.4"
|
||||
version: "1.21.1"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.4.12"
|
||||
version: "0.4.9"
|
||||
test_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_core
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.4.16"
|
||||
version: "0.4.13"
|
||||
time:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1501,7 +1508,7 @@ packages:
|
|||
name: typed_data
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
version: "1.3.0"
|
||||
universal_io:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1585,7 +1592,7 @@ packages:
|
|||
name: vm_service
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "9.0.0"
|
||||
version: "8.2.2"
|
||||
wakelock:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
|
@ -43,6 +43,9 @@ void main() {
|
|||
mockito
|
||||
.when(wallets.getManagerProvider("wallet id"))
|
||||
.thenAnswer((realInvocation) => managerProvider);
|
||||
mockito
|
||||
.when(wallets.getManager("wallet id"))
|
||||
.thenAnswer((realInvocation) => manager);
|
||||
|
||||
final navigator = mockingjay.MockNavigator();
|
||||
mockingjay
|
||||
|
|
Loading…
Reference in a new issue