mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-23 02:54:30 +00:00
Merge branch 'staging' into desktop
This commit is contained in:
commit
baca31cfba
47 changed files with 3715 additions and 500 deletions
38
.github/workflows/test.yaml
vendored
38
.github/workflows/test.yaml
vendored
|
@ -50,48 +50,36 @@ jobs:
|
|||
$encodedBytes = [System.Convert]::FromBase64String($env:CHANGE_NOW);
|
||||
Set-Content $secretFileExchange -Value $encodedBytes -AsByteStream;
|
||||
$secretFileExchangeHash = Get-FileHash $secretFileExchange;
|
||||
Write-Output "::set-output name=SECRET_FILE_EXCHANGE::$secretFileExchange";
|
||||
Write-Output "::set-output name=SECRET_FILE_EXCHANGE_HASH::$($secretFileExchangeHash.Hash)";
|
||||
Write-Output "Secret file $secretFileExchange has hash $($secretFileExchangeHash.Hash)";
|
||||
|
||||
$secretFileBitcoin = Join-Path -Path $env:GITHUB_WORKSPACE -ChildPath "test/services/coins/bitcoin/bitcoin_wallet_test_parameters.dart";
|
||||
$encodedBytes = [System.Convert]::FromBase64String($env:BITCOIN_TEST);
|
||||
Set-Content $secretFileBitcoin -Value $encodedBytes -AsByteStream;
|
||||
$secretFileBitcoinHash = Get-FileHash $secretFileBitcoin;
|
||||
Write-Output "::set-output name=SECRET_FILE_BITCOIN::$secretFileBitcoin";
|
||||
Write-Output "::set-output name=SECRET_FILE_BITCOIN_HASH::$($secretFileBitcoinHash.Hash)";
|
||||
Write-Output "Secret file $secretFileBitcoin has hash $($secretFileBitcoinHash.Hash)";
|
||||
|
||||
$secretFileDogecoin = Join-Path -Path $env:GITHUB_WORKSPACE -ChildPath "test/services/coins/dogecoin/dogecoin_wallet_test_parameters.dart";
|
||||
$encodedBytes = [System.Convert]::FromBase64String($env:DOGECOIN_TEST);
|
||||
Set-Content $secretFileDogecoin -Value $encodedBytes -AsByteStream;
|
||||
$secretFileDogecoinHash = Get-FileHash $secretFileDogecoin;
|
||||
Write-Output "::set-output name=SECRET_FILE_DOGECOIN::$secretFileDogecoin";
|
||||
Write-Output "::set-output name=SECRET_FILE_DOGECOIN_HASH::$($secretFileDogecoinHash.Hash)";
|
||||
Write-Output "Secret file $secretFileDogecoin has hash $($secretFileDogecoinHash.Hash)";
|
||||
|
||||
$secretFileFiro = Join-Path -Path $env:GITHUB_WORKSPACE -ChildPath "test/services/coins/firo/firo_wallet_test_parameters.dart";
|
||||
$encodedBytes = [System.Convert]::FromBase64String($env:FIRO_TEST);
|
||||
Set-Content $secretFileFiro -Value $encodedBytes -AsByteStream;
|
||||
$secretFileFiroHash = Get-FileHash $secretFileFiro;
|
||||
Write-Output "::set-output name=SECRET_FILE_FIRO::$secretFileFiro";
|
||||
Write-Output "::set-output name=SECRET_FILE_FIRO_HASH::$($secretFileFiroHash.Hash)";
|
||||
Write-Output "Secret file $secretFileFiro has hash $($secretFileFiroHash.Hash)";
|
||||
|
||||
$secretFileBitcoinCash = Join-Path -Path $env:GITHUB_WORKSPACE -ChildPath "test/services/coins/bitcoincash/bitcoincash_wallet_test_parameters.dart";
|
||||
$encodedBytes = [System.Convert]::FromBase64String($env:BITCOINCASH_TEST);
|
||||
Set-Content $secretFileBitcoinCash -Value $encodedBytes -AsByteStream;
|
||||
$secretFileBitcoinCashHash = Get-FileHash $secretFileBitcoinCash;
|
||||
Write-Output "::set-output name=SECRET_FILE_BITCOINCASH::$secretFileBitcoinCash";
|
||||
Write-Output "::set-output name=SECRET_FILE_BITCOINCASH_HASH::$($secretFileBitcoinCashHash.Hash)";
|
||||
Write-Output "Secret file $secretFileBitcoinCash has hash $($secretFileBitcoinCashHash.Hash)";
|
||||
|
||||
$secretFileNamecoin = Join-Path -Path $env:GITHUB_WORKSPACE -ChildPath "test/services/coins/namecoin/namecoin_wallet_test_parameters.dart";
|
||||
$encodedBytes = [System.Convert]::FromBase64String($env:NAMECOIN_TEST);
|
||||
Set-Content $secretFileNamecoin -Value $encodedBytes -AsByteStream;
|
||||
$secretFileNamecoinHash = Get-FileHash $secretFileNamecoin;
|
||||
Write-Output "::set-output name=SECRET_FILE_NAMECOIN::$secretFileNamecoin";
|
||||
Write-Output "::set-output name=SECRET_FILE_NAMECOIN_HASH::$($secretFileNamecoinHash.Hash)";
|
||||
Write-Output "Secret file $secretFileNamecoin has hash $($secretFileNamecoinHash.Hash)";
|
||||
|
||||
shell: pwsh
|
||||
|
@ -114,18 +102,18 @@ jobs:
|
|||
file: coverage/lcov.info
|
||||
- name: Delete temp files
|
||||
run: |
|
||||
Remove-Item -Path $env:CHANGE_NOW;
|
||||
Remove-Item -Path $env:BITCOIN_TEST;
|
||||
Remove-Item -Path $env:DOGECOIN_TEST;
|
||||
Remove-Item -Path $env:FIRO_TEST;
|
||||
Remove-Item -Path $env:BITCOINCASH_TEST;
|
||||
Remove-Item -Path $env:NAMECOIN_TEST;
|
||||
$secretFileExchange = Join-Path -Path $env:GITHUB_WORKSPACE -ChildPath "lib/external_api_keys.dart";
|
||||
$secretFileBitcoin = Join-Path -Path $env:GITHUB_WORKSPACE -ChildPath "test/services/coins/bitcoin/bitcoin_wallet_test_parameters.dart";
|
||||
$secretFileDogecoin = Join-Path -Path $env:GITHUB_WORKSPACE -ChildPath "test/services/coins/dogecoin/dogecoin_wallet_test_parameters.dart";
|
||||
$secretFileFiro = Join-Path -Path $env:GITHUB_WORKSPACE -ChildPath "test/services/coins/firo/firo_wallet_test_parameters.dart";
|
||||
$secretFileBitcoinCash = Join-Path -Path $env:GITHUB_WORKSPACE -ChildPath "test/services/coins/bitcoincash/bitcoincash_wallet_test_parameters.dart";
|
||||
$secretFileNamecoin = Join-Path -Path $env:GITHUB_WORKSPACE -ChildPath "test/services/coins/namecoin/namecoin_wallet_test_parameters.dart";
|
||||
|
||||
Remove-Item -Path $secretFileExchange;
|
||||
Remove-Item -Path $secretFileBitcoin;
|
||||
Remove-Item -Path $secretFileDogecoin;
|
||||
Remove-Item -Path $secretFileFiro;
|
||||
Remove-Item -Path $secretFileBitcoinCash;
|
||||
Remove-Item -Path $secretFileNamecoin;
|
||||
shell: pwsh
|
||||
if: always()
|
||||
env:
|
||||
CHANGE_NOW: ${{ steps.secret-file1.outputs.SECRET_FILE_EXCHANGE }}
|
||||
BITCOIN_TEST: ${{ steps.secret-file1.outputs.SECRET_FILE_BITCOIN }}
|
||||
DOGECOIN_TEST: ${{ steps.secret-file1.outputs.SECRET_FILE_DOGECOIN }}
|
||||
FIRO_TEST: ${{ steps.secret-file1.outputs.SECRET_FILE_FIRO }}
|
||||
BITCOINCASH_TEST: ${{ steps.secret-file1.outputs.SECRET_FILE_BITCOINCASH }}
|
||||
NAMECOIN_TEST: ${{ steps.secret-file1.outputs.SECRET_FILE_NAMECOIN }}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
<application
|
||||
android:name="${applicationName}"
|
||||
android:label="Stack Wallet"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:allowBackup="false"
|
||||
android:fullBackupContent="false">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
buildscript {
|
||||
ext.kotlin_version = '1.6.10'
|
||||
ext.kotlin_version = '1.7.20'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
|
|
|
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
|||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
|
||||
|
|
|
@ -454,7 +454,7 @@
|
|||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 78;
|
||||
CURRENT_PROJECT_VERSION = 79;
|
||||
DEVELOPMENT_TEAM = 4DQKUWSG6C;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
|
@ -508,7 +508,7 @@
|
|||
"$(PROJECT_DIR)/../crypto_plugins/flutter_libmonero/cw_shared_external/ios/External/ios/**",
|
||||
"$(PROJECT_DIR)/../crypto_plugins/flutter_libepiccash/ios/libs",
|
||||
);
|
||||
MARKETING_VERSION = 1.5.8;
|
||||
MARKETING_VERSION = 1.5.9;
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.cypherstack.stackwallet;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
@ -641,7 +641,7 @@
|
|||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 78;
|
||||
CURRENT_PROJECT_VERSION = 79;
|
||||
DEVELOPMENT_TEAM = 4DQKUWSG6C;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
|
@ -695,7 +695,7 @@
|
|||
"$(PROJECT_DIR)/../crypto_plugins/flutter_libmonero/cw_shared_external/ios/External/ios/**",
|
||||
"$(PROJECT_DIR)/../crypto_plugins/flutter_libepiccash/ios/libs",
|
||||
);
|
||||
MARKETING_VERSION = 1.5.8;
|
||||
MARKETING_VERSION = 1.5.9;
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.cypherstack.stackwallet;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
@ -720,7 +720,7 @@
|
|||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 78;
|
||||
CURRENT_PROJECT_VERSION = 79;
|
||||
DEVELOPMENT_TEAM = 4DQKUWSG6C;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
|
@ -774,7 +774,7 @@
|
|||
"$(PROJECT_DIR)/../crypto_plugins/flutter_libmonero/cw_shared_external/ios/External/ios/**",
|
||||
"$(PROJECT_DIR)/../crypto_plugins/flutter_libepiccash/ios/libs",
|
||||
);
|
||||
MARKETING_VERSION = 1.5.8;
|
||||
MARKETING_VERSION = 1.5.9;
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.cypherstack.stackwallet;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:stackwallet/electrumx_rpc/electrumx.dart';
|
||||
import 'package:stackwallet/hive/db.dart';
|
||||
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/prefs.dart';
|
||||
import 'package:string_validator/string_validator.dart';
|
||||
|
||||
class CachedElectrumX {
|
||||
final ElectrumX? electrumXClient;
|
||||
|
@ -94,10 +97,32 @@ class CachedElectrumX {
|
|||
|
||||
// update set with new data
|
||||
if (newSet["setHash"] != "" && set["setHash"] != newSet["setHash"]) {
|
||||
set["setHash"] = newSet["setHash"];
|
||||
set["blockHash"] = newSet["blockHash"];
|
||||
set["setHash"] = !isHexadecimal(newSet["setHash"] as String)
|
||||
? base64ToReverseHex(newSet["setHash"] as String)
|
||||
: newSet["setHash"];
|
||||
set["blockHash"] = !isHexadecimal(newSet["blockHash"] as String)
|
||||
? base64ToHex(newSet["blockHash"] as String)
|
||||
: newSet["blockHash"];
|
||||
for (int i = (newSet["coins"] as List).length - 1; i >= 0; i--) {
|
||||
set["coins"].insert(0, newSet["coins"][i]);
|
||||
dynamic newCoin = newSet["coins"][i];
|
||||
List translatedCoin = [];
|
||||
translatedCoin.add(!isHexadecimal(newCoin[0] as String)
|
||||
? base64ToHex(newCoin[0] as String)
|
||||
: newCoin[0]);
|
||||
translatedCoin.add(!isHexadecimal(newCoin[1] as String)
|
||||
? base64ToReverseHex(newCoin[1] as String)
|
||||
: newCoin[1]);
|
||||
try {
|
||||
translatedCoin.add(!isHexadecimal(newCoin[2] as String)
|
||||
? base64ToHex(newCoin[2] as String)
|
||||
: newCoin[2]);
|
||||
} catch (e, s) {
|
||||
translatedCoin.add(newCoin[2]);
|
||||
}
|
||||
translatedCoin.add(!isHexadecimal(newCoin[3] as String)
|
||||
? base64ToReverseHex(newCoin[3] as String)
|
||||
: newCoin[3]);
|
||||
set["coins"].insert(0, translatedCoin);
|
||||
}
|
||||
// save set to db
|
||||
await DB.instance.put<dynamic>(
|
||||
|
@ -118,6 +143,17 @@ class CachedElectrumX {
|
|||
}
|
||||
}
|
||||
|
||||
String base64ToHex(String source) =>
|
||||
base64Decode(LineSplitter.split(source).join())
|
||||
.map((e) => e.toRadixString(16).padLeft(2, '0'))
|
||||
.join();
|
||||
|
||||
String base64ToReverseHex(String source) =>
|
||||
base64Decode(LineSplitter.split(source).join())
|
||||
.reversed
|
||||
.map((e) => e.toRadixString(16).padLeft(2, '0'))
|
||||
.join();
|
||||
|
||||
/// Call electrumx getTransaction on a per coin basis, storing the result in local db if not already there.
|
||||
///
|
||||
/// ElectrumX api only called if the tx does not exist in local db
|
||||
|
@ -189,7 +225,15 @@ class CachedElectrumX {
|
|||
);
|
||||
|
||||
final serials = await client.getUsedCoinSerials(startNumber: startNumber);
|
||||
cachedSerials.addAll(serials["serials"] as List);
|
||||
List newSerials = [];
|
||||
for (var element in (serials["serials"] as List)) {
|
||||
if (!isHexadecimal(element as String)) {
|
||||
newSerials.add(base64ToHex(element));
|
||||
} else {
|
||||
newSerials.add(element);
|
||||
}
|
||||
}
|
||||
cachedSerials.addAll(newSerials);
|
||||
|
||||
await DB.instance.put<dynamic>(
|
||||
boxName: DB.instance.boxNameUsedSerialsCache(coin: coin),
|
||||
|
|
|
@ -9,6 +9,7 @@ import 'package:stackwallet/models/node_model.dart';
|
|||
import 'package:stackwallet/models/notification_model.dart';
|
||||
import 'package:stackwallet/models/trade_wallet_lookup.dart';
|
||||
import 'package:stackwallet/services/wallets_service.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
|
||||
|
@ -142,6 +143,17 @@ class DB {
|
|||
_loadSharedCoinCacheBoxes(),
|
||||
]);
|
||||
_initialized = true;
|
||||
|
||||
try {
|
||||
if (_boxPrefs.get("familiarity") == null) {
|
||||
await _boxPrefs.put("familiarity", 0);
|
||||
}
|
||||
int count = _boxPrefs.get("familiarity") as int;
|
||||
await _boxPrefs.put("familiarity", count + 1);
|
||||
Constants.exchangeForExperiencedUsers(count + 1);
|
||||
} catch (e, s) {
|
||||
print("$e $s");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -146,7 +146,12 @@ void main() async {
|
|||
boxName: DB.boxNameDBInfo, key: "hive_data_version") as int? ??
|
||||
0;
|
||||
if (dbVersion < Constants.currentHiveDbVersion) {
|
||||
try {
|
||||
await DbVersionMigrator().migrate(dbVersion);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("Cannot migrate database\n$e $s",
|
||||
level: LogLevel.Error, printFullLength: true);
|
||||
}
|
||||
}
|
||||
|
||||
monero.onStartup();
|
||||
|
@ -234,7 +239,9 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
// unawaited(_nodeService.updateCommunityNodes());
|
||||
|
||||
// run without awaiting
|
||||
if (Constants.enableExchange && _prefs.externalCalls) {
|
||||
if (Constants.enableExchange &&
|
||||
_prefs.externalCalls &&
|
||||
await _prefs.isExternalCallsSet()) {
|
||||
unawaited(ExchangeDataLoadingService().loadAll(ref));
|
||||
}
|
||||
|
||||
|
|
|
@ -276,6 +276,12 @@ class ExchangeFormState extends ChangeNotifier {
|
|||
|
||||
void _onExchangeRateTypeChanged() {
|
||||
print("_onExchangeRateTypeChanged");
|
||||
updateRanges(shouldNotifyListeners: true).then(
|
||||
(_) => updateEstimate(
|
||||
shouldNotifyListeners: true,
|
||||
reversed: reversed,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _onExchangeTypeChanged() {
|
||||
|
|
|
@ -144,6 +144,8 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
|||
|
||||
Future<void> chooseDate() async {
|
||||
final height = MediaQuery.of(context).size.height;
|
||||
final fetchedColor =
|
||||
Theme.of(context).extension<StackColors>()!.accentColorDark;
|
||||
// check and hide keyboard
|
||||
if (FocusScope.of(context).hasFocus) {
|
||||
FocusScope.of(context).unfocus();
|
||||
|
@ -155,8 +157,7 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
|||
initialDate: DateTime.now(),
|
||||
height: height * 0.5,
|
||||
theme: ThemeData(
|
||||
primarySwatch: Util.createMaterialColor(
|
||||
Theme.of(context).extension<StackColors>()!.accentColorDark),
|
||||
primarySwatch: Util.createMaterialColor(fetchedColor),
|
||||
),
|
||||
//TODO pick a better initial date
|
||||
// 2007 chosen as that is just before bitcoin launched
|
||||
|
@ -272,6 +273,7 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
|||
// if (!isDesktop)
|
||||
RestoreFromDatePicker(
|
||||
onTap: chooseDate,
|
||||
controller: _dateController,
|
||||
),
|
||||
|
||||
// if (isDesktop)
|
||||
|
|
|
@ -7,10 +7,14 @@ import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
|||
import 'package:stackwallet/utilities/util.dart';
|
||||
|
||||
class RestoreFromDatePicker extends StatefulWidget {
|
||||
const RestoreFromDatePicker({Key? key, required this.onTap})
|
||||
: super(key: key);
|
||||
const RestoreFromDatePicker({
|
||||
Key? key,
|
||||
required this.onTap,
|
||||
required this.controller,
|
||||
}) : super(key: key);
|
||||
|
||||
final VoidCallback onTap;
|
||||
final TextEditingController controller;
|
||||
|
||||
@override
|
||||
State<RestoreFromDatePicker> createState() => _RestoreFromDatePickerState();
|
||||
|
@ -23,17 +27,11 @@ class _RestoreFromDatePickerState extends State<RestoreFromDatePicker> {
|
|||
@override
|
||||
void initState() {
|
||||
onTap = widget.onTap;
|
||||
_dateController = TextEditingController();
|
||||
_dateController = widget.controller;
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_dateController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:event_bus/event_bus.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:stackwallet/models/isar/models/log.dart';
|
||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||
|
@ -24,6 +28,13 @@ import 'package:stackwallet/widgets/rounded_container.dart';
|
|||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||
import 'package:stackwallet/widgets/stack_text_field.dart';
|
||||
import 'package:stackwallet/widgets/textfield_icon_button.dart';
|
||||
import 'package:flutter_libepiccash/git_versions.dart' as EPIC_VERSIONS;
|
||||
import 'package:flutter_libmonero/git_versions.dart' as MONERO_VERSIONS;
|
||||
import 'package:lelantus/git_versions.dart' as FIRO_VERSIONS;
|
||||
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/helpers/stack_file_system.dart';
|
||||
|
||||
import 'package:stackwallet/utilities/clipboard_interface.dart';
|
||||
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
|
||||
|
@ -272,21 +283,77 @@ class _DebugViewState extends ConsumerState<DebugView> {
|
|||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
// BlueTextButton(
|
||||
// text: ref.watch(debugServiceProvider
|
||||
// .select((value) => value.isPaused))
|
||||
// ? "Unpause"
|
||||
// : "Pause",
|
||||
// onTap: () {
|
||||
// ref
|
||||
// .read(debugServiceProvider)
|
||||
// .togglePauseUiUpdates();
|
||||
// },
|
||||
// ),
|
||||
BlueTextButton(
|
||||
text: "Save Debug Info to clipboard",
|
||||
onTap: () async {
|
||||
try {
|
||||
final packageInfo =
|
||||
await PackageInfo.fromPlatform();
|
||||
final version = packageInfo.version;
|
||||
final build = packageInfo.buildNumber;
|
||||
final signature = packageInfo.buildSignature;
|
||||
final appName = packageInfo.appName;
|
||||
String firoCommit =
|
||||
FIRO_VERSIONS.getPluginVersion();
|
||||
String epicCashCommit =
|
||||
EPIC_VERSIONS.getPluginVersion();
|
||||
String moneroCommit =
|
||||
MONERO_VERSIONS.getPluginVersion();
|
||||
DeviceInfoPlugin deviceInfoPlugin =
|
||||
DeviceInfoPlugin();
|
||||
final deviceInfo =
|
||||
await deviceInfoPlugin.deviceInfo;
|
||||
var deviceInfoMap = deviceInfo.toMap();
|
||||
deviceInfoMap.remove("systemFeatures");
|
||||
|
||||
final logs = filtered(
|
||||
ref.watch(debugServiceProvider.select(
|
||||
(value) => value.recentLogs)),
|
||||
_searchTerm)
|
||||
.reversed
|
||||
.toList(growable: false);
|
||||
List errorLogs = [];
|
||||
for (var log in logs) {
|
||||
if (log.logLevel == LogLevel.Error ||
|
||||
log.logLevel == LogLevel.Fatal) {
|
||||
errorLogs.add(
|
||||
"${log.logLevel}: ${log.message}");
|
||||
}
|
||||
}
|
||||
|
||||
final finalDebugMap = {
|
||||
"version": version,
|
||||
"build": build,
|
||||
"signature": signature,
|
||||
"appName": appName,
|
||||
"firoCommit": firoCommit,
|
||||
"epicCashCommit": epicCashCommit,
|
||||
"moneroCommit": moneroCommit,
|
||||
"deviceInfoMap": deviceInfoMap,
|
||||
"errorLogs": errorLogs,
|
||||
};
|
||||
Logging.instance.log(
|
||||
json.encode(finalDebugMap),
|
||||
level: LogLevel.Info,
|
||||
printFullLength: true);
|
||||
const ClipboardInterface clipboard =
|
||||
ClipboardWrapper();
|
||||
await clipboard.setData(
|
||||
ClipboardData(
|
||||
text: json.encode(finalDebugMap)),
|
||||
);
|
||||
} catch (e, s) {
|
||||
Logging.instance
|
||||
.log("$e $s", level: LogLevel.Error);
|
||||
}
|
||||
},
|
||||
),
|
||||
const Spacer(),
|
||||
BlueTextButton(
|
||||
text: "Save logs to file",
|
||||
onTap: () async {
|
||||
final systemfile = StackFileSystem();
|
||||
await systemfile.prepareStorage();
|
||||
Directory rootPath =
|
||||
(await getApplicationDocumentsDirectory());
|
||||
|
||||
|
@ -313,8 +380,9 @@ class _DebugViewState extends ConsumerState<DebugView> {
|
|||
} else {
|
||||
path = await FilePicker.platform
|
||||
.getDirectoryPath(
|
||||
dialogTitle: "Choose Backup location",
|
||||
initialDirectory: dir.path,
|
||||
dialogTitle: "Choose Log Save Location",
|
||||
initialDirectory:
|
||||
systemfile.startPath!.path,
|
||||
lockParentWindow: true,
|
||||
);
|
||||
}
|
||||
|
@ -336,9 +404,17 @@ class _DebugViewState extends ConsumerState<DebugView> {
|
|||
),
|
||||
));
|
||||
|
||||
final filename = await ref
|
||||
bool logssaved = true;
|
||||
var filename;
|
||||
try {
|
||||
filename = await ref
|
||||
.read(debugServiceProvider)
|
||||
.exportToFile(path, eventBus);
|
||||
} catch (e, s) {
|
||||
logssaved = false;
|
||||
Logging.instance
|
||||
.log("$e $s", level: LogLevel.Error);
|
||||
}
|
||||
|
||||
shouldPop = true;
|
||||
|
||||
|
@ -350,7 +426,9 @@ class _DebugViewState extends ConsumerState<DebugView> {
|
|||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => StackOkDialog(
|
||||
title: "Logs saved to",
|
||||
title: logssaved
|
||||
? "Logs saved to"
|
||||
: "Error Saving Logs",
|
||||
message: "${path!}/$filename",
|
||||
),
|
||||
),
|
||||
|
@ -360,7 +438,9 @@ class _DebugViewState extends ConsumerState<DebugView> {
|
|||
showFloatingFlushBar(
|
||||
type: FlushBarType.info,
|
||||
context: context,
|
||||
message: 'Logs file saved',
|
||||
message: logssaved
|
||||
? 'Logs file saved'
|
||||
: "Error Saving Logs",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -687,27 +687,14 @@ abstract class SWB {
|
|||
uiState?.walletStates = walletStates;
|
||||
|
||||
List<Future<bool>> restoreStatuses = [];
|
||||
final List<Tuple2<dynamic, Manager>> firoWallets = [];
|
||||
final List<Tuple2<dynamic, Manager>> firoTestnetWallets = [];
|
||||
final List<Tuple2<dynamic, Manager>> epicCashWallets = [];
|
||||
// start restoring wallets
|
||||
for (final tuple in managers) {
|
||||
// check if cancel was requested and restore previous state
|
||||
if (_checkShouldCancel(preRestoreState)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tuple.item2.coin == Coin.firoTestNet) {
|
||||
firoTestnetWallets.add(tuple);
|
||||
continue;
|
||||
} else if (tuple.item2.coin == Coin.firo) {
|
||||
firoWallets.add(tuple);
|
||||
continue;
|
||||
} else if (tuple.item2.coin == Coin.epicCash) {
|
||||
epicCashWallets.add(tuple);
|
||||
continue;
|
||||
}
|
||||
restoreStatuses.add(asyncRestore(tuple, uiState, walletsService));
|
||||
final bools = await asyncRestore(tuple, uiState, walletsService);
|
||||
restoreStatuses.add(Future(() => bools));
|
||||
}
|
||||
|
||||
// check if cancel was requested and restore previous state
|
||||
|
@ -715,153 +702,6 @@ abstract class SWB {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (firoTestnetWallets.isNotEmpty) {
|
||||
// check if cancel was requested and restore previous state
|
||||
if (_checkShouldCancel(preRestoreState)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (final wallet in firoTestnetWallets) {
|
||||
uiState?.update(
|
||||
walletId: wallet.item2.walletId,
|
||||
restoringStatus: StackRestoringStatus.restoring,
|
||||
);
|
||||
}
|
||||
// try using node from backup first
|
||||
NodeModel node = nodeService.getPrimaryNodeFor(coin: Coin.firoTestNet) ??
|
||||
DefaultNodes.getNodeFor(Coin.firoTestNet);
|
||||
|
||||
final electrumxNode = ElectrumXNode(
|
||||
address: node.host,
|
||||
port: node.port,
|
||||
name: node.name,
|
||||
id: node.id,
|
||||
useSSL: node.useSSL,
|
||||
);
|
||||
|
||||
final failovers = nodeService.failoverNodesFor(coin: Coin.firoTestNet);
|
||||
|
||||
// check if cancel was requested and restore previous state
|
||||
if (_checkShouldCancel(preRestoreState)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final cachedClient = CachedElectrumX.from(
|
||||
node: electrumxNode,
|
||||
prefs: _prefs,
|
||||
failovers: failovers
|
||||
.map(
|
||||
(e) => ElectrumXNode(
|
||||
address: e.host,
|
||||
port: e.port,
|
||||
name: e.name,
|
||||
id: e.id,
|
||||
useSSL: e.useSSL,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
|
||||
// check if cancel was requested and restore previous state
|
||||
if (_checkShouldCancel(preRestoreState)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Anonymity Set often fails when gathering from the server
|
||||
const int maxTries = 5;
|
||||
for (int j = 0; j < maxTries; j++) {
|
||||
// check if cancel was requested and restore previous state
|
||||
if (_checkShouldCancel(preRestoreState)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
await cachedClient.getAnonymitySet(
|
||||
groupId: "1",
|
||||
coin: Coin.firoTestNet,
|
||||
);
|
||||
break;
|
||||
} catch (_) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// check if cancel was requested and restore previous state
|
||||
if (_checkShouldCancel(preRestoreState)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (firoWallets.isNotEmpty) {
|
||||
for (final wallet in firoWallets) {
|
||||
uiState?.update(
|
||||
walletId: wallet.item2.walletId,
|
||||
restoringStatus: StackRestoringStatus.restoring,
|
||||
);
|
||||
}
|
||||
|
||||
// check if cancel was requested and restore previous state
|
||||
if (_checkShouldCancel(preRestoreState)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// try using node from backup first
|
||||
NodeModel node = nodeService.getPrimaryNodeFor(coin: Coin.firo) ??
|
||||
DefaultNodes.getNodeFor(Coin.firo);
|
||||
|
||||
final electrumxNode = ElectrumXNode(
|
||||
address: node.host,
|
||||
port: node.port,
|
||||
name: node.name,
|
||||
id: node.id,
|
||||
useSSL: node.useSSL,
|
||||
);
|
||||
final failovers = nodeService.failoverNodesFor(coin: Coin.firoTestNet);
|
||||
final cachedClient = CachedElectrumX.from(
|
||||
node: electrumxNode,
|
||||
prefs: _prefs,
|
||||
failovers: failovers
|
||||
.map(
|
||||
(e) => ElectrumXNode(
|
||||
address: e.host,
|
||||
port: e.port,
|
||||
name: e.name,
|
||||
id: e.id,
|
||||
useSSL: e.useSSL,
|
||||
),
|
||||
)
|
||||
.toList());
|
||||
|
||||
// Anonymity Set often fails when gathering from the server
|
||||
const int maxTries = 5;
|
||||
for (int j = 0; j < maxTries; j++) {
|
||||
// check if cancel was requested and restore previous state
|
||||
if (_checkShouldCancel(preRestoreState)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
await cachedClient.getAnonymitySet(
|
||||
groupId: "1",
|
||||
coin: Coin.firo,
|
||||
);
|
||||
break;
|
||||
} catch (_) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if cancel was requested and restore previous state
|
||||
if (_checkShouldCancel(preRestoreState)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (final tuple in firoTestnetWallets) {
|
||||
restoreStatuses.add(asyncRestore(tuple, uiState, walletsService));
|
||||
}
|
||||
for (final tuple in firoWallets) {
|
||||
restoreStatuses.add(asyncRestore(tuple, uiState, walletsService));
|
||||
}
|
||||
|
||||
for (Future<bool> status in restoreStatuses) {
|
||||
// check if cancel was requested and restore previous state
|
||||
if (_checkShouldCancel(preRestoreState)) {
|
||||
|
@ -869,13 +709,7 @@ abstract class SWB {
|
|||
}
|
||||
await status;
|
||||
}
|
||||
for (int i = 0; i < epicCashWallets.length; i++) {
|
||||
// check if cancel was requested and restore previous state
|
||||
if (_checkShouldCancel(preRestoreState)) {
|
||||
return false;
|
||||
}
|
||||
await asyncRestore(epicCashWallets[i], uiState, walletsService);
|
||||
}
|
||||
|
||||
if (!Platform.isLinux) await Wakelock.disable();
|
||||
// check if cancel was requested and restore previous state
|
||||
if (_checkShouldCancel(preRestoreState)) {
|
||||
|
|
|
@ -445,7 +445,7 @@ class _StackRestoreProgressViewState
|
|||
},
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getSecondaryEnabledButtonColor(context),
|
||||
.getPrimaryEnabledButtonColor(context),
|
||||
child: Text(
|
||||
_success ? "OK" : "Cancel restore process",
|
||||
style: STextStyles.button(context).copyWith(
|
||||
|
|
|
@ -43,7 +43,7 @@ import 'package:stackwallet/utilities/prefs.dart';
|
|||
import 'package:tuple/tuple.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
const int MINIMUM_CONFIRMATIONS = 3;
|
||||
const int MINIMUM_CONFIRMATIONS = 1;
|
||||
const int DUST_LIMIT = 546;
|
||||
|
||||
const String GENESIS_HASH_MAINNET =
|
||||
|
@ -265,6 +265,11 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
|||
DerivePathType addressType({required String address}) {
|
||||
Uint8List? decodeBase58;
|
||||
Segwit? decodeBech32;
|
||||
try {
|
||||
if (Bitbox.Address.detectFormat(address) == 0) {
|
||||
address = Bitbox.Address.toLegacyAddress(address);
|
||||
}
|
||||
} catch (e, s) {}
|
||||
try {
|
||||
decodeBase58 = bs58check.decode(address);
|
||||
} catch (err) {
|
||||
|
@ -825,9 +830,6 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
|||
/// Refreshes display data for the wallet
|
||||
@override
|
||||
Future<void> refresh() async {
|
||||
final bchaddr = Bitbox.Address.toCashAddress(await currentReceivingAddress);
|
||||
print("bchaddr: $bchaddr ${await currentReceivingAddress}");
|
||||
|
||||
if (refreshMutex) {
|
||||
Logging.instance.log("$walletId $walletName refreshMutex denied",
|
||||
level: LogLevel.Info);
|
||||
|
@ -1384,7 +1386,9 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
|||
initialChangeAddressP2SH, 1, DerivePathType.bip49);
|
||||
|
||||
// this._currentReceivingAddress = Future(() => initialReceivingAddress);
|
||||
_currentReceivingAddressP2PKH = Future(() => initialReceivingAddressP2PKH);
|
||||
|
||||
var newaddr = await _getCurrentAddressForChain(0, DerivePathType.bip44);
|
||||
_currentReceivingAddressP2PKH = Future(() => newaddr);
|
||||
_currentReceivingAddressP2SH = Future(() => initialReceivingAddressP2SH);
|
||||
|
||||
Logging.instance.log("_generateNewWalletFinished", level: LogLevel.Info);
|
||||
|
@ -1521,6 +1525,11 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
|||
print("Array key is ${jsonEncode(arrayKey)}");
|
||||
final internalChainArray =
|
||||
DB.instance.get<dynamic>(boxName: walletId, key: arrayKey);
|
||||
if (derivePathType == DerivePathType.bip44) {
|
||||
if (Bitbox.Address.detectFormat(internalChainArray.last as String) == 1) {
|
||||
return Bitbox.Address.toCashAddress(internalChainArray.last as String);
|
||||
}
|
||||
}
|
||||
return internalChainArray.last as String;
|
||||
}
|
||||
|
||||
|
@ -1986,6 +1995,9 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
|||
/// Returns the scripthash or throws an exception on invalid bch address
|
||||
String _convertToScriptHash(String bchAddress, NetworkType network) {
|
||||
try {
|
||||
if (Bitbox.Address.detectFormat(bchAddress) == 0) {
|
||||
bchAddress = Bitbox.Address.toLegacyAddress(bchAddress);
|
||||
}
|
||||
final output = Address.addressToOutputScript(bchAddress, network);
|
||||
final hash = sha256.convert(output.toList(growable: false)).toString();
|
||||
|
||||
|
@ -2058,11 +2070,27 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
|||
}
|
||||
|
||||
Future<TransactionData> _fetchTransactionData() async {
|
||||
final List<String> allAddresses = await _fetchAllOwnAddresses();
|
||||
List<String> allAddressesOld = await _fetchAllOwnAddresses();
|
||||
List<String> allAddresses = [];
|
||||
for (String address in allAddressesOld) {
|
||||
if (Bitbox.Address.detectFormat(address) == 1) {
|
||||
allAddresses.add(Bitbox.Address.toCashAddress(address));
|
||||
} else {
|
||||
allAddresses.add(address);
|
||||
}
|
||||
}
|
||||
|
||||
final changeAddressesP2PKH =
|
||||
var changeAddressesP2PKHOld =
|
||||
DB.instance.get<dynamic>(boxName: walletId, key: 'changeAddressesP2PKH')
|
||||
as List<dynamic>;
|
||||
List<dynamic> changeAddressesP2PKH = [];
|
||||
for (var address in changeAddressesP2PKHOld) {
|
||||
if (Bitbox.Address.detectFormat(address as String) == 1) {
|
||||
changeAddressesP2PKH.add(Bitbox.Address.toCashAddress(address));
|
||||
} else {
|
||||
changeAddressesP2PKH.add(address);
|
||||
}
|
||||
}
|
||||
|
||||
final List<Map<String, dynamic>> allTxHashes =
|
||||
await _fetchHistory(allAddresses);
|
||||
|
@ -2087,16 +2115,24 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
|||
if (txHeight > 0 &&
|
||||
txHeight < latestTxnBlockHeight - MINIMUM_CONFIRMATIONS) {
|
||||
if (unconfirmedCachedTransactions[tx["tx_hash"] as String] == null) {
|
||||
print(cachedTransactions.findTransaction(tx["tx_hash"] as String));
|
||||
print(unconfirmedCachedTransactions[tx["tx_hash"] as String]);
|
||||
final cachedTx =
|
||||
cachedTransactions.findTransaction(tx["tx_hash"] as String);
|
||||
if (!(cachedTx != null &&
|
||||
addressType(address: cachedTx.address) ==
|
||||
DerivePathType.bip44 &&
|
||||
Bitbox.Address.detectFormat(cachedTx.address) == 1)) {
|
||||
allTxHashes.remove(tx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<Map<String, dynamic>> allTransactions = [];
|
||||
|
||||
for (final txHash in allTxHashes) {
|
||||
Logging.instance.log("bch: $txHash", level: LogLevel.Info);
|
||||
final tx = await cachedElectrumXClient.getTransaction(
|
||||
txHash: txHash["tx_hash"] as String,
|
||||
verbose: true,
|
||||
|
@ -2166,7 +2202,8 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
|||
.log("recipientsArray: $recipientsArray", level: LogLevel.Info);
|
||||
|
||||
final foundInSenders =
|
||||
allAddresses.any((element) => sendersArray.contains(element));
|
||||
allAddresses.any((element) => sendersArray.contains(element)) ||
|
||||
allAddressesOld.any((element) => sendersArray.contains(element));
|
||||
Logging.instance
|
||||
.log("foundInSenders: $foundInSenders", level: LogLevel.Info);
|
||||
|
||||
|
@ -2228,7 +2265,8 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
|||
.toBigInt()
|
||||
.toInt();
|
||||
totalOut += value;
|
||||
if (allAddresses.contains(address)) {
|
||||
if (allAddresses.contains(address) ||
|
||||
allAddressesOld.contains(address)) {
|
||||
outputAmtAddressedToWallet += value;
|
||||
}
|
||||
}
|
||||
|
@ -2743,7 +2781,10 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
|||
for (final output in tx["vout"] as List) {
|
||||
final n = output["n"];
|
||||
if (n != null && n == utxosToUse[i].vout) {
|
||||
final address = output["scriptPubKey"]["addresses"][0] as String;
|
||||
String address = output["scriptPubKey"]["addresses"][0] as String;
|
||||
if (Bitbox.Address.detectFormat(address) == 0) {
|
||||
address = Bitbox.Address.toLegacyAddress(address);
|
||||
}
|
||||
if (!addressTxid.containsKey(address)) {
|
||||
addressTxid[address] = <String>[];
|
||||
}
|
||||
|
@ -2772,8 +2813,13 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
|||
derivePathType: DerivePathType.bip44,
|
||||
);
|
||||
for (int i = 0; i < p2pkhLength; i++) {
|
||||
String address = addressesP2PKH[i];
|
||||
if (Bitbox.Address.detectFormat(address) == 0) {
|
||||
address = Bitbox.Address.toLegacyAddress(address);
|
||||
}
|
||||
|
||||
// receives
|
||||
final receiveDerivation = receiveDerivations[addressesP2PKH[i]];
|
||||
final receiveDerivation = receiveDerivations[address];
|
||||
// if a match exists it will not be null
|
||||
if (receiveDerivation != null) {
|
||||
final data = P2PKH(
|
||||
|
@ -2783,7 +2829,7 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
|||
network: _network,
|
||||
).data;
|
||||
|
||||
for (String tx in addressTxid[addressesP2PKH[i]]!) {
|
||||
for (String tx in addressTxid[address]!) {
|
||||
results[tx] = {
|
||||
"output": data.output,
|
||||
"keyPair": ECPair.fromWIF(
|
||||
|
@ -2794,7 +2840,7 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
|||
}
|
||||
} else {
|
||||
// if its not a receive, check change
|
||||
final changeDerivation = changeDerivations[addressesP2PKH[i]];
|
||||
final changeDerivation = changeDerivations[address];
|
||||
// if a match exists it will not be null
|
||||
if (changeDerivation != null) {
|
||||
final data = P2PKH(
|
||||
|
@ -2804,7 +2850,7 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
|||
network: _network,
|
||||
).data;
|
||||
|
||||
for (String tx in addressTxid[addressesP2PKH[i]]!) {
|
||||
for (String tx in addressTxid[address]!) {
|
||||
results[tx] = {
|
||||
"output": data.output,
|
||||
"keyPair": ECPair.fromWIF(
|
||||
|
@ -3377,8 +3423,9 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
|||
0,
|
||||
DerivePathType
|
||||
.bip44); // Add that new receiving address to the array of receiving addresses
|
||||
_currentReceivingAddressP2PKH = Future(() =>
|
||||
newReceivingAddress); // Set the new receiving address that the service
|
||||
var newaddr = await _getCurrentAddressForChain(0, DerivePathType.bip44);
|
||||
_currentReceivingAddressP2PKH = Future(
|
||||
() => newaddr); // Set the new receiving address that the service
|
||||
|
||||
return true;
|
||||
} catch (e, s) {
|
||||
|
|
|
@ -1990,7 +1990,6 @@ class EpicCashWallet extends CoinServiceAPI {
|
|||
|
||||
Future<bool> refreshIfThereIsNewData() async {
|
||||
if (_hasCalledExit) return false;
|
||||
Logging.instance.log("Can we do this here?", level: LogLevel.Fatal);
|
||||
// TODO returning true here signals this class to call refresh() after which it will fire an event that notifies the UI that new data has been fetched/found for this wallet
|
||||
return true;
|
||||
// TODO: do a quick check to see if there is any new data that would require a refresh
|
||||
|
|
|
@ -39,6 +39,19 @@ class NodeService extends ChangeNotifier {
|
|||
key: savedNode.id,
|
||||
value: defaultNode.copyWith(enabled: savedNode.enabled));
|
||||
}
|
||||
|
||||
// check if a default node is the primary node for the crypto currency
|
||||
// and update it if needed
|
||||
final coin = coinFromPrettyName(defaultNode.coinName);
|
||||
final primaryNode = getPrimaryNodeFor(coin: coin);
|
||||
if (primaryNode != null && primaryNode.id == defaultNode.id) {
|
||||
await setPrimaryNodeFor(
|
||||
coin: coin,
|
||||
node: defaultNode.copyWith(
|
||||
enabled: primaryNode.enabled,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -78,12 +78,12 @@ class PriceAPI {
|
|||
}
|
||||
|
||||
final externalCalls = Prefs.instance.externalCalls;
|
||||
if (!Logger.isTestEnv && !externalCalls) {
|
||||
if ((!Logger.isTestEnv && !externalCalls) ||
|
||||
!(await Prefs.instance.isExternalCallsSet())) {
|
||||
Logging.instance.log("User does not want to use external calls",
|
||||
level: LogLevel.Info);
|
||||
return _cachedPrices;
|
||||
}
|
||||
|
||||
Map<Coin, Tuple2<Decimal, double>> result = {};
|
||||
try {
|
||||
final uri = Uri.parse(
|
||||
|
@ -123,7 +123,8 @@ class PriceAPI {
|
|||
|
||||
static Future<List<String>?> availableBaseCurrencies() async {
|
||||
final externalCalls = Prefs.instance.externalCalls;
|
||||
if (!Logger.isTestEnv && !externalCalls) {
|
||||
if ((!Logger.isTestEnv && !externalCalls) ||
|
||||
!(await Prefs.instance.isExternalCallsSet())) {
|
||||
Logging.instance.log("User does not want to use external calls",
|
||||
level: LogLevel.Info);
|
||||
return null;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
|
||||
class _LayoutSizing {
|
||||
const _LayoutSizing();
|
||||
|
@ -14,7 +15,12 @@ class _LayoutSizing {
|
|||
abstract class Constants {
|
||||
static const size = _LayoutSizing();
|
||||
|
||||
static final bool enableExchange = !Platform.isIOS;
|
||||
static void exchangeForExperiencedUsers(int count) {
|
||||
enableExchange =
|
||||
Util.isDesktop || Platform.isAndroid || count > 5 || !Platform.isIOS;
|
||||
}
|
||||
|
||||
static bool enableExchange = Util.isDesktop || !Platform.isIOS;
|
||||
|
||||
//TODO: correct for monero?
|
||||
static const int satsPerCoinMonero = 1000000000000;
|
||||
|
@ -36,7 +42,7 @@ abstract class Constants {
|
|||
// Enable Logger.print statements
|
||||
static const bool disableLogger = false;
|
||||
|
||||
static const int currentHiveDbVersion = 2;
|
||||
static const int currentHiveDbVersion = 3;
|
||||
|
||||
static List<int> possibleLengthsForCoin(Coin coin) {
|
||||
final List<int> values = [];
|
||||
|
|
|
@ -143,6 +143,18 @@ class DbVersionMigrator {
|
|||
|
||||
// try to continue migrating
|
||||
return await migrate(2);
|
||||
case 2:
|
||||
await Hive.openBox<dynamic>(DB.boxNamePrefs);
|
||||
final prefs = Prefs.instance;
|
||||
await prefs.init();
|
||||
if (!(await prefs.isExternalCallsSet())) {
|
||||
prefs.externalCalls = true;
|
||||
}
|
||||
|
||||
// update version
|
||||
await DB.instance.put<dynamic>(
|
||||
boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 3);
|
||||
return await migrate(3);
|
||||
|
||||
default:
|
||||
// finally return
|
||||
|
|
|
@ -70,28 +70,24 @@ abstract class DefaultNodes {
|
|||
isDown: false,
|
||||
);
|
||||
|
||||
// TODO: eventually enable ssl and set scheme to https
|
||||
// currently get certificate failure
|
||||
static NodeModel get monero => NodeModel(
|
||||
host: "http://monero.stackwallet.com",
|
||||
host: "https://monero.stackwallet.com",
|
||||
port: 18081,
|
||||
name: defaultName,
|
||||
id: _nodeId(Coin.monero),
|
||||
useSSL: false,
|
||||
useSSL: true,
|
||||
enabled: true,
|
||||
coinName: Coin.monero.name,
|
||||
isFailover: true,
|
||||
isDown: false,
|
||||
);
|
||||
|
||||
// TODO: eventually enable ssl and set scheme to https
|
||||
// currently get certificate failure
|
||||
static NodeModel get wownero => NodeModel(
|
||||
host: "http://eu-west-2.wow.xmr.pm",
|
||||
host: "https://wownero.stackwallet.com",
|
||||
port: 34568,
|
||||
name: defaultName,
|
||||
id: _nodeId(Coin.wownero),
|
||||
useSSL: false,
|
||||
useSSL: true,
|
||||
enabled: true,
|
||||
coinName: Coin.wownero.name,
|
||||
isFailover: true,
|
||||
|
|
|
@ -181,25 +181,32 @@ Coin coinFromPrettyName(String name) {
|
|||
case "Bitcoin":
|
||||
case "bitcoin":
|
||||
return Coin.bitcoin;
|
||||
|
||||
case "Bitcoincash":
|
||||
case "bitcoincash":
|
||||
case "Bitcoin Cash":
|
||||
return Coin.bitcoincash;
|
||||
|
||||
case "Dogecoin":
|
||||
case "dogecoin":
|
||||
return Coin.dogecoin;
|
||||
|
||||
case "Epic Cash":
|
||||
case "epicCash":
|
||||
return Coin.epicCash;
|
||||
|
||||
case "Firo":
|
||||
case "firo":
|
||||
return Coin.firo;
|
||||
|
||||
case "Monero":
|
||||
case "monero":
|
||||
return Coin.monero;
|
||||
|
||||
case "Namecoin":
|
||||
case "namecoin":
|
||||
return Coin.namecoin;
|
||||
|
||||
case "Bitcoin Testnet":
|
||||
case "tBitcoin":
|
||||
case "bitcoinTestNet":
|
||||
|
@ -208,19 +215,24 @@ Coin coinFromPrettyName(String name) {
|
|||
case "Bitcoincash Testnet":
|
||||
case "tBitcoin Cash":
|
||||
case "Bitcoin Cash Testnet":
|
||||
case "bitcoincashTestnet":
|
||||
return Coin.bitcoincashTestnet;
|
||||
|
||||
case "Firo Testnet":
|
||||
case "tFiro":
|
||||
case "firoTestNet":
|
||||
return Coin.firoTestNet;
|
||||
|
||||
case "Dogecoin Testnet":
|
||||
case "tDogecoin":
|
||||
case "dogecoinTestNet":
|
||||
return Coin.dogecoinTestNet;
|
||||
|
||||
case "Wownero":
|
||||
case "tWownero":
|
||||
case "wownero":
|
||||
return Coin.wownero;
|
||||
|
||||
default:
|
||||
throw ArgumentError.value(
|
||||
name, "name", "No Coin enum value with that prettyName");
|
||||
|
|
|
@ -571,4 +571,13 @@ class Prefs extends ChangeNotifier {
|
|||
boxName: DB.boxNamePrefs, key: "externalCalls") as bool? ??
|
||||
true;
|
||||
}
|
||||
|
||||
Future<bool> isExternalCallsSet() async {
|
||||
if (await DB.instance
|
||||
.get<dynamic>(boxName: DB.boxNamePrefs, key: "externalCalls") ==
|
||||
null) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -306,10 +306,10 @@ class NodeOptionsSheet extends ConsumerWidget {
|
|||
style: status == "Connected"
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getPrimaryEnabledButtonColor(context)
|
||||
.getPrimaryDisabledButtonColor(context)
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getPrimaryDisabledButtonColor(context),
|
||||
.getPrimaryEnabledButtonColor(context),
|
||||
onPressed: status == "Connected"
|
||||
? null
|
||||
: () async {
|
||||
|
|
|
@ -6,6 +6,7 @@ import FlutterMacOS
|
|||
import Foundation
|
||||
|
||||
import connectivity_plus_macos
|
||||
import device_info_plus
|
||||
import devicelocale
|
||||
import flutter_libepiccash
|
||||
import flutter_local_notifications
|
||||
|
@ -22,6 +23,7 @@ import window_size
|
|||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin"))
|
||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||
DevicelocalePlugin.register(with: registry.registrar(forPlugin: "DevicelocalePlugin"))
|
||||
FlutterLibepiccashPlugin.register(with: registry.registrar(forPlugin: "FlutterLibepiccashPlugin"))
|
||||
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
|
||||
|
|
23
pubspec.lock
23
pubspec.lock
|
@ -380,6 +380,20 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.2.2"
|
||||
device_info_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: device_info_plus
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "7.0.1"
|
||||
device_info_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: device_info_plus_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.0.1"
|
||||
devicelocale:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -1396,7 +1410,14 @@ packages:
|
|||
name: string_scanner
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.1.1"
|
||||
string_validator:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: string_validator
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.0"
|
||||
sync_http:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -11,7 +11,7 @@ description: Stack Wallet
|
|||
# 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.5.8+78
|
||||
version: 1.5.9+79
|
||||
|
||||
environment:
|
||||
sdk: ">=2.17.0 <3.0.0"
|
||||
|
@ -115,6 +115,7 @@ dependencies:
|
|||
wakelock: ^0.6.2
|
||||
intl: ^0.17.0
|
||||
devicelocale: ^0.5.0
|
||||
device_info_plus: ^7.0.1
|
||||
keyboard_dismisser: ^3.0.0
|
||||
another_flushbar: ^1.10.28
|
||||
tuple: ^2.0.0
|
||||
|
@ -132,6 +133,7 @@ dependencies:
|
|||
isar: 3.0.0-dev.10
|
||||
isar_flutter_libs: 3.0.0-dev.10 # contains the binaries
|
||||
dropdown_button2: 1.7.2
|
||||
string_validator: ^0.3.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
47
test/notifications/notification_card_test.dart
Normal file
47
test/notifications/notification_card_test.dart
Normal file
|
@ -0,0 +1,47 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:stackwallet/models/notification_model.dart';
|
||||
import 'package:stackwallet/notifications/notification_card.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/theme/light_colors.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets("test notification card", (widgetTester) async {
|
||||
final key = UniqueKey();
|
||||
final notificationCard = NotificationCard(
|
||||
key: key,
|
||||
notification: NotificationModel(
|
||||
id: 1,
|
||||
title: "notification title",
|
||||
description: "notification description",
|
||||
iconAssetName: Assets.svg.iconFor(coin: Coin.bitcoin),
|
||||
date: DateTime.parse("1662544771"),
|
||||
walletId: "wallet id",
|
||||
read: true,
|
||||
shouldWatchForUpdates: true,
|
||||
coinName: "Bitcoin"),
|
||||
);
|
||||
|
||||
await widgetTester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(
|
||||
extensions: [
|
||||
StackColors.fromStackColorTheme(LightColors()),
|
||||
],
|
||||
),
|
||||
home: Material(
|
||||
child: notificationCard,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byWidget(notificationCard), findsOneWidget);
|
||||
expect(find.text("notification title"), findsOneWidget);
|
||||
expect(find.text("notification description"), findsOneWidget);
|
||||
expect(find.byType(SvgPicture), findsOneWidget);
|
||||
});
|
||||
}
|
157
test/pages/send_view/send_view_test.dart
Normal file
157
test/pages/send_view/send_view_test.dart
Normal file
|
@ -0,0 +1,157 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:stackwallet/models/send_view_auto_fill_data.dart';
|
||||
import 'package:stackwallet/pages/send_view/send_view.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/services/coins/bitcoin/bitcoin_wallet.dart';
|
||||
import 'package:stackwallet/services/coins/coin_service.dart';
|
||||
import 'package:stackwallet/services/coins/manager.dart';
|
||||
import 'package:stackwallet/services/locale_service.dart';
|
||||
import 'package:stackwallet/services/node_service.dart';
|
||||
import 'package:stackwallet/services/wallets.dart';
|
||||
import 'package:stackwallet/services/wallets_service.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/prefs.dart';
|
||||
import 'package:stackwallet/utilities/theme/light_colors.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'send_view_test.mocks.dart';
|
||||
|
||||
@GenerateMocks([
|
||||
Wallets,
|
||||
WalletsService,
|
||||
NodeService,
|
||||
BitcoinWallet,
|
||||
LocaleService,
|
||||
Prefs,
|
||||
], customMocks: [
|
||||
MockSpec<Manager>(returnNullOnMissingStub: true),
|
||||
MockSpec<CoinServiceAPI>(returnNullOnMissingStub: true),
|
||||
])
|
||||
void main() {
|
||||
testWidgets("Send to valid address", (widgetTester) async {
|
||||
final mockWallets = MockWallets();
|
||||
final mockWalletsService = MockWalletsService();
|
||||
final mockNodeService = MockNodeService();
|
||||
final CoinServiceAPI wallet = MockBitcoinWallet();
|
||||
final mockLocaleService = MockLocaleService();
|
||||
final mockPrefs = MockPrefs();
|
||||
|
||||
when(wallet.coin).thenAnswer((_) => Coin.bitcoin);
|
||||
when(wallet.walletName).thenAnswer((_) => "some wallet");
|
||||
when(wallet.walletId).thenAnswer((_) => "wallet id");
|
||||
|
||||
final manager = Manager(wallet);
|
||||
when(mockWallets.getManagerProvider("wallet id")).thenAnswer(
|
||||
(realInvocation) => ChangeNotifierProvider((ref) => manager));
|
||||
when(mockWallets.getManager("wallet id"))
|
||||
.thenAnswer((realInvocation) => manager);
|
||||
|
||||
when(mockLocaleService.locale).thenAnswer((_) => "en_US");
|
||||
when(mockPrefs.currency).thenAnswer((_) => "USD");
|
||||
when(wallet.validateAddress("send to address"))
|
||||
.thenAnswer((realInvocation) => true);
|
||||
|
||||
await widgetTester.pumpWidget(
|
||||
ProviderScope(
|
||||
overrides: [
|
||||
walletsChangeNotifierProvider.overrideWithValue(mockWallets),
|
||||
walletsServiceChangeNotifierProvider
|
||||
.overrideWithValue(mockWalletsService),
|
||||
nodeServiceChangeNotifierProvider.overrideWithValue(mockNodeService),
|
||||
localeServiceChangeNotifierProvider
|
||||
.overrideWithValue(mockLocaleService),
|
||||
prefsChangeNotifierProvider.overrideWithValue(mockPrefs),
|
||||
// previewTxButtonStateProvider
|
||||
],
|
||||
child: MaterialApp(
|
||||
theme: ThemeData(
|
||||
extensions: [
|
||||
StackColors.fromStackColorTheme(
|
||||
LightColors(),
|
||||
),
|
||||
],
|
||||
),
|
||||
home: SendView(
|
||||
walletId: "wallet id",
|
||||
coin: Coin.bitcoin,
|
||||
autoFillData: SendViewAutoFillData(
|
||||
address: "send to address", contactLabel: "contact label"),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.text("Send to"), findsOneWidget);
|
||||
expect(find.text("Amount"), findsOneWidget);
|
||||
expect(find.text("Note (optional)"), findsOneWidget);
|
||||
expect(find.text("Transaction fee (estimated)"), findsOneWidget);
|
||||
verify(manager.validateAddress("send to address")).called(1);
|
||||
});
|
||||
|
||||
testWidgets("Send to invalid address", (widgetTester) async {
|
||||
final mockWallets = MockWallets();
|
||||
final mockWalletsService = MockWalletsService();
|
||||
final mockNodeService = MockNodeService();
|
||||
final CoinServiceAPI wallet = MockBitcoinWallet();
|
||||
final mockLocaleService = MockLocaleService();
|
||||
final mockPrefs = MockPrefs();
|
||||
|
||||
when(wallet.coin).thenAnswer((_) => Coin.bitcoin);
|
||||
when(wallet.walletName).thenAnswer((_) => "some wallet");
|
||||
when(wallet.walletId).thenAnswer((_) => "wallet id");
|
||||
|
||||
final manager = Manager(wallet);
|
||||
when(mockWallets.getManagerProvider("wallet id")).thenAnswer(
|
||||
(realInvocation) => ChangeNotifierProvider((ref) => manager));
|
||||
when(mockWallets.getManager("wallet id"))
|
||||
.thenAnswer((realInvocation) => manager);
|
||||
|
||||
when(mockLocaleService.locale).thenAnswer((_) => "en_US");
|
||||
when(mockPrefs.currency).thenAnswer((_) => "USD");
|
||||
when(wallet.validateAddress("send to address"))
|
||||
.thenAnswer((realInvocation) => false);
|
||||
|
||||
// when(manager.isOwnAddress("send to address"))
|
||||
// .thenAnswer((realInvocation) => Future(() => true));
|
||||
|
||||
await widgetTester.pumpWidget(
|
||||
ProviderScope(
|
||||
overrides: [
|
||||
walletsChangeNotifierProvider.overrideWithValue(mockWallets),
|
||||
walletsServiceChangeNotifierProvider
|
||||
.overrideWithValue(mockWalletsService),
|
||||
nodeServiceChangeNotifierProvider.overrideWithValue(mockNodeService),
|
||||
localeServiceChangeNotifierProvider
|
||||
.overrideWithValue(mockLocaleService),
|
||||
prefsChangeNotifierProvider.overrideWithValue(mockPrefs),
|
||||
// previewTxButtonStateProvider
|
||||
],
|
||||
child: MaterialApp(
|
||||
theme: ThemeData(
|
||||
extensions: [
|
||||
StackColors.fromStackColorTheme(
|
||||
LightColors(),
|
||||
),
|
||||
],
|
||||
),
|
||||
home: SendView(
|
||||
walletId: "wallet id",
|
||||
coin: Coin.bitcoin,
|
||||
autoFillData: SendViewAutoFillData(
|
||||
address: "send to address", contactLabel: "contact label"),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.text("Send to"), findsOneWidget);
|
||||
expect(find.text("Amount"), findsOneWidget);
|
||||
expect(find.text("Note (optional)"), findsOneWidget);
|
||||
expect(find.text("Transaction fee (estimated)"), findsOneWidget);
|
||||
expect(find.text("Invalid address"), findsOneWidget);
|
||||
verify(manager.validateAddress("send to address")).called(1);
|
||||
});
|
||||
}
|
2626
test/pages/send_view/send_view_test.mocks.dart
Normal file
2626
test/pages/send_view/send_view_test.mocks.dart
Normal file
File diff suppressed because it is too large
Load diff
|
@ -16,6 +16,9 @@ void main() {
|
|||
setUp(() async {
|
||||
await setUpTestHive();
|
||||
await Hive.openBox<dynamic>(DB.boxNamePriceCache);
|
||||
await Hive.openBox<dynamic>(DB.boxNamePrefs);
|
||||
await DB.instance.put<dynamic>(
|
||||
boxName: DB.boxNamePrefs, key: "externalCalls", value: true);
|
||||
});
|
||||
|
||||
test("getPricesAnd24hChange fetch", () async {
|
||||
|
|
|
@ -26,7 +26,7 @@ import 'bitcoincash_wallet_test_parameters.dart';
|
|||
void main() {
|
||||
group("bitcoincash constants", () {
|
||||
test("bitcoincash minimum confirmations", () async {
|
||||
expect(MINIMUM_CONFIRMATIONS, 3);
|
||||
expect(MINIMUM_CONFIRMATIONS, 1);
|
||||
});
|
||||
test("bitcoincash dust limit", () async {
|
||||
expect(DUST_LIMIT, 546);
|
||||
|
@ -831,18 +831,9 @@ void main() {
|
|||
|
||||
await bch?.initializeNew();
|
||||
await bch?.initializeExisting();
|
||||
expect(
|
||||
Address.validateAddress(
|
||||
await bch!.currentReceivingAddress, bitcoincashtestnet),
|
||||
true);
|
||||
expect(
|
||||
Address.validateAddress(
|
||||
await bch!.currentReceivingAddress, bitcoincashtestnet),
|
||||
true);
|
||||
expect(
|
||||
Address.validateAddress(
|
||||
await bch!.currentReceivingAddress, bitcoincashtestnet),
|
||||
true);
|
||||
expect(bch?.validateAddress(await bch!.currentReceivingAddress), true);
|
||||
expect(bch?.validateAddress(await bch!.currentReceivingAddress), true);
|
||||
expect(bch?.validateAddress(await bch!.currentReceivingAddress), true);
|
||||
|
||||
verifyNever(client?.ping()).called(0);
|
||||
verify(client?.getServerFeatures()).called(1);
|
||||
|
@ -884,8 +875,7 @@ void main() {
|
|||
expect(addresses?.length, 2);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
expect(
|
||||
Address.validateAddress(addresses![i], bitcoincashtestnet), true);
|
||||
expect(bch?.validateAddress(addresses![i]), true);
|
||||
}
|
||||
|
||||
verifyNever(client?.ping()).called(0);
|
||||
|
|
|
@ -21,12 +21,10 @@ class MockedFunctions extends Mock {
|
|||
|
||||
@GenerateMocks([AddressBookService])
|
||||
void main() {
|
||||
group('Navigation tests', () {
|
||||
late AddressBookService service;
|
||||
setUp(() {
|
||||
service = MockAddressBookService();
|
||||
testWidgets('test returns Contact Address Entry', (widgetTester) async {
|
||||
final service = MockAddressBookService();
|
||||
|
||||
when(service.getContactById("some id"))
|
||||
when(service.getContactById("default"))
|
||||
.thenAnswer((realInvocation) => Contact(
|
||||
name: "John Doe",
|
||||
addresses: [
|
||||
|
@ -36,9 +34,7 @@ void main() {
|
|||
label: "Bills")
|
||||
],
|
||||
isFavorite: true));
|
||||
});
|
||||
|
||||
testWidgets('test returns Contact Address Entry', (widgetTester) async {
|
||||
await widgetTester.pumpWidget(
|
||||
ProviderScope(
|
||||
overrides: [
|
||||
|
@ -55,173 +51,16 @@ void main() {
|
|||
],
|
||||
),
|
||||
home: const AddressBookCard(
|
||||
contactId: "some id",
|
||||
contactId: "default",
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.text("John Doe"), findsOneWidget);
|
||||
expect(find.text("BCH"), findsOneWidget);
|
||||
expect(find.text(Coin.bitcoincash.ticker), findsOneWidget);
|
||||
|
||||
await widgetTester.tap(find.byType(RawMaterialButton));
|
||||
});
|
||||
|
||||
// testWidgets("Test button press opens dialog", (widgetTester) async {
|
||||
// // final service = MockAddressBookService();
|
||||
//
|
||||
// when(service.getContactById("some id"))
|
||||
// .thenAnswer((realInvocation) => Contact(
|
||||
// name: "John Doe",
|
||||
// addresses: [
|
||||
// const ContactAddressEntry(
|
||||
// coin: Coin.bitcoincash,
|
||||
// address: "some bch address",
|
||||
// label: "Bills")
|
||||
// ],
|
||||
// isFavorite: true));
|
||||
//
|
||||
// await widgetTester.pumpWidget(
|
||||
// ProviderScope(
|
||||
// overrides: [
|
||||
// addressBookServiceProvider.overrideWithValue(
|
||||
// service,
|
||||
// ),
|
||||
// ],
|
||||
// child: MaterialApp(
|
||||
// theme: ThemeData(
|
||||
// extensions: [
|
||||
// StackColors.fromStackColorTheme(
|
||||
// LightColors(),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// home: const AddressBookCard(
|
||||
// contactId: "some id",
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// //
|
||||
// // when(service.getContactById("03177ce0-4af4-11ed-9617-af8aa7a3796f"))
|
||||
// // .thenAnswer((realInvocation) => Contact(
|
||||
// // name: "John Doe",
|
||||
// // addresses: [
|
||||
// // const ContactAddressEntry(
|
||||
// // coin: Coin.bitcoincash,
|
||||
// // address: "some bch address",
|
||||
// // label: "Bills")
|
||||
// // ],
|
||||
// // isFavorite: true));
|
||||
// await widgetTester.tap(find.byType(RawMaterialButton));
|
||||
// // verify(MockedFunctions().showDialog()).called(1);
|
||||
// await widgetTester.pump();
|
||||
// when(service.getContactById("03177ce0-4af4-11ed-9617-af8aa7a3796f"))
|
||||
// .thenAnswer((realInvocation) => Contact(
|
||||
// name: "John Doe",
|
||||
// addresses: [
|
||||
// const ContactAddressEntry(
|
||||
// coin: Coin.bitcoincash,
|
||||
// address: "some bch address",
|
||||
// label: "Bills")
|
||||
// ],
|
||||
// isFavorite: true));
|
||||
//
|
||||
// expect(
|
||||
// find.byWidget(const ContactPopUp(
|
||||
// contactId: "03177ce0-4af4-11ed-9617-af8aa7a3796f")),
|
||||
// findsOneWidget);
|
||||
// // await widgetTester.pump();
|
||||
// // // when(contact)
|
||||
// // await widgetTester.pump();
|
||||
// });
|
||||
});
|
||||
|
||||
// testWidgets('test returns Contact Address Entry', (widgetTester) async {
|
||||
// // final service = MockAddressBookService();
|
||||
// // when(service.getContactById("some id"))
|
||||
// // .thenAnswer((realInvocation) => Contact(
|
||||
// // name: "John Doe",
|
||||
// // addresses: [
|
||||
// // const ContactAddressEntry(
|
||||
// // coin: Coin.bitcoincash,
|
||||
// // address: "some bch address",
|
||||
// // label: "Bills")
|
||||
// // ],
|
||||
// // isFavorite: true));
|
||||
//
|
||||
// await widgetTester.pumpWidget(
|
||||
// ProviderScope(
|
||||
// overrides: [
|
||||
// addressBookServiceProvider.overrideWithValue(
|
||||
// serv,
|
||||
// ),
|
||||
// ],
|
||||
// child: MaterialApp(
|
||||
// theme: ThemeData(
|
||||
// extensions: [
|
||||
// StackColors.fromStackColorTheme(
|
||||
// LightColors(),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// home: const AddressBookCard(
|
||||
// contactId: "some id",
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
//
|
||||
// expect(find.text("John Doe"), findsOneWidget);
|
||||
// expect(find.text(Coin.bitcoincash.ticker), findsOneWidget);
|
||||
// });
|
||||
|
||||
// testWidgets("Test button press opens dialog", (widgetTester) async {
|
||||
// final service = MockAddressBookService();
|
||||
//
|
||||
// // when(service.getContactById("some id"))
|
||||
// // .thenAnswer((realInvocation) => Contact(
|
||||
// // name: "John Doe",
|
||||
// // addresses: [
|
||||
// // const ContactAddressEntry(
|
||||
// // coin: Coin.bitcoincash,
|
||||
// // address: "some bch address",
|
||||
// // label: "Bills")
|
||||
// // ],
|
||||
// // isFavorite: true));
|
||||
//
|
||||
// await widgetTester.pumpWidget(
|
||||
// ProviderScope(
|
||||
// overrides: [
|
||||
// addressBookServiceProvider.overrideWithValue(
|
||||
// service,
|
||||
// ),
|
||||
// ],
|
||||
// child: MaterialApp(
|
||||
// theme: ThemeData(
|
||||
// extensions: [
|
||||
// StackColors.fromStackColorTheme(
|
||||
// LightColors(),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// home: const AddressBookCard(
|
||||
// contactId: "03177ce0-4af4-11ed-9617-af8aa7a3796f",
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// //
|
||||
// // when(service.getContactById("03177ce0-4af4-11ed-9617-af8aa7a3796f"))
|
||||
// // .thenAnswer((realInvocation) => Contact(
|
||||
// // name: "John Doe",
|
||||
// // addresses: [
|
||||
// // const ContactAddressEntry(
|
||||
// // coin: Coin.bitcoincash,
|
||||
// // address: "some bch address",
|
||||
// // label: "Bills")
|
||||
// // ],
|
||||
// // isFavorite: true));
|
||||
// // await widgetTester.tap(find.byType(RawMaterialButton));
|
||||
// // // when(contact)
|
||||
// // await widgetTester.pump();
|
||||
// });
|
||||
}
|
||||
|
|
35
test/widget_tests/custom_buttons/favorite_toggle_test.dart
Normal file
35
test/widget_tests/custom_buttons/favorite_toggle_test.dart
Normal file
|
@ -0,0 +1,35 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:stackwallet/utilities/theme/light_colors.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/favorite_toggle.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets("Test widget build", (widgetTester) async {
|
||||
final key = UniqueKey();
|
||||
|
||||
await widgetTester.pumpWidget(
|
||||
ProviderScope(
|
||||
overrides: [],
|
||||
child: MaterialApp(
|
||||
theme: ThemeData(
|
||||
extensions: [
|
||||
StackColors.fromStackColorTheme(
|
||||
LightColors(),
|
||||
),
|
||||
],
|
||||
),
|
||||
home: FavoriteToggle(
|
||||
onChanged: null,
|
||||
key: key,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(FavoriteToggle), findsOneWidget);
|
||||
expect(find.byType(SvgPicture), findsOneWidget);
|
||||
});
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:event_bus/event_bus.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:stackwallet/utilities/theme/light_colors.dart';
|
||||
|
@ -6,8 +7,7 @@ import 'package:stackwallet/widgets/custom_loading_overlay.dart';
|
|||
|
||||
void main() {
|
||||
testWidgets("Test wiget displays correct text", (widgetTester) async {
|
||||
const customLoadingOverlay =
|
||||
CustomLoadingOverlay(message: "Updating exchange rate", eventBus: null);
|
||||
final eventBus = EventBus();
|
||||
await widgetTester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(
|
||||
|
@ -15,8 +15,9 @@ void main() {
|
|||
StackColors.fromStackColorTheme(LightColors()),
|
||||
],
|
||||
),
|
||||
home: const Material(
|
||||
child: customLoadingOverlay,
|
||||
home: Material(
|
||||
child: CustomLoadingOverlay(
|
||||
message: "Updating exchange rate", eventBus: eventBus),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
33
test/widget_tests/desktop/custom_text_button_test.dart
Normal file
33
test/widget_tests/desktop/custom_text_button_test.dart
Normal file
|
@ -0,0 +1,33 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:stackwallet/utilities/theme/light_colors.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/desktop/custom_text_button.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets("Test text button ", (widgetTester) async {
|
||||
final key = UniqueKey();
|
||||
|
||||
await widgetTester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(
|
||||
extensions: [
|
||||
StackColors.fromStackColorTheme(LightColors()),
|
||||
],
|
||||
),
|
||||
home: Material(
|
||||
child: CustomTextButtonBase(
|
||||
key: key,
|
||||
width: 200,
|
||||
height: 300,
|
||||
textButton:
|
||||
const TextButton(onPressed: null, child: Text("Some Text")),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(CustomTextButtonBase), findsOneWidget);
|
||||
});
|
||||
}
|
34
test/widget_tests/desktop/desktop_app_bar_test.dart
Normal file
34
test/widget_tests/desktop/desktop_app_bar_test.dart
Normal file
|
@ -0,0 +1,34 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart';
|
||||
import 'package:stackwallet/utilities/theme/light_colors.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets("Test DesktopAppBar widget", (widgetTester) async {
|
||||
final key = UniqueKey();
|
||||
|
||||
await widgetTester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(
|
||||
extensions: [
|
||||
StackColors.fromStackColorTheme(LightColors()),
|
||||
],
|
||||
),
|
||||
home: Material(
|
||||
child: DesktopAppBar(
|
||||
key: key,
|
||||
isCompactHeight: false,
|
||||
leading: const AppBarBackButton(),
|
||||
trailing: const ExitToMyStackButton(),
|
||||
center: const Text("Some Text"),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(DesktopAppBar), findsOneWidget);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockingjay/mockingjay.dart' as mockingjay;
|
||||
import 'package:stackwallet/utilities/theme/light_colors.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets("test DesktopDialog button pressed", (widgetTester) async {
|
||||
final key = UniqueKey();
|
||||
|
||||
final navigator = mockingjay.MockNavigator();
|
||||
|
||||
await widgetTester.pumpWidget(
|
||||
ProviderScope(
|
||||
overrides: [],
|
||||
child: MaterialApp(
|
||||
theme: ThemeData(
|
||||
extensions: [
|
||||
StackColors.fromStackColorTheme(LightColors()),
|
||||
],
|
||||
),
|
||||
home: mockingjay.MockNavigatorProvider(
|
||||
navigator: navigator,
|
||||
child: DesktopDialogCloseButton(
|
||||
key: key,
|
||||
onPressedOverride: null,
|
||||
)),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await widgetTester.tap(find.byType(AppBarIconButton));
|
||||
await widgetTester.pumpAndSettle();
|
||||
|
||||
mockingjay.verify(() => navigator.pop()).called(1);
|
||||
});
|
||||
}
|
30
test/widget_tests/desktop/desktop_dialog_test.dart
Normal file
30
test/widget_tests/desktop/desktop_dialog_test.dart
Normal file
|
@ -0,0 +1,30 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:stackwallet/utilities/theme/light_colors.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets("test DesktopDialog builds", (widgetTester) async {
|
||||
final key = UniqueKey();
|
||||
|
||||
await widgetTester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(
|
||||
extensions: [
|
||||
StackColors.fromStackColorTheme(LightColors()),
|
||||
],
|
||||
),
|
||||
home: Material(
|
||||
child: DesktopDialog(
|
||||
key: key,
|
||||
child: const DesktopDialogCloseButton(),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(DesktopDialog), findsOneWidget);
|
||||
});
|
||||
}
|
70
test/widget_tests/desktop/desktop_scaffold_test.dart
Normal file
70
test/widget_tests/desktop/desktop_scaffold_test.dart
Normal file
|
@ -0,0 +1,70 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:stackwallet/utilities/theme/light_colors.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets("test DesktopScaffold", (widgetTester) async {
|
||||
final key = UniqueKey();
|
||||
await widgetTester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(
|
||||
extensions: [
|
||||
StackColors.fromStackColorTheme(LightColors()),
|
||||
],
|
||||
),
|
||||
home: Material(
|
||||
child: DesktopScaffold(
|
||||
key: key,
|
||||
body: const SizedBox(),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets("Test MasterScaffold for non desktop", (widgetTester) async {
|
||||
final key = UniqueKey();
|
||||
|
||||
await widgetTester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(
|
||||
extensions: [
|
||||
StackColors.fromStackColorTheme(LightColors()),
|
||||
],
|
||||
),
|
||||
home: Material(
|
||||
child: MasterScaffold(
|
||||
key: key,
|
||||
body: const SizedBox(),
|
||||
appBar: AppBar(),
|
||||
isDesktop: false,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets("Test MasterScaffold for desktop", (widgetTester) async {
|
||||
final key = UniqueKey();
|
||||
|
||||
await widgetTester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(
|
||||
extensions: [
|
||||
StackColors.fromStackColorTheme(LightColors()),
|
||||
],
|
||||
),
|
||||
home: Material(
|
||||
child: MasterScaffold(
|
||||
key: key,
|
||||
body: const SizedBox(),
|
||||
appBar: AppBar(),
|
||||
isDesktop: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
31
test/widget_tests/icon_widgets/addressbook_icon_test.dart
Normal file
31
test/widget_tests/icon_widgets/addressbook_icon_test.dart
Normal file
|
@ -0,0 +1,31 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:stackwallet/utilities/theme/light_colors.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/icon_widgets/addressbook_icon.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets("test address book icon widget", (widgetTester) async {
|
||||
final key = UniqueKey();
|
||||
final addressBookIcon = AddressBookIcon(
|
||||
key: key,
|
||||
);
|
||||
|
||||
await widgetTester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(
|
||||
extensions: [
|
||||
StackColors.fromStackColorTheme(LightColors()),
|
||||
],
|
||||
),
|
||||
home: Material(
|
||||
child: addressBookIcon,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byWidget(addressBookIcon), findsOneWidget);
|
||||
expect(find.byType(SvgPicture), findsOneWidget);
|
||||
});
|
||||
}
|
|
@ -18,6 +18,7 @@ import 'package:stackwallet/widgets/managed_favorite.dart';
|
|||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/theme/light_colors.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
|
||||
import 'managed_favorite_test.mocks.dart';
|
||||
|
||||
|
@ -45,7 +46,8 @@ void main() {
|
|||
.thenAnswer((realInvocation) => manager);
|
||||
|
||||
when(manager.isFavorite).thenAnswer((realInvocation) => false);
|
||||
const managedFavorite = ManagedFavorite(walletId: "some wallet id");
|
||||
final key = UniqueKey();
|
||||
// const managedFavorite = ManagedFavorite(walletId: "some wallet id", key: key,);
|
||||
await widgetTester.pumpWidget(
|
||||
ProviderScope(
|
||||
overrides: [
|
||||
|
@ -59,8 +61,11 @@ void main() {
|
|||
),
|
||||
],
|
||||
),
|
||||
home: const Material(
|
||||
child: managedFavorite,
|
||||
home: Material(
|
||||
child: ManagedFavorite(
|
||||
walletId: "some wallet id",
|
||||
key: key,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -82,7 +82,7 @@ void main() {
|
|||
(realInvocation) => NodeModel(
|
||||
host: "127.0.0.1",
|
||||
port: 2000,
|
||||
name: "Stack Default",
|
||||
name: "Some other node name",
|
||||
id: "node id",
|
||||
useSSL: true,
|
||||
enabled: true,
|
||||
|
@ -94,7 +94,7 @@ void main() {
|
|||
NodeModel(
|
||||
host: "127.0.0.1",
|
||||
port: 2000,
|
||||
name: "Stack Default",
|
||||
name: "Some other node name",
|
||||
id: "node id",
|
||||
useSSL: true,
|
||||
enabled: true,
|
||||
|
@ -122,7 +122,7 @@ void main() {
|
|||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text("Stack Default"), findsOneWidget);
|
||||
expect(find.text("Some other node name"), findsOneWidget);
|
||||
expect(find.text("Connected"), findsOneWidget);
|
||||
expect(find.byType(Text), findsNWidgets(2));
|
||||
expect(find.byType(SvgPicture), findsWidgets);
|
||||
|
|
|
@ -29,7 +29,7 @@ void main() {
|
|||
(realInvocation) => NodeModel(
|
||||
host: "127.0.0.1",
|
||||
port: 2000,
|
||||
name: "Stack Default",
|
||||
name: "Some other name",
|
||||
id: "node id",
|
||||
useSSL: true,
|
||||
enabled: true,
|
||||
|
@ -41,7 +41,7 @@ void main() {
|
|||
(realInvocation) => NodeModel(
|
||||
host: "127.0.0.1",
|
||||
port: 2000,
|
||||
name: "Stack Default",
|
||||
name: "Some other name",
|
||||
id: "node id",
|
||||
useSSL: true,
|
||||
enabled: true,
|
||||
|
@ -72,7 +72,7 @@ void main() {
|
|||
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text("Node options"), findsOneWidget);
|
||||
expect(find.text("Stack Default"), findsOneWidget);
|
||||
expect(find.text("Some other name"), findsOneWidget);
|
||||
expect(find.text("Connected"), findsOneWidget);
|
||||
expect(find.byType(SvgPicture), findsNWidgets(2));
|
||||
expect(find.text("Details"), findsOneWidget);
|
||||
|
@ -204,7 +204,6 @@ void main() {
|
|||
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text("Node options"), findsOneWidget);
|
||||
// expect(find.text("Stack Default"), findsOneWidget);
|
||||
expect(find.text("Disconnected"), findsOneWidget);
|
||||
|
||||
await tester.tap(find.text("Connect"));
|
||||
|
|
35
test/widget_tests/shake/shake_test.dart
Normal file
35
test/widget_tests/shake/shake_test.dart
Normal file
|
@ -0,0 +1,35 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:stackwallet/utilities/theme/light_colors.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/shake/shake.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets("Widget build", (widgetTester) async {
|
||||
await widgetTester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(
|
||||
extensions: [
|
||||
StackColors.fromStackColorTheme(LightColors()),
|
||||
],
|
||||
),
|
||||
home: Material(
|
||||
child: Shake(
|
||||
animationRange: 10,
|
||||
controller: ShakeController(),
|
||||
animationDuration: const Duration(milliseconds: 200),
|
||||
child: Column(
|
||||
children: const [
|
||||
Center(
|
||||
child: Text("Enter Pin"),
|
||||
)
|
||||
],
|
||||
)),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(Shake), findsOneWidget);
|
||||
expect(find.byType(Text), findsOneWidget);
|
||||
});
|
||||
}
|
55
test/widget_tests/trade_card_test.dart
Normal file
55
test/widget_tests/trade_card_test.dart
Normal file
|
@ -0,0 +1,55 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
|
||||
import 'package:stackwallet/utilities/theme/light_colors.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/trade_card.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets("Test Trade card builds", (widgetTester) async {
|
||||
final trade = Trade(
|
||||
uuid: "uuid",
|
||||
tradeId: "trade id",
|
||||
rateType: "Estimate rate",
|
||||
direction: "",
|
||||
timestamp: DateTime.parse("1662544771"),
|
||||
updatedAt: DateTime.parse("1662544771"),
|
||||
payInCurrency: "BTC",
|
||||
payInAmount: "10",
|
||||
payInAddress: "btc address",
|
||||
payInNetwork: "",
|
||||
payInExtraId: "",
|
||||
payInTxid: "",
|
||||
payOutCurrency: "xmr",
|
||||
payOutAmount: "10",
|
||||
payOutAddress: "xmr address",
|
||||
payOutNetwork: "",
|
||||
payOutExtraId: "",
|
||||
payOutTxid: "",
|
||||
refundAddress: "refund address",
|
||||
refundExtraId: "",
|
||||
status: "Failed",
|
||||
exchangeName: "Some Exchange");
|
||||
|
||||
await widgetTester.pumpWidget(
|
||||
ProviderScope(
|
||||
overrides: [],
|
||||
child: MaterialApp(
|
||||
theme: ThemeData(
|
||||
extensions: [
|
||||
StackColors.fromStackColorTheme(
|
||||
LightColors(),
|
||||
),
|
||||
],
|
||||
),
|
||||
home: TradeCard(trade: trade, onTap: () {}),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(TradeCard), findsOneWidget);
|
||||
expect(find.text("BTC → XMR"), findsOneWidget);
|
||||
expect(find.text("Some Exchange"), findsOneWidget);
|
||||
});
|
||||
}
|
|
@ -131,6 +131,99 @@ void main() {
|
|||
verifyNoMoreInteractions(mockLocaleService);
|
||||
});
|
||||
|
||||
testWidgets("Anonymized confirmed tx displays correctly", (tester) async {
|
||||
final mockManager = MockManager();
|
||||
final mockLocaleService = MockLocaleService();
|
||||
final wallets = MockWallets();
|
||||
final mockPrefs = MockPrefs();
|
||||
final mockPriceService = MockPriceService();
|
||||
|
||||
final tx = Transaction(
|
||||
txid: "some txid",
|
||||
confirmedStatus: true,
|
||||
timestamp: 1648595998,
|
||||
txType: "Anonymized",
|
||||
amount: 100000000,
|
||||
aliens: [],
|
||||
worthNow: "0.01",
|
||||
worthAtBlockTimestamp: "0.01",
|
||||
fees: 3794,
|
||||
inputSize: 1,
|
||||
outputSize: 1,
|
||||
inputs: [],
|
||||
outputs: [],
|
||||
address: "",
|
||||
height: 450123,
|
||||
subType: "mint",
|
||||
confirmations: 10,
|
||||
isCancelled: false);
|
||||
|
||||
final CoinServiceAPI wallet = MockFiroWallet();
|
||||
|
||||
when(wallet.coin.ticker).thenAnswer((_) => "FIRO");
|
||||
when(mockLocaleService.locale).thenAnswer((_) => "en_US");
|
||||
when(mockPrefs.currency).thenAnswer((_) => "USD");
|
||||
when(mockPrefs.externalCalls).thenAnswer((_) => true);
|
||||
when(mockPriceService.getPrice(Coin.firo))
|
||||
.thenAnswer((realInvocation) => Tuple2(Decimal.ten, 0.00));
|
||||
|
||||
when(wallet.coin).thenAnswer((_) => Coin.firo);
|
||||
|
||||
when(wallets.getManager("wallet-id"))
|
||||
.thenAnswer((realInvocation) => Manager(wallet));
|
||||
//
|
||||
await tester.pumpWidget(
|
||||
ProviderScope(
|
||||
overrides: [
|
||||
walletsChangeNotifierProvider.overrideWithValue(wallets),
|
||||
localeServiceChangeNotifierProvider
|
||||
.overrideWithValue(mockLocaleService),
|
||||
prefsChangeNotifierProvider.overrideWithValue(mockPrefs),
|
||||
priceAnd24hChangeNotifierProvider.overrideWithValue(mockPriceService)
|
||||
],
|
||||
child: MaterialApp(
|
||||
theme: ThemeData(
|
||||
extensions: [
|
||||
StackColors.fromStackColorTheme(
|
||||
LightColors(),
|
||||
),
|
||||
],
|
||||
),
|
||||
home: TransactionCard(transaction: tx, walletId: "wallet-id"),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
//
|
||||
final title = find.text("Anonymized");
|
||||
// final price1 = find.text("0.00 USD");
|
||||
final amount = find.text("1.00000000 FIRO");
|
||||
|
||||
final icon = find.byIcon(FeatherIcons.arrowUp);
|
||||
|
||||
expect(title, findsOneWidget);
|
||||
// expect(price1, findsOneWidget);
|
||||
expect(amount, findsOneWidget);
|
||||
// expect(icon, findsOneWidget);
|
||||
//
|
||||
await tester.pumpAndSettle(Duration(seconds: 2));
|
||||
//
|
||||
// final price2 = find.text("\$10.00");
|
||||
// expect(price2, findsOneWidget);
|
||||
//
|
||||
// verify(mockManager.addListener(any)).called(1);
|
||||
verify(mockLocaleService.addListener(any)).called(1);
|
||||
|
||||
verify(mockPrefs.currency).called(1);
|
||||
verify(mockPriceService.getPrice(Coin.firo)).called(1);
|
||||
verify(wallet.coin.ticker).called(1);
|
||||
|
||||
verify(mockLocaleService.locale).called(1);
|
||||
|
||||
verifyNoMoreInteractions(mockManager);
|
||||
verifyNoMoreInteractions(mockLocaleService);
|
||||
});
|
||||
|
||||
testWidgets("Received unconfirmed tx displays correctly", (tester) async {
|
||||
final mockManager = MockManager();
|
||||
final mockLocaleService = MockLocaleService();
|
||||
|
|
Loading…
Reference in a new issue