Merge main into cw-linux

This commit is contained in:
Rafael Saes 2023-09-06 17:44:55 -03:00
parent 39cfa265b0
commit e39d5c6af4
89 changed files with 1400 additions and 654 deletions
.github/workflows
assets/text
cw_bitcoin
cw_core
cw_ethereum/lib
cw_haven
cw_monero
ios
lib
macos
model_generator.sh
res/values
scripts
tool

View file

@ -1,6 +1,7 @@
name: Cache Dependencies name: Cache Dependencies
on: on:
workflow_dispatch:
push: push:
branches: [ main ] branches: [ main ]
@ -45,7 +46,7 @@ jobs:
/opt/android/cake_wallet/cw_monero/android/.cxx /opt/android/cake_wallet/cw_monero/android/.cxx
/opt/android/cake_wallet/cw_monero/ios/External /opt/android/cake_wallet/cw_monero/ios/External
/opt/android/cake_wallet/cw_shared_external/ios/External /opt/android/cake_wallet/cw_shared_external/ios/External
key: ${{ hashFiles('**/build_monero.sh', '**/build_haven.sh') }} key: ${{ hashFiles('**/build_monero.sh', '**/build_haven.sh', '**/monero_api.cpp') }}
- if: ${{ steps.cache-externals.outputs.cache-hit != 'true' }} - if: ${{ steps.cache-externals.outputs.cache-hit != 'true' }}
name: Generate Externals name: Generate Externals

View file

@ -163,7 +163,11 @@ jobs:
- name: Send Test APK - name: Send Test APK
continue-on-error: true continue-on-error: true
run: | uses: adrey/slack-file-upload-action@1.0.5
cd /opt/android/cake_wallet with:
var=$(curl --upload-file build/app/outputs/apk/release/app-release.apk https://transfer.sh/$GITHUB_HEAD_REF.apk -H "Max-Days: 10") token: ${{ secrets.SLACK_APP_TOKEN }}
curl ${{ secrets.SLACK_WEB_HOOK }} -H "Content-Type: application/json" -d '{"apk_link": "'"$var"'","ticket": "'"$GITHUB_HEAD_REF"'"}' path: /opt/android/cake_wallet/build/app/outputs/apk/release/app-release.apk
channel: ${{ secrets.SLACK_APK_CHANNEL }}
title: '${{github.head_ref}}.apk'
filename: ${{github.head_ref}}.apk
initial_comment: ${{ github.event.head_commit.message }}

View file

@ -1,2 +1,5 @@
Bug fixes Ability to Auto generate new Monero subaddress when used
Fiat Onramp improvements Coin Control for Monero
In-app Live Chat support
Additional themes
Bug Fixes and performance enhancements

View file

@ -1,2 +1,6 @@
Bug fixes Restore Ethereum from private key and QR
Fiat Onramp improvements Ability to Auto generate new Monero subaddress when used
Coin Control for Monero
In-app Live Chat support
Additional themes
Bug Fixes and performance enhancements

View file

@ -37,19 +37,19 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: async name: async
sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.10.0" version: "2.11.0"
bech32: bech32:
dependency: transitive dependency: transitive
description: description:
path: "." path: "."
ref: "cake-0.2.1" ref: "cake-0.2.2"
resolved-ref: cafd1c270641e95017d57d69f55cca9831d4db56 resolved-ref: "05755063b593aa6cca0a4820a318e0ce17de6192"
url: "https://github.com/cake-tech/bech32.git" url: "https://github.com/cake-tech/bech32.git"
source: git source: git
version: "0.2.1" version: "0.2.2"
bip32: bip32:
dependency: transitive dependency: transitive
description: description:
@ -70,8 +70,8 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
path: "." path: "."
ref: cake-update-v2 ref: cake-update-v3
resolved-ref: "8f86453761c0c26e368392d0ff2c6f12f3b7397b" resolved-ref: df9204144011ed9419eff7d9ef3143102a40252d
url: "https://github.com/cake-tech/bitcoin_flutter.git" url: "https://github.com/cake-tech/bitcoin_flutter.git"
source: git source: git
version: "2.0.2" version: "2.0.2"
@ -168,10 +168,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: characters name: characters
sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.1" version: "1.3.0"
checked_yaml: checked_yaml:
dependency: transitive dependency: transitive
description: description:
@ -200,18 +200,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: collection name: collection
sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.17.0" version: "1.17.1"
convert: convert:
dependency: transitive dependency: transitive
description: description:
name: convert name: convert
sha256: "196284f26f69444b7f5c50692b55ec25da86d9e500451dc09333bf2e3ad69259" sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.2" version: "3.1.1"
crypto: crypto:
dependency: transitive dependency: transitive
description: description:
@ -361,10 +361,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: http name: http
sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.13.5" version: "1.1.0"
http_multi_server: http_multi_server:
dependency: transitive dependency: transitive
description: description:
@ -385,10 +385,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: intl name: intl
sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.17.0" version: "0.18.1"
io: io:
dependency: transitive dependency: transitive
description: description:
@ -401,10 +401,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: js name: js
sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.6.5" version: "0.6.7"
json_annotation: json_annotation:
dependency: transitive dependency: transitive
description: description:
@ -425,10 +425,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.12.13" version: "0.12.15"
material_color_utilities: material_color_utilities:
dependency: transitive dependency: transitive
description: description:
@ -441,10 +441,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.8.0" version: "1.9.1"
mime: mime:
dependency: transitive dependency: transitive
description: description:
@ -481,10 +481,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: path name: path
sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.8.2" version: "1.8.3"
path_provider: path_provider:
dependency: "direct main" dependency: "direct main"
description: description:
@ -686,10 +686,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.4.16" version: "0.5.1"
timing: timing:
dependency: transitive dependency: transitive
description: description:
@ -771,5 +771,5 @@ packages:
source: hosted source: hosted
version: "3.1.1" version: "3.1.1"
sdks: sdks:
dart: ">=2.19.0 <3.0.0" dart: ">=3.0.0 <4.0.0"
flutter: ">=3.0.0" flutter: ">=3.0.0"

View file

@ -0,0 +1,21 @@
import 'package:cw_core/hive_type_ids.dart';
import 'package:hive/hive.dart';
part 'address_info.g.dart';
@HiveType(typeId: ADDRESS_INFO_TYPE_ID)
class AddressInfo extends HiveObject {
AddressInfo({required this.address, this.accountIndex, required this.label});
static const typeId = ADDRESS_INFO_TYPE_ID;
static const boxName = 'AddressInfo';
@HiveField(0)
int? accountIndex;
@HiveField(1, defaultValue: '')
String address;
@HiveField(2, defaultValue: '')
String label;
}

View file

@ -0,0 +1,4 @@
import 'package:hive/hive.dart';
import 'package:hive/src/hive_impl.dart';
final HiveInterface CakeHive = HiveImpl();

View file

@ -1,4 +1,5 @@
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/hive_type_ids.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
part 'erc20_token.g.dart'; part 'erc20_token.g.dart';
@ -53,7 +54,7 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
iconPath: icon, iconPath: icon,
); );
static const typeId = 12; static const typeId = ERC20_TOKEN_TYPE_ID;
static const boxName = 'Erc20Tokens'; static const boxName = 'Erc20Tokens';
@override @override

View file

@ -0,0 +1,13 @@
const CONTACT_TYPE_ID = 0;
const NODE_TYPE_ID = 1;
const TRANSACTION_TYPE_ID = 2;
const TRADE_TYPE_ID = 3;
const WALLET_INFO_TYPE_ID = 4;
const WALLET_TYPE_TYPE_ID = 5;
const TEMPLATE_TYPE_ID = 6;
const EXCHANGE_TEMPLATE_TYPE_ID = 7;
const ORDER_TYPE_ID = 8;
const UNSPENT_COINS_INFO_TYPE_ID = 9;
const ANONPAY_INVOICE_INFO_TYPE_ID = 10;
const ADDRESS_INFO_TYPE_ID = 11;
const ERC20_TOKEN_TYPE_ID = 12;

View file

@ -1,8 +1,10 @@
import 'package:cw_core/address_info.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
abstract class WalletAddresses { abstract class WalletAddresses {
WalletAddresses(this.walletInfo) WalletAddresses(this.walletInfo)
: addressesMap = {}; : addressesMap = {},
addressInfos = {};
final WalletInfo walletInfo; final WalletInfo walletInfo;
@ -12,6 +14,10 @@ abstract class WalletAddresses {
Map<String, String> addressesMap; Map<String, String> addressesMap;
Map<int, List<AddressInfo>> addressInfos;
Set<String> usedAddresses = {};
Future<void> init(); Future<void> init();
Future<void> updateAddressesInBox(); Future<void> updateAddressesInBox();
@ -20,6 +26,8 @@ abstract class WalletAddresses {
try { try {
walletInfo.address = address; walletInfo.address = address;
walletInfo.addresses = addressesMap; walletInfo.addresses = addressesMap;
walletInfo.addressInfos = addressInfos;
walletInfo.usedAddresses = usedAddresses.toList();
if (walletInfo.isInBox) { if (walletInfo.isInBox) {
await walletInfo.save(); await walletInfo.save();

View file

@ -52,6 +52,10 @@ abstract class WalletBase<
late HistoryType transactionHistory; late HistoryType transactionHistory;
set isEnabledAutoGenerateSubaddress(bool value) {}
bool get isEnabledAutoGenerateSubaddress => false;
Future<void> connectToNode({required Node node}); Future<void> connectToNode({required Node node});
Future<void> startSync(); Future<void> startSync();

View file

@ -1,7 +1,8 @@
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'dart:async'; import 'dart:async';
import 'package:cw_core/address_info.dart';
import 'package:cw_core/hive_type_ids.dart';
part 'wallet_info.g.dart'; part 'wallet_info.g.dart';
@ -30,7 +31,7 @@ class WalletInfo extends HiveObject {
yatEid, yatLastUsedAddressRaw, showIntroCakePayCard); yatEid, yatLastUsedAddressRaw, showIntroCakePayCard);
} }
static const typeId = 4; static const typeId = WALLET_INFO_TYPE_ID;
static const boxName = 'WalletInfo'; static const boxName = 'WalletInfo';
@HiveField(0, defaultValue: '') @HiveField(0, defaultValue: '')
@ -72,6 +73,12 @@ class WalletInfo extends HiveObject {
@HiveField(13) @HiveField(13)
bool? showIntroCakePayCard; bool? showIntroCakePayCard;
@HiveField(14)
Map<int, List<AddressInfo>>? addressInfos;
@HiveField(15)
List<String>? usedAddresses;
String get yatLastUsedAddress => yatLastUsedAddressRaw ?? ''; String get yatLastUsedAddress => yatLastUsedAddressRaw ?? '';
set yatLastUsedAddress(String address) { set yatLastUsedAddress(String address) {

View file

@ -5,191 +5,218 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: _fe_analyzer_shared name: _fe_analyzer_shared
url: "https://pub.dartlang.org" sha256: "4897882604d919befd350648c7f91926a9d5de99e67b455bf0917cc2362f4bb8"
url: "https://pub.dev"
source: hosted source: hosted
version: "47.0.0" version: "47.0.0"
analyzer: analyzer:
dependency: transitive dependency: transitive
description: description:
name: analyzer name: analyzer
url: "https://pub.dartlang.org" sha256: "690e335554a8385bc9d787117d9eb52c0c03ee207a607e593de3c9d71b1cfe80"
url: "https://pub.dev"
source: hosted source: hosted
version: "4.7.0" version: "4.7.0"
args: args:
dependency: transitive dependency: transitive
description: description:
name: args name: args
url: "https://pub.dartlang.org" sha256: "139d809800a412ebb26a3892da228b2d0ba36f0ef5d9a82166e5e52ec8d61611"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.0" version: "2.3.2"
asn1lib: asn1lib:
dependency: transitive dependency: transitive
description: description:
name: asn1lib name: asn1lib
url: "https://pub.dartlang.org" sha256: ab96a1cb3beeccf8145c52e449233fe68364c9641623acd3adad66f8184f1039
url: "https://pub.dev"
source: hosted source: hosted
version: "1.4.0" version: "1.4.0"
async: async:
dependency: transitive dependency: transitive
description: description:
name: async name: async
url: "https://pub.dartlang.org" sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.9.0" version: "2.11.0"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
name: boolean_selector name: boolean_selector
url: "https://pub.dartlang.org" sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.0" version: "2.1.1"
build: build:
dependency: transitive dependency: transitive
description: description:
name: build name: build
url: "https://pub.dartlang.org" sha256: "3fbda25365741f8251b39f3917fb3c8e286a96fd068a5a242e11c2012d495777"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.1" version: "2.3.1"
build_config: build_config:
dependency: transitive dependency: transitive
description: description:
name: build_config name: build_config
url: "https://pub.dartlang.org" sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.1" version: "1.1.1"
build_daemon: build_daemon:
dependency: transitive dependency: transitive
description: description:
name: build_daemon name: build_daemon
url: "https://pub.dartlang.org" sha256: "6bc5544ea6ce4428266e7ea680e945c68806c4aae2da0eb5e9ccf38df8d6acbf"
url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.1" version: "3.1.0"
build_resolvers: build_resolvers:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: build_resolvers name: build_resolvers
url: "https://pub.dartlang.org" sha256: "687cf90a3951affac1bd5f9ecb5e3e90b60487f3d9cdc359bb310f8876bb02a6"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.10" version: "2.0.10"
build_runner: build_runner:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: build_runner name: build_runner
url: "https://pub.dartlang.org" sha256: b0a8a7b8a76c493e85f1b84bffa0588859a06197863dba8c9036b15581fd9727
url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.3" version: "2.3.3"
build_runner_core: build_runner_core:
dependency: transitive dependency: transitive
description: description:
name: build_runner_core name: build_runner_core
url: "https://pub.dartlang.org" sha256: "14febe0f5bac5ae474117a36099b4de6f1dbc52df6c5e55534b3da9591bf4292"
url: "https://pub.dev"
source: hosted source: hosted
version: "7.2.7" version: "7.2.7"
built_collection: built_collection:
dependency: transitive dependency: transitive
description: description:
name: built_collection name: built_collection
url: "https://pub.dartlang.org" sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
url: "https://pub.dev"
source: hosted source: hosted
version: "5.1.1" version: "5.1.1"
built_value: built_value:
dependency: transitive dependency: transitive
description: description:
name: built_value name: built_value
url: "https://pub.dartlang.org" sha256: "169565c8ad06adb760c3645bf71f00bff161b00002cace266cad42c5d22a7725"
url: "https://pub.dev"
source: hosted source: hosted
version: "8.4.4" version: "8.4.3"
characters: characters:
dependency: transitive dependency: transitive
description: description:
name: characters name: characters
url: "https://pub.dartlang.org" sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.1" version: "1.3.0"
checked_yaml: checked_yaml:
dependency: transitive dependency: transitive
description: description:
name: checked_yaml name: checked_yaml
url: "https://pub.dartlang.org" sha256: "3d1505d91afa809d177efd4eed5bb0eb65805097a1463abdd2add076effae311"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.2" version: "2.0.2"
clock: clock:
dependency: transitive dependency: transitive
description: description:
name: clock name: clock
url: "https://pub.dartlang.org" sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.1" version: "1.1.1"
code_builder: code_builder:
dependency: transitive dependency: transitive
description: description:
name: code_builder name: code_builder
url: "https://pub.dartlang.org" sha256: "0d43dd1288fd145de1ecc9a3948ad4a6d5a82f0a14c4fdd0892260787d975cbe"
url: "https://pub.dev"
source: hosted source: hosted
version: "4.4.0" version: "4.4.0"
collection: collection:
dependency: transitive dependency: transitive
description: description:
name: collection name: collection
url: "https://pub.dartlang.org" sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.16.0" version: "1.17.1"
convert: convert:
dependency: transitive dependency: transitive
description: description:
name: convert name: convert
url: "https://pub.dartlang.org" sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.1" version: "3.1.1"
crypto: crypto:
dependency: transitive dependency: transitive
description: description:
name: crypto name: crypto
url: "https://pub.dartlang.org" sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67
url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.2" version: "3.0.2"
dart_style: dart_style:
dependency: transitive dependency: transitive
description: description:
name: dart_style name: dart_style
url: "https://pub.dartlang.org" sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.4" version: "2.2.4"
encrypt: encrypt:
dependency: "direct main" dependency: "direct main"
description: description:
name: encrypt name: encrypt
url: "https://pub.dartlang.org" sha256: "4fd4e4fdc21b9d7d4141823e1e6515cd94e7b8d84749504c232999fba25d9bbb"
url: "https://pub.dev"
source: hosted source: hosted
version: "5.0.1" version: "5.0.1"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
name: fake_async name: fake_async
url: "https://pub.dartlang.org" sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.1" version: "1.3.1"
ffi: ffi:
dependency: transitive dependency: transitive
description: description:
name: ffi name: ffi
url: "https://pub.dartlang.org" sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978
url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "2.0.1"
file: file:
dependency: "direct main" dependency: "direct main"
description: description:
name: file name: file
url: "https://pub.dartlang.org" sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d"
url: "https://pub.dev"
source: hosted source: hosted
version: "6.1.4" version: "6.1.4"
fixnum: fixnum:
dependency: transitive dependency: transitive
description: description:
name: fixnum name: fixnum
url: "https://pub.dartlang.org" sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.1" version: "1.1.0"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -199,7 +226,8 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_mobx name: flutter_mobx
url: "https://pub.dartlang.org" sha256: "0da4add0016387a7bf309a0d0c41d36c6b3ae25ed7a176409267f166509e723e"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.6+5" version: "2.0.6+5"
flutter_test: flutter_test:
@ -211,252 +239,288 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: frontend_server_client name: frontend_server_client
url: "https://pub.dartlang.org" sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612"
url: "https://pub.dev"
source: hosted source: hosted
version: "3.2.0" version: "3.2.0"
glob: glob:
dependency: transitive dependency: transitive
description: description:
name: glob name: glob
url: "https://pub.dartlang.org" sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.1.1"
graphs: graphs:
dependency: transitive dependency: transitive
description: description:
name: graphs name: graphs
url: "https://pub.dartlang.org" sha256: f9e130f3259f52d26f0cfc0e964513796dafed572fa52e45d2f8d6ca14db39b2
url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.0" version: "2.2.0"
hive: hive:
dependency: transitive dependency: transitive
description: description:
name: hive name: hive
url: "https://pub.dartlang.org" sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.3" version: "2.2.3"
hive_generator: hive_generator:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: hive_generator name: hive_generator
url: "https://pub.dartlang.org" sha256: "81fd20125cb2ce8fd23623d7744ffbaf653aae93706c9bd3bf7019ea0ace3938"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.3" version: "1.1.3"
http: http:
dependency: "direct main" dependency: "direct main"
description: description:
name: http name: http
url: "https://pub.dartlang.org" sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
url: "https://pub.dev"
source: hosted source: hosted
version: "0.13.5" version: "1.1.0"
http_multi_server: http_multi_server:
dependency: transitive dependency: transitive
description: description:
name: http_multi_server name: http_multi_server
url: "https://pub.dartlang.org" sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
url: "https://pub.dev"
source: hosted source: hosted
version: "3.2.1" version: "3.2.1"
http_parser: http_parser:
dependency: transitive dependency: transitive
description: description:
name: http_parser name: http_parser
url: "https://pub.dartlang.org" sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.2" version: "4.0.2"
intl: intl:
dependency: "direct main" dependency: "direct main"
description: description:
name: intl name: intl
url: "https://pub.dartlang.org" sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
url: "https://pub.dev"
source: hosted source: hosted
version: "0.17.0" version: "0.18.1"
io: io:
dependency: transitive dependency: transitive
description: description:
name: io name: io
url: "https://pub.dartlang.org" sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.4" version: "1.0.4"
js: js:
dependency: transitive dependency: transitive
description: description:
name: js name: js
url: "https://pub.dartlang.org" sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
url: "https://pub.dev"
source: hosted source: hosted
version: "0.6.5" version: "0.6.7"
json_annotation: json_annotation:
dependency: transitive dependency: transitive
description: description:
name: json_annotation name: json_annotation
url: "https://pub.dartlang.org" sha256: c33da08e136c3df0190bd5bbe51ae1df4a7d96e7954d1d7249fea2968a72d317
url: "https://pub.dev"
source: hosted source: hosted
version: "4.8.0" version: "4.8.0"
logging: logging:
dependency: transitive dependency: transitive
description: description:
name: logging name: logging
url: "https://pub.dartlang.org" sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.1" version: "1.1.1"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
url: "https://pub.dartlang.org" sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
url: "https://pub.dev"
source: hosted source: hosted
version: "0.12.12" version: "0.12.15"
material_color_utilities: material_color_utilities:
dependency: transitive dependency: transitive
description: description:
name: material_color_utilities name: material_color_utilities
url: "https://pub.dartlang.org" sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
url: "https://pub.dev"
source: hosted source: hosted
version: "0.1.5" version: "0.2.0"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
url: "https://pub.dartlang.org" sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.8.0" version: "1.9.1"
mime: mime:
dependency: transitive dependency: transitive
description: description:
name: mime name: mime
url: "https://pub.dartlang.org" sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e
url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.4" version: "1.0.4"
mobx: mobx:
dependency: "direct main" dependency: "direct main"
description: description:
name: mobx name: mobx
url: "https://pub.dartlang.org" sha256: f1862bd92c6a903fab67338f27e2f731117c3cb9ea37cee1a487f9e4e0de314a
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.4" version: "2.1.3+1"
mobx_codegen: mobx_codegen:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: mobx_codegen name: mobx_codegen
url: "https://pub.dartlang.org" sha256: "86122e410d8ea24dda0c69adb5c2a6ccadd5ce02ad46e144764e0d0184a06181"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.1.1"
package_config: package_config:
dependency: transitive dependency: transitive
description: description:
name: package_config name: package_config
url: "https://pub.dartlang.org" sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.0" version: "2.1.0"
path: path:
dependency: transitive dependency: transitive
description: description:
name: path name: path
url: "https://pub.dartlang.org" sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.8.2" version: "1.8.3"
path_provider: path_provider:
dependency: "direct main" dependency: "direct main"
description: description:
name: path_provider name: path_provider
url: "https://pub.dartlang.org" sha256: dcea5feb97d8abf90cab9e9030b497fb7c3cbf26b7a1fe9e3ef7dcb0a1ddec95
url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.13" version: "2.0.12"
path_provider_android: path_provider_android:
dependency: transitive dependency: transitive
description: description:
name: path_provider_android name: path_provider_android
url: "https://pub.dartlang.org" sha256: a776c088d671b27f6e3aa8881d64b87b3e80201c64e8869b811325de7a76c15e
url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.24" version: "2.0.22"
path_provider_foundation: path_provider_foundation:
dependency: transitive dependency: transitive
description: description:
name: path_provider_foundation name: path_provider_foundation
url: "https://pub.dartlang.org" sha256: "62a68e7e1c6c459f9289859e2fae58290c981ce21d1697faf54910fe1faa4c74"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.3" version: "2.1.1"
path_provider_linux: path_provider_linux:
dependency: transitive dependency: transitive
description: description:
name: path_provider_linux name: path_provider_linux
url: "https://pub.dartlang.org" sha256: ab0987bf95bc591da42dffb38c77398fc43309f0b9b894dcc5d6f40c4b26c379
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.10" version: "2.1.7"
path_provider_platform_interface: path_provider_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: path_provider_platform_interface name: path_provider_platform_interface
url: "https://pub.dartlang.org" sha256: f0abc8ebd7253741f05488b4813d936b4d07c6bae3e86148a09e342ee4b08e76
url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.6" version: "2.0.5"
path_provider_windows: path_provider_windows:
dependency: transitive dependency: transitive
description: description:
name: path_provider_windows name: path_provider_windows
url: "https://pub.dartlang.org" sha256: bcabbe399d4042b8ee687e17548d5d3f527255253b4a639f5f8d2094a9c2b45c
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.5" version: "2.1.3"
platform: platform:
dependency: transitive dependency: transitive
description: description:
name: platform name: platform
url: "https://pub.dartlang.org" sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76"
url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.0" version: "3.1.0"
plugin_platform_interface: plugin_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: plugin_platform_interface name: plugin_platform_interface
url: "https://pub.dartlang.org" sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.4" version: "2.1.3"
pointycastle: pointycastle:
dependency: transitive dependency: transitive
description: description:
name: pointycastle name: pointycastle
url: "https://pub.dartlang.org" sha256: db7306cf0249f838d1a24af52b5a5887c5bf7f31d8bb4e827d071dc0939ad346
url: "https://pub.dev"
source: hosted source: hosted
version: "3.6.2" version: "3.6.2"
pool: pool:
dependency: transitive dependency: transitive
description: description:
name: pool name: pool
url: "https://pub.dartlang.org" sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.5.1" version: "1.5.1"
process: process:
dependency: transitive dependency: transitive
description: description:
name: process name: process
url: "https://pub.dartlang.org" sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09"
url: "https://pub.dev"
source: hosted source: hosted
version: "4.2.4" version: "4.2.4"
pub_semver: pub_semver:
dependency: transitive dependency: transitive
description: description:
name: pub_semver name: pub_semver
url: "https://pub.dartlang.org" sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.3" version: "2.1.3"
pubspec_parse: pubspec_parse:
dependency: transitive dependency: transitive
description: description:
name: pubspec_parse name: pubspec_parse
url: "https://pub.dartlang.org" sha256: "75f6614d6dde2dc68948dffbaa4fe5dae32cd700eb9fb763fe11dfb45a3c4d0a"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.2" version: "1.2.1"
shelf: shelf:
dependency: transitive dependency: transitive
description: description:
name: shelf name: shelf
url: "https://pub.dartlang.org" sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c
url: "https://pub.dev"
source: hosted source: hosted
version: "1.4.0" version: "1.4.0"
shelf_web_socket: shelf_web_socket:
dependency: transitive dependency: transitive
description: description:
name: shelf_web_socket name: shelf_web_socket
url: "https://pub.dartlang.org" sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8
url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.3" version: "1.0.3"
sky_engine: sky_engine:
@ -468,121 +532,138 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: source_gen name: source_gen
url: "https://pub.dartlang.org" sha256: "2d79738b6bbf38a43920e2b8d189e9a3ce6cc201f4b8fc76be5e4fe377b1c38d"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.6" version: "1.2.6"
source_helper: source_helper:
dependency: transitive dependency: transitive
description: description:
name: source_helper name: source_helper
url: "https://pub.dartlang.org" sha256: "3b67aade1d52416149c633ba1bb36df44d97c6b51830c2198e934e3fca87ca1f"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.3" version: "1.3.3"
source_span: source_span:
dependency: transitive dependency: transitive
description: description:
name: source_span name: source_span
url: "https://pub.dartlang.org" sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
url: "https://pub.dev"
source: hosted source: hosted
version: "1.9.0" version: "1.9.1"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
name: stack_trace name: stack_trace
url: "https://pub.dartlang.org" sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
url: "https://pub.dev"
source: hosted source: hosted
version: "1.10.0" version: "1.11.0"
stream_channel: stream_channel:
dependency: transitive dependency: transitive
description: description:
name: stream_channel name: stream_channel
url: "https://pub.dartlang.org" sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.0" version: "2.1.1"
stream_transform: stream_transform:
dependency: transitive dependency: transitive
description: description:
name: stream_transform name: stream_transform
url: "https://pub.dartlang.org" sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.0" version: "2.1.0"
string_scanner: string_scanner:
dependency: transitive dependency: transitive
description: description:
name: string_scanner name: string_scanner
url: "https://pub.dartlang.org" sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.1" version: "1.2.0"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:
name: term_glyph name: term_glyph
url: "https://pub.dartlang.org" sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.1" version: "1.2.1"
test_api: test_api:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
url: "https://pub.dartlang.org" sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
url: "https://pub.dev"
source: hosted source: hosted
version: "0.4.12" version: "0.5.1"
timing: timing:
dependency: transitive dependency: transitive
description: description:
name: timing name: timing
url: "https://pub.dartlang.org" sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.1" version: "1.0.1"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
name: typed_data name: typed_data
url: "https://pub.dartlang.org" sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.1" version: "1.3.1"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
name: vector_math name: vector_math
url: "https://pub.dartlang.org" sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.2" version: "2.1.4"
watcher: watcher:
dependency: transitive dependency: transitive
description: description:
name: watcher name: watcher
url: "https://pub.dartlang.org" sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.2" version: "1.0.2"
web_socket_channel: web_socket_channel:
dependency: transitive dependency: transitive
description: description:
name: web_socket_channel name: web_socket_channel
url: "https://pub.dartlang.org" sha256: ca49c0bc209c687b887f30527fb6a9d80040b072cc2990f34b9bec3e7663101b
url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.0" version: "2.3.0"
win32: win32:
dependency: transitive dependency: transitive
description: description:
name: win32 name: win32
url: "https://pub.dartlang.org" sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46
url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.3" version: "3.1.3"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:
name: xdg_directories name: xdg_directories
url: "https://pub.dartlang.org" sha256: bd512f03919aac5f1313eb8249f223bacf4927031bf60b02601f81f687689e86
url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.0" version: "0.2.0+3"
yaml: yaml:
dependency: transitive dependency: transitive
description: description:
name: yaml name: yaml
url: "https://pub.dartlang.org" sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370"
url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.1" version: "3.1.1"
sdks: sdks:
dart: ">=2.19.0 <3.0.0" dart: ">=3.0.0 <4.0.0"
flutter: ">=3.0.0" flutter: ">=3.0.0"

View file

@ -4,6 +4,7 @@ import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/cake_hive.dart';
import 'package:cw_core/node.dart'; import 'package:cw_core/node.dart';
import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/pending_transaction.dart'; import 'package:cw_core/pending_transaction.dart';
@ -61,14 +62,11 @@ abstract class EthereumWalletBase
{CryptoCurrency.eth: initialBalance ?? ERC20Balance(BigInt.zero)}), {CryptoCurrency.eth: initialBalance ?? ERC20Balance(BigInt.zero)}),
super(walletInfo) { super(walletInfo) {
this.walletInfo = walletInfo; this.walletInfo = walletInfo;
transactionHistory = EthereumTransactionHistory( transactionHistory = EthereumTransactionHistory(walletInfo: walletInfo, password: password, encryptionFileUtils: encryptionFileUtils,
walletInfo: walletInfo, );
password: password,
encryptionFileUtils: encryptionFileUtils,
);
if (!Hive.isAdapterRegistered(Erc20Token.typeId)) { if (!CakeHive.isAdapterRegistered(Erc20Token.typeId)) {
Hive.registerAdapter(Erc20TokenAdapter()); CakeHive.registerAdapter(Erc20TokenAdapter());
} }
_sharedPrefs.complete(SharedPreferences.getInstance()); _sharedPrefs.complete(SharedPreferences.getInstance());
@ -107,7 +105,7 @@ abstract class EthereumWalletBase
Completer<SharedPreferences> _sharedPrefs = Completer(); Completer<SharedPreferences> _sharedPrefs = Completer();
Future<void> init() async { Future<void> init() async {
erc20TokensBox = await Hive.openBox<Erc20Token>(Erc20Token.boxName); erc20TokensBox = await CakeHive.openBox<Erc20Token>(Erc20Token.boxName);
await walletAddresses.init(); await walletAddresses.init();
await transactionHistory.init(); await transactionHistory.init();
_ethPrivateKey = await getPrivateKey( _ethPrivateKey = await getPrivateKey(

View file

@ -75,6 +75,7 @@ class EthereumWalletService extends WalletService<EthereumNewWalletCredentials,
password: credentials.password!, password: credentials.password!,
privateKey: credentials.privateKey, privateKey: credentials.privateKey,
walletInfo: credentials.walletInfo!, walletInfo: credentials.walletInfo!,
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
); );
await wallet.init(); await wallet.init();

View file

@ -12,8 +12,7 @@ import 'package:cw_core/monero_wallet_utils.dart';
import 'package:cw_haven/api/structs/pending_transaction.dart'; import 'package:cw_haven/api/structs/pending_transaction.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cw_haven/api/transaction_history.dart' import 'package:cw_haven/api/transaction_history.dart' as haven_transaction_history;
as haven_transaction_history;
//import 'package:cw_haven/wallet.dart'; //import 'package:cw_haven/wallet.dart';
import 'package:cw_haven/api/wallet.dart' as haven_wallet; import 'package:cw_haven/api/wallet.dart' as haven_wallet;
import 'package:cw_haven/api/transaction_history.dart' as transaction_history; import 'package:cw_haven/api/transaction_history.dart' as transaction_history;
@ -37,8 +36,8 @@ const moneroBlockSize = 1000;
class HavenWallet = HavenWalletBase with _$HavenWallet; class HavenWallet = HavenWalletBase with _$HavenWallet;
abstract class HavenWalletBase extends WalletBase<MoneroBalance, abstract class HavenWalletBase
HavenTransactionHistory, HavenTransactionInfo> with Store { extends WalletBase<MoneroBalance, HavenTransactionHistory, HavenTransactionInfo> with Store {
HavenWalletBase({required WalletInfo walletInfo}) HavenWalletBase({required WalletInfo walletInfo})
: balance = ObservableMap.of(getHavenBalance(accountIndex: 0)), : balance = ObservableMap.of(getHavenBalance(accountIndex: 0)),
_isTransactionUpdating = false, _isTransactionUpdating = false,
@ -47,8 +46,7 @@ abstract class HavenWalletBase extends WalletBase<MoneroBalance,
syncStatus = NotConnectedSyncStatus(), syncStatus = NotConnectedSyncStatus(),
super(walletInfo) { super(walletInfo) {
transactionHistory = HavenTransactionHistory(); transactionHistory = HavenTransactionHistory();
_onAccountChangeReaction = reaction((_) => walletAddresses.account, _onAccountChangeReaction = reaction((_) => walletAddresses.account, (Account? account) {
(Account? account) {
if (account == null) { if (account == null) {
return; return;
} }
@ -96,14 +94,12 @@ abstract class HavenWalletBase extends WalletBase<MoneroBalance,
haven_wallet.setRecoveringFromSeed(isRecovery: walletInfo.isRecovery); haven_wallet.setRecoveringFromSeed(isRecovery: walletInfo.isRecovery);
if (haven_wallet.getCurrentHeight() <= 1) { if (haven_wallet.getCurrentHeight() <= 1) {
haven_wallet.setRefreshFromBlockHeight( haven_wallet.setRefreshFromBlockHeight(height: walletInfo.restoreHeight);
height: walletInfo.restoreHeight);
} }
} }
_autoSaveTimer = Timer.periodic( _autoSaveTimer =
Duration(seconds: _autoSaveInterval), Timer.periodic(Duration(seconds: _autoSaveInterval), (_) async => await save());
(_) async => await save());
} }
@override @override
@ -115,7 +111,7 @@ abstract class HavenWalletBase extends WalletBase<MoneroBalance,
_onAccountChangeReaction?.reaction.dispose(); _onAccountChangeReaction?.reaction.dispose();
_autoSaveTimer?.cancel(); _autoSaveTimer?.cancel();
} }
@override @override
Future<void> connectToNode({required Node node}) async { Future<void> connectToNode({required Node node}) async {
try { try {
@ -170,26 +166,25 @@ abstract class HavenWalletBase extends WalletBase<MoneroBalance,
} }
if (hasMultiDestination) { if (hasMultiDestination) {
if (outputs.any((item) => item.sendAll if (outputs.any((item) => item.sendAll || (item.formattedCryptoAmount ?? 0) <= 0)) {
|| (item.formattedCryptoAmount ?? 0) <= 0)) { throw HavenTransactionCreationException(
throw HavenTransactionCreationException('You do not have enough coins to send this amount.'); 'You do not have enough coins to send this amount.');
} }
final int totalAmount = outputs.fold(0, (acc, value) => final int totalAmount =
acc + (value.formattedCryptoAmount ?? 0)); outputs.fold(0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0));
if (unlockedBalance < totalAmount) { if (unlockedBalance < totalAmount) {
throw HavenTransactionCreationException('You do not have enough coins to send this amount.'); throw HavenTransactionCreationException(
'You do not have enough coins to send this amount.');
} }
final moneroOutputs = outputs.map((output) => final moneroOutputs = outputs
MoneroOutput( .map((output) => MoneroOutput(
address: output.address, address: output.address, amount: output.cryptoAmount!.replaceAll(',', '.')))
amount: output.cryptoAmount!.replaceAll(',', '.')))
.toList(); .toList();
pendingTransactionDescription = pendingTransactionDescription = await transaction_history.createTransactionMultDest(
await transaction_history.createTransactionMultDest(
outputs: moneroOutputs, outputs: moneroOutputs,
priorityRaw: _credentials.priority.serialize(), priorityRaw: _credentials.priority.serialize(),
accountIndex: walletAddresses.account!.id); accountIndex: walletAddresses.account!.id);
@ -198,12 +193,8 @@ abstract class HavenWalletBase extends WalletBase<MoneroBalance,
final address = output.isParsedAddress && (output.extractedAddress?.isNotEmpty ?? false) final address = output.isParsedAddress && (output.extractedAddress?.isNotEmpty ?? false)
? output.extractedAddress! ? output.extractedAddress!
: output.address; : output.address;
final amount = output.sendAll final amount = output.sendAll ? null : output.cryptoAmount!.replaceAll(',', '.');
? null final int? formattedAmount = output.sendAll ? null : output.formattedCryptoAmount;
: output.cryptoAmount!.replaceAll(',', '.');
final int? formattedAmount = output.sendAll
? null
: output.formattedCryptoAmount;
if ((formattedAmount != null && unlockedBalance < formattedAmount) || if ((formattedAmount != null && unlockedBalance < formattedAmount) ||
(formattedAmount == null && unlockedBalance <= 0)) { (formattedAmount == null && unlockedBalance <= 0)) {
@ -213,8 +204,7 @@ abstract class HavenWalletBase extends WalletBase<MoneroBalance,
'You do not have enough unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.'); 'You do not have enough unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.');
} }
pendingTransactionDescription = pendingTransactionDescription = await transaction_history.createTransaction(
await transaction_history.createTransaction(
address: address, address: address,
assetType: _credentials.assetType, assetType: _credentials.assetType,
amount: amount, amount: amount,
@ -307,16 +297,14 @@ abstract class HavenWalletBase extends WalletBase<MoneroBalance,
} }
String getTransactionAddress(int accountIndex, int addressIndex) => String getTransactionAddress(int accountIndex, int addressIndex) =>
haven_wallet.getAddress( haven_wallet.getAddress(accountIndex: accountIndex, addressIndex: addressIndex);
accountIndex: accountIndex,
addressIndex: addressIndex);
@override @override
Future<Map<String, HavenTransactionInfo>> fetchTransactions() async { Future<Map<String, HavenTransactionInfo>> fetchTransactions() async {
haven_transaction_history.refreshTransactions(); haven_transaction_history.refreshTransactions();
return _getAllTransactions(null).fold<Map<String, HavenTransactionInfo>>( return _getAllTransactions(null)
<String, HavenTransactionInfo>{}, .fold<Map<String, HavenTransactionInfo>>(<String, HavenTransactionInfo>{},
(Map<String, HavenTransactionInfo> acc, HavenTransactionInfo tx) { (Map<String, HavenTransactionInfo> acc, HavenTransactionInfo tx) {
acc[tx.id] = tx; acc[tx.id] = tx;
return acc; return acc;
}); });
@ -340,9 +328,9 @@ abstract class HavenWalletBase extends WalletBase<MoneroBalance,
} }
List<HavenTransactionInfo> _getAllTransactions(dynamic _) => haven_transaction_history List<HavenTransactionInfo> _getAllTransactions(dynamic _) => haven_transaction_history
.getAllTransations() .getAllTransations()
.map((row) => HavenTransactionInfo.fromRow(row)) .map((row) => HavenTransactionInfo.fromRow(row))
.toList(); .toList();
void _setListeners() { void _setListeners() {
_listener?.stop(); _listener?.stop();
@ -364,8 +352,7 @@ abstract class HavenWalletBase extends WalletBase<MoneroBalance,
} }
int _getHeightDistance(DateTime date) { int _getHeightDistance(DateTime date) {
final distance = final distance = DateTime.now().millisecondsSinceEpoch - date.millisecondsSinceEpoch;
DateTime.now().millisecondsSinceEpoch - date.millisecondsSinceEpoch;
final daysTmp = (distance / 86400).round(); final daysTmp = (distance / 86400).round();
final days = daysTmp < 1 ? 1 : daysTmp; final days = daysTmp < 1 ? 1 : daysTmp;
@ -386,8 +373,7 @@ abstract class HavenWalletBase extends WalletBase<MoneroBalance,
void _askForUpdateBalance() => void _askForUpdateBalance() =>
balance.addAll(getHavenBalance(accountIndex: walletAddresses.account!.id)); balance.addAll(getHavenBalance(accountIndex: walletAddresses.account!.id));
Future<void> _askForUpdateTransactionHistory() async => Future<void> _askForUpdateTransactionHistory() async => await updateTransactions();
await updateTransactions();
void _onNewBlock(int height, int blocksLeft, double ptc) async { void _onNewBlock(int height, int blocksLeft, double ptc) async {
try { try {
@ -404,9 +390,9 @@ abstract class HavenWalletBase extends WalletBase<MoneroBalance,
syncStatus = SyncedSyncStatus(); syncStatus = SyncedSyncStatus();
if (!_hasSyncAfterStartup) { if (!_hasSyncAfterStartup) {
_hasSyncAfterStartup = true; _hasSyncAfterStartup = true;
await save(); await save();
} }
if (walletInfo.isRecovery) { if (walletInfo.isRecovery) {
await setAsRecovered(); await setAsRecovered();

View file

@ -37,10 +37,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: async name: async
sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.10.0" version: "2.11.0"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -117,10 +117,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: characters name: characters
sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.1" version: "1.3.0"
checked_yaml: checked_yaml:
dependency: transitive dependency: transitive
description: description:
@ -149,10 +149,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: collection name: collection
sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.17.0" version: "1.17.1"
convert: convert:
dependency: transitive dependency: transitive
description: description:
@ -286,10 +286,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: http name: http
sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.13.5" version: "1.1.0"
http_multi_server: http_multi_server:
dependency: transitive dependency: transitive
description: description:
@ -310,10 +310,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: intl name: intl
sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.17.0" version: "0.18.1"
io: io:
dependency: transitive dependency: transitive
description: description:
@ -326,10 +326,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: js name: js
sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.6.5" version: "0.6.7"
json_annotation: json_annotation:
dependency: transitive dependency: transitive
description: description:
@ -350,10 +350,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.12.13" version: "0.12.15"
material_color_utilities: material_color_utilities:
dependency: transitive dependency: transitive
description: description:
@ -366,10 +366,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.8.0" version: "1.9.1"
mime: mime:
dependency: transitive dependency: transitive
description: description:
@ -406,10 +406,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: path name: path
sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.8.2" version: "1.8.3"
path_provider: path_provider:
dependency: "direct main" dependency: "direct main"
description: description:
@ -603,10 +603,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.4.16" version: "0.5.1"
timing: timing:
dependency: transitive dependency: transitive
description: description:
@ -672,5 +672,5 @@ packages:
source: hosted source: hosted
version: "3.1.1" version: "3.1.1"
sdks: sdks:
dart: ">=2.19.0 <3.0.0" dart: ">=3.0.0 <4.0.0"
flutter: ">=3.0.0" flutter: ">=3.0.0"

View file

@ -21,10 +21,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: async name: async
sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.10.0" version: "2.11.0"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -37,10 +37,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: characters name: characters
sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.1" version: "1.3.0"
clock: clock:
dependency: transitive dependency: transitive
description: description:
@ -53,10 +53,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: collection name: collection
sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.17.0" version: "1.17.1"
convert: convert:
dependency: transitive dependency: transitive
description: description:
@ -157,10 +157,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: http name: http
sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.13.5" version: "1.1.0"
http_parser: http_parser:
dependency: transitive dependency: transitive
description: description:
@ -173,18 +173,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: intl name: intl
sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.17.0" version: "0.18.1"
js: js:
dependency: transitive dependency: transitive
description: description:
name: js name: js
sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.6.5" version: "0.6.7"
lints: lints:
dependency: transitive dependency: transitive
description: description:
@ -197,10 +197,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.12.13" version: "0.12.15"
material_color_utilities: material_color_utilities:
dependency: transitive dependency: transitive
description: description:
@ -213,10 +213,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.8.0" version: "1.9.1"
mobx: mobx:
dependency: transitive dependency: transitive
description: description:
@ -229,10 +229,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: path name: path
sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.8.2" version: "1.8.3"
path_provider: path_provider:
dependency: transitive dependency: transitive
description: description:
@ -362,10 +362,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.4.16" version: "0.5.1"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
@ -399,5 +399,5 @@ packages:
source: hosted source: hosted
version: "0.2.0+3" version: "0.2.0+3"
sdks: sdks:
dart: ">=2.18.1 <3.0.0" dart: ">=3.0.0 <4.0.0"
flutter: ">=3.0.0" flutter: ">=3.0.0"

View file

@ -145,7 +145,7 @@ extern "C"
int8_t direction; int8_t direction;
int8_t isPending; int8_t isPending;
uint32_t subaddrIndex; uint32_t subaddrIndex;
char *hash; char *hash;
char *paymentId; char *paymentId;
@ -161,7 +161,7 @@ extern "C"
std::set<uint32_t>::iterator it = subIndex.begin(); std::set<uint32_t>::iterator it = subIndex.begin();
subaddrIndex = *it; subaddrIndex = *it;
confirmations = transaction->confirmations(); confirmations = transaction->confirmations();
datetime = static_cast<int64_t>(transaction->timestamp()); datetime = static_cast<int64_t>(transaction->timestamp());
direction = transaction->direction(); direction = transaction->direction();
isPending = static_cast<int8_t>(transaction->isPending()); isPending = static_cast<int8_t>(transaction->isPending());
std::string *hash_str = new std::string(transaction->hash()); std::string *hash_str = new std::string(transaction->hash());
@ -241,7 +241,7 @@ extern "C"
} }
void setUnlocked(bool unlocked); void setUnlocked(bool unlocked);
}; };
Monero::Coins *m_coins; Monero::Coins *m_coins;
@ -262,7 +262,7 @@ extern "C"
{ {
m_wallet = wallet; m_wallet = wallet;
m_listener = nullptr; m_listener = nullptr;
if (wallet != nullptr) if (wallet != nullptr)
{ {
@ -505,7 +505,7 @@ extern "C"
{ {
nice(19); nice(19);
Monero::Wallet *wallet = get_current_wallet(); Monero::Wallet *wallet = get_current_wallet();
std::string _login = ""; std::string _login = "";
std::string _password = ""; std::string _password = "";
std::string _socksProxyAddress = ""; std::string _socksProxyAddress = "";
@ -601,7 +601,7 @@ extern "C"
_preferred_inputs.insert(std::string(*preferred_inputs)); _preferred_inputs.insert(std::string(*preferred_inputs));
preferred_inputs++; preferred_inputs++;
} }
auto priority = static_cast<Monero::PendingTransaction::Priority>(priority_raw); auto priority = static_cast<Monero::PendingTransaction::Priority>(priority_raw);
std::string _payment_id; std::string _payment_id;
Monero::PendingTransaction *transaction; Monero::PendingTransaction *transaction;
@ -620,7 +620,7 @@ extern "C"
{ {
transaction = m_wallet->createTransaction(std::string(address), _payment_id, Monero::optional<uint64_t>(), m_wallet->defaultMixin(), priority, subaddr_account, {}, _preferred_inputs); transaction = m_wallet->createTransaction(std::string(address), _payment_id, Monero::optional<uint64_t>(), m_wallet->defaultMixin(), priority, subaddr_account, {}, _preferred_inputs);
} }
int status = transaction->status(); int status = transaction->status();
if (status == Monero::PendingTransaction::Status::Status_Error || status == Monero::PendingTransaction::Status::Status_Critical) if (status == Monero::PendingTransaction::Status::Status_Error || status == Monero::PendingTransaction::Status::Status_Critical)

View file

@ -6,14 +6,15 @@ import 'package:cw_core/subaddress.dart';
part 'monero_subaddress_list.g.dart'; part 'monero_subaddress_list.g.dart';
class MoneroSubaddressList = MoneroSubaddressListBase class MoneroSubaddressList = MoneroSubaddressListBase with _$MoneroSubaddressList;
with _$MoneroSubaddressList;
abstract class MoneroSubaddressListBase with Store { abstract class MoneroSubaddressListBase with Store {
MoneroSubaddressListBase() MoneroSubaddressListBase()
: _isRefreshing = false, : _isRefreshing = false,
_isUpdating = false, _isUpdating = false,
subaddresses = ObservableList<Subaddress>(); subaddresses = ObservableList<Subaddress>();
final List<String> _usedAddresses = [];
@observable @observable
ObservableList<Subaddress> subaddresses; ObservableList<Subaddress> subaddresses;
@ -49,20 +50,24 @@ abstract class MoneroSubaddressListBase with Store {
subaddresses = [primary] + rest.toList(); subaddresses = [primary] + rest.toList();
} }
return subaddresses return subaddresses.map((subaddressRow) {
.map((subaddressRow) => Subaddress( final hasDefaultAddressName =
subaddressRow.getLabel().toLowerCase() == 'Primary account'.toLowerCase() ||
subaddressRow.getLabel().toLowerCase() == 'Untitled account'.toLowerCase();
final isPrimaryAddress = subaddressRow.getId() == 0 && hasDefaultAddressName;
return Subaddress(
id: subaddressRow.getId(), id: subaddressRow.getId(),
address: subaddressRow.getAddress(), address: subaddressRow.getAddress(),
label: subaddressRow.getId() == 0 && label: isPrimaryAddress
subaddressRow.getLabel().toLowerCase() == 'Primary account'.toLowerCase() ? 'Primary address'
? 'Primary address' : hasDefaultAddressName
: subaddressRow.getLabel())) ? ''
.toList(); : subaddressRow.getLabel());
}).toList();
} }
Future<void> addSubaddress({required int accountIndex, required String label}) async { Future<void> addSubaddress({required int accountIndex, required String label}) async {
await subaddress_list.addSubaddress( await subaddress_list.addSubaddress(accountIndex: accountIndex, label: label);
accountIndex: accountIndex, label: label);
update(accountIndex: accountIndex); update(accountIndex: accountIndex);
} }
@ -88,4 +93,59 @@ abstract class MoneroSubaddressListBase with Store {
rethrow; rethrow;
} }
} }
Future<void> updateWithAutoGenerate({
required int accountIndex,
required String defaultLabel,
required List<String> usedAddresses,
}) async {
_usedAddresses.addAll(usedAddresses);
if (_isUpdating) {
return;
}
try {
_isUpdating = true;
refresh(accountIndex: accountIndex);
subaddresses.clear();
final newSubAddresses =
await _getAllUnusedAddresses(accountIndex: accountIndex, label: defaultLabel);
subaddresses.addAll(newSubAddresses);
} catch (e) {
rethrow;
} finally {
_isUpdating = false;
}
}
Future<List<Subaddress>> _getAllUnusedAddresses(
{required int accountIndex, required String label}) async {
final allAddresses = subaddress_list.getAllSubaddresses();
if (allAddresses.isEmpty || _usedAddresses.contains(allAddresses.last.getAddress())) {
final isAddressUnused = await _newSubaddress(accountIndex: accountIndex, label: label);
if (!isAddressUnused) {
return await _getAllUnusedAddresses(accountIndex: accountIndex, label: label);
}
}
return allAddresses
.map((subaddressRow) => Subaddress(
id: subaddressRow.getId(),
address: subaddressRow.getAddress(),
label: subaddressRow.getId() == 0 &&
subaddressRow.getLabel().toLowerCase() == 'Primary account'.toLowerCase()
? 'Primary address'
: subaddressRow.getLabel()))
.toList();
}
Future<bool> _newSubaddress({required int accountIndex, required String label}) async {
await subaddress_list.addSubaddress(accountIndex: accountIndex, label: label);
return subaddress_list
.getAllSubaddresses()
.where((subaddressRow) => !_usedAddresses.contains(subaddressRow.getAddress()))
.isNotEmpty;
}
} }

View file

@ -51,12 +51,14 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
_isTransactionUpdating = false, _isTransactionUpdating = false,
_hasSyncAfterStartup = false, _hasSyncAfterStartup = false,
_password = password, _password = password,
walletAddresses = MoneroWalletAddresses(walletInfo), isEnabledAutoGenerateSubaddress = false,
syncStatus = NotConnectedSyncStatus(), syncStatus = NotConnectedSyncStatus(),
unspentCoins = [], unspentCoins = [],
this.unspentCoinsInfo = unspentCoinsInfo, this.unspentCoinsInfo = unspentCoinsInfo,
super(walletInfo) { super(walletInfo) {
transactionHistory = MoneroTransactionHistory(); transactionHistory = MoneroTransactionHistory();
walletAddresses = MoneroWalletAddresses(walletInfo, transactionHistory);
_onAccountChangeReaction = reaction((_) => walletAddresses.account, (Account? account) { _onAccountChangeReaction = reaction((_) => walletAddresses.account, (Account? account) {
if (account == null) { if (account == null) {
return; return;
@ -67,7 +69,11 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
fullBalance: monero_wallet.getFullBalance(accountIndex: account.id), fullBalance: monero_wallet.getFullBalance(accountIndex: account.id),
unlockedBalance: monero_wallet.getUnlockedBalance(accountIndex: account.id)) unlockedBalance: monero_wallet.getUnlockedBalance(accountIndex: account.id))
}); });
walletAddresses.updateSubaddressList(accountIndex: account.id); _updateSubAddress(isEnabledAutoGenerateSubaddress, account: account);
});
reaction((_) => isEnabledAutoGenerateSubaddress, (bool enabled) {
_updateSubAddress(enabled, account: walletAddresses.account);
}); });
} }
@ -76,7 +82,11 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
Box<UnspentCoinsInfo> unspentCoinsInfo; Box<UnspentCoinsInfo> unspentCoinsInfo;
@override @override
MoneroWalletAddresses walletAddresses; late MoneroWalletAddresses walletAddresses;
@override
@observable
bool isEnabledAutoGenerateSubaddress;
@override @override
@observable @observable
@ -294,6 +304,14 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
@override @override
Future<void> save() async { Future<void> save() async {
await walletAddresses.updateUsedSubaddress();
if (isEnabledAutoGenerateSubaddress) {
walletAddresses.updateUnusedSubaddress(
accountIndex: walletAddresses.account?.id ?? 0,
defaultLabel: walletAddresses.account?.label ?? '');
}
await walletAddresses.updateAddressesInBox(); await walletAddresses.updateAddressesInBox();
await backupWalletFiles(name); await backupWalletFiles(name);
await monero_wallet.store(); await monero_wallet.store();
@ -386,7 +404,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
} }
Future<void> updateUnspent() async { Future<void> updateUnspent() async {
// refreshCoins(walletAddresses.account!.id); refreshCoins(walletAddresses.account!.id);
unspentCoins.clear(); unspentCoins.clear();
@ -618,4 +636,15 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
print(e.toString()); print(e.toString());
} }
} }
void _updateSubAddress(bool enableAutoGenerate, {Account? account}) {
if (enableAutoGenerate) {
walletAddresses.updateUnusedSubaddress(
accountIndex: account?.id ?? 0,
defaultLabel: account?.label ?? '',
);
} else {
walletAddresses.updateSubaddressList(accountIndex: account?.id ?? 0);
}
}
} }

View file

@ -1,27 +1,32 @@
import 'package:cw_core/address_info.dart';
import 'package:cw_core/wallet_addresses.dart'; import 'package:cw_core/wallet_addresses.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/account.dart'; import 'package:cw_core/account.dart';
import 'package:cw_monero/api/wallet.dart';
import 'package:cw_monero/monero_account_list.dart'; import 'package:cw_monero/monero_account_list.dart';
import 'package:cw_monero/monero_subaddress_list.dart'; import 'package:cw_monero/monero_subaddress_list.dart';
import 'package:cw_core/subaddress.dart'; import 'package:cw_core/subaddress.dart';
import 'package:cw_monero/monero_transaction_history.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
part 'monero_wallet_addresses.g.dart'; part 'monero_wallet_addresses.g.dart';
class MoneroWalletAddresses = MoneroWalletAddressesBase class MoneroWalletAddresses = MoneroWalletAddressesBase with _$MoneroWalletAddresses;
with _$MoneroWalletAddresses;
abstract class MoneroWalletAddressesBase extends WalletAddresses with Store { abstract class MoneroWalletAddressesBase extends WalletAddresses with Store {
MoneroWalletAddressesBase(WalletInfo walletInfo) MoneroWalletAddressesBase(
: accountList = MoneroAccountList(), WalletInfo walletInfo, MoneroTransactionHistory moneroTransactionHistory)
subaddressList = MoneroSubaddressList(), : accountList = MoneroAccountList(),
address = '', _moneroTransactionHistory = moneroTransactionHistory,
super(walletInfo); subaddressList = MoneroSubaddressList(),
address = '',
super(walletInfo);
final MoneroTransactionHistory _moneroTransactionHistory;
@override @override
@observable @observable
String address; String address;
@observable @observable
Account? account; Account? account;
@ -46,11 +51,15 @@ abstract class MoneroWalletAddressesBase extends WalletAddresses with Store {
final _subaddressList = MoneroSubaddressList(); final _subaddressList = MoneroSubaddressList();
addressesMap.clear(); addressesMap.clear();
addressInfos.clear();
accountList.accounts.forEach((account) { accountList.accounts.forEach((account) {
_subaddressList.update(accountIndex: account.id); _subaddressList.update(accountIndex: account.id);
_subaddressList.subaddresses.forEach((subaddress) { _subaddressList.subaddresses.forEach((subaddress) {
addressesMap[subaddress.address] = subaddress.label; addressesMap[subaddress.address] = subaddress.label;
addressInfos[account.id] ??= [];
addressInfos[account.id]?.add(AddressInfo(
address: subaddress.address, label: subaddress.label, accountIndex: account.id));
}); });
}); });
@ -62,14 +71,14 @@ abstract class MoneroWalletAddressesBase extends WalletAddresses with Store {
bool validate() { bool validate() {
accountList.update(); accountList.update();
final accountListLength = accountList.accounts.length ?? 0; final accountListLength = accountList.accounts.length;
if (accountListLength <= 0) { if (accountListLength <= 0) {
return false; return false;
} }
subaddressList.update(accountIndex: accountList.accounts.first.id); subaddressList.update(accountIndex: accountList.accounts.first.id);
final subaddressListLength = subaddressList.subaddresses.length ?? 0; final subaddressListLength = subaddressList.subaddresses.length;
if (subaddressListLength <= 0) { if (subaddressListLength <= 0) {
return false; return false;
@ -83,4 +92,24 @@ abstract class MoneroWalletAddressesBase extends WalletAddresses with Store {
subaddress = subaddressList.subaddresses.first; subaddress = subaddressList.subaddresses.first;
address = subaddress!.address; address = subaddress!.address;
} }
}
Future<void> updateUsedSubaddress() async {
final transactions = _moneroTransactionHistory.transactions.values.toList();
transactions.forEach((element) {
final accountIndex = element.accountIndex;
final addressIndex = element.addressIndex;
usedAddresses.add(getAddress(accountIndex: accountIndex, addressIndex: addressIndex));
});
}
Future<void> updateUnusedSubaddress(
{required int accountIndex, required String defaultLabel}) async {
await subaddressList.updateWithAutoGenerate(
accountIndex: accountIndex,
defaultLabel: defaultLabel,
usedAddresses: usedAddresses.toList());
subaddress = subaddressList.subaddresses.last;
address = subaddress!.address;
}
}

View file

@ -57,7 +57,7 @@ class MoneroWalletService extends WalletService<
final Box<WalletInfo> walletInfoSource; final Box<WalletInfo> walletInfoSource;
final Box<UnspentCoinsInfo> unspentCoinsInfoSource; final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
static bool walletFilesExist(String path) => static bool walletFilesExist(String path) =>
!File(path).existsSync() && !File('$path.keys').existsSync(); !File(path).existsSync() && !File('$path.keys').existsSync();
@ -128,13 +128,20 @@ class MoneroWalletService extends WalletService<
} catch (e) { } catch (e) {
// TODO: Implement Exception for wallet list service. // TODO: Implement Exception for wallet list service.
if ((e.toString().contains('bad_alloc') || final bool isBadAlloc = e.toString().contains('bad_alloc') ||
(e is WalletOpeningException && (e is WalletOpeningException &&
(e.message == 'std::bad_alloc' || (e.message == 'std::bad_alloc' || e.message.contains('bad_alloc')));
e.message.contains('bad_alloc')))) ||
(e.toString().contains('does not correspond') || final bool doesNotCorrespond = e.toString().contains('does not correspond') ||
(e is WalletOpeningException && (e is WalletOpeningException && e.message.contains('does not correspond'));
e.message.contains('does not correspond')))) {
final bool isMissingCacheFilesIOS = e.toString().contains('basic_string') ||
(e is WalletOpeningException && e.message.contains('basic_string'));
final bool isMissingCacheFilesAndroid = e.toString().contains('input_stream') ||
(e is WalletOpeningException && e.message.contains('input_stream'));
if (isBadAlloc || doesNotCorrespond || isMissingCacheFilesIOS || isMissingCacheFilesAndroid) {
await restoreOrResetWalletFiles(name); await restoreOrResetWalletFiles(name);
return openWallet(name, password); return openWallet(name, password);
} }

View file

@ -3,8 +3,10 @@
#include <chrono> #include <chrono>
#include <functional> #include <functional>
#include <iostream> #include <iostream>
#include <fstream>
#include <unistd.h> #include <unistd.h>
#include <mutex> #include <mutex>
#include <list>
#include "thread" #include "thread"
#include "CwWalletListener.h" #include "CwWalletListener.h"
#if __APPLE__ #if __APPLE__
@ -135,7 +137,7 @@ extern "C"
int8_t direction; int8_t direction;
int8_t isPending; int8_t isPending;
uint32_t subaddrIndex; uint32_t subaddrIndex;
char *hash; char *hash;
char *paymentId; char *paymentId;
@ -151,7 +153,7 @@ extern "C"
std::set<uint32_t>::iterator it = subIndex.begin(); std::set<uint32_t>::iterator it = subIndex.begin();
subaddrIndex = *it; subaddrIndex = *it;
confirmations = transaction->confirmations(); confirmations = transaction->confirmations();
datetime = static_cast<int64_t>(transaction->timestamp()); datetime = static_cast<int64_t>(transaction->timestamp());
direction = transaction->direction(); direction = transaction->direction();
isPending = static_cast<int8_t>(transaction->isPending()); isPending = static_cast<int8_t>(transaction->isPending());
std::string *hash_str = new std::string(transaction->hash()); std::string *hash_str = new std::string(transaction->hash());
@ -180,6 +182,62 @@ extern "C"
} }
}; };
struct CoinsInfoRow
{
uint64_t blockHeight;
char *hash;
uint64_t internalOutputIndex;
uint64_t globalOutputIndex;
bool spent;
bool frozen;
uint64_t spentHeight;
uint64_t amount;
bool rct;
bool keyImageKnown;
uint64_t pkIndex;
uint32_t subaddrIndex;
uint32_t subaddrAccount;
char *address;
char *addressLabel;
char *keyImage;
uint64_t unlockTime;
bool unlocked;
char *pubKey;
bool coinbase;
char *description;
CoinsInfoRow(Monero::CoinsInfo *coinsInfo)
{
blockHeight = coinsInfo->blockHeight();
std::string *hash_str = new std::string(coinsInfo->hash());
hash = strdup(hash_str->c_str());
internalOutputIndex = coinsInfo->internalOutputIndex();
globalOutputIndex = coinsInfo->globalOutputIndex();
spent = coinsInfo->spent();
frozen = coinsInfo->frozen();
spentHeight = coinsInfo->spentHeight();
amount = coinsInfo->amount();
rct = coinsInfo->rct();
keyImageKnown = coinsInfo->keyImageKnown();
pkIndex = coinsInfo->pkIndex();
subaddrIndex = coinsInfo->subaddrIndex();
subaddrAccount = coinsInfo->subaddrAccount();
address = strdup(coinsInfo->address().c_str()) ;
addressLabel = strdup(coinsInfo->addressLabel().c_str());
keyImage = strdup(coinsInfo->keyImage().c_str());
unlockTime = coinsInfo->unlockTime();
unlocked = coinsInfo->unlocked();
pubKey = strdup(coinsInfo->pubKey().c_str());
coinbase = coinsInfo->coinbase();
description = strdup(coinsInfo->description().c_str());
}
void setUnlocked(bool unlocked);
};
Monero::Coins *m_coins;
Monero::Wallet *m_wallet; Monero::Wallet *m_wallet;
Monero::TransactionHistory *m_transaction_history; Monero::TransactionHistory *m_transaction_history;
MoneroWalletListener *m_listener; MoneroWalletListener *m_listener;
@ -187,6 +245,7 @@ extern "C"
Monero::SubaddressAccount *m_account; Monero::SubaddressAccount *m_account;
uint64_t m_last_known_wallet_height; uint64_t m_last_known_wallet_height;
uint64_t m_cached_syncing_blockchain_height = 0; uint64_t m_cached_syncing_blockchain_height = 0;
std::list<Monero::CoinsInfo*> m_coins_info;
std::mutex store_lock; std::mutex store_lock;
bool is_storing = false; bool is_storing = false;
@ -194,7 +253,7 @@ extern "C"
{ {
m_wallet = wallet; m_wallet = wallet;
m_listener = nullptr; m_listener = nullptr;
if (wallet != nullptr) if (wallet != nullptr)
{ {
@ -222,6 +281,17 @@ extern "C"
{ {
m_subaddress = nullptr; m_subaddress = nullptr;
} }
m_coins_info = std::list<Monero::CoinsInfo*>();
if (wallet != nullptr)
{
m_coins = wallet->coins();
}
else
{
m_coins = nullptr;
}
} }
Monero::Wallet *get_current_wallet() Monero::Wallet *get_current_wallet()
@ -404,13 +474,14 @@ extern "C"
return is_connected; return is_connected;
} }
bool setup_node(char *address, char *login, char *password, bool use_ssl, bool is_light_wallet, char *error) bool setup_node(char *address, char *login, char *password, bool use_ssl, bool is_light_wallet, char *socksProxyAddress, char *error)
{ {
nice(19); nice(19);
Monero::Wallet *wallet = get_current_wallet(); Monero::Wallet *wallet = get_current_wallet();
std::string _login = ""; std::string _login = "";
std::string _password = ""; std::string _password = "";
std::string _socksProxyAddress = "";
if (login != nullptr) if (login != nullptr)
{ {
@ -422,7 +493,12 @@ extern "C"
_password = std::string(password); _password = std::string(password);
} }
bool inited = wallet->init(std::string(address), 0, _login, _password, use_ssl, is_light_wallet); if (socksProxyAddress != nullptr)
{
_socksProxyAddress = std::string(socksProxyAddress);
}
bool inited = wallet->init(std::string(address), 0, _login, _password, use_ssl, is_light_wallet, _socksProxyAddress);
if (!inited) if (!inited)
{ {
@ -479,10 +555,19 @@ extern "C"
} }
bool transaction_create(char *address, char *payment_id, char *amount, bool transaction_create(char *address, char *payment_id, char *amount,
uint8_t priority_raw, uint32_t subaddr_account, Utf8Box &error, PendingTransactionRaw &pendingTransaction) uint8_t priority_raw, uint32_t subaddr_account,
char **preferred_inputs, uint32_t preferred_inputs_size,
Utf8Box &error, PendingTransactionRaw &pendingTransaction)
{ {
nice(19); nice(19);
std::set<std::string> _preferred_inputs;
for (int i = 0; i < preferred_inputs_size; i++) {
_preferred_inputs.insert(std::string(*preferred_inputs));
preferred_inputs++;
}
auto priority = static_cast<Monero::PendingTransaction::Priority>(priority_raw); auto priority = static_cast<Monero::PendingTransaction::Priority>(priority_raw);
std::string _payment_id; std::string _payment_id;
Monero::PendingTransaction *transaction; Monero::PendingTransaction *transaction;
@ -495,13 +580,13 @@ extern "C"
if (amount != nullptr) if (amount != nullptr)
{ {
uint64_t _amount = Monero::Wallet::amountFromString(std::string(amount)); uint64_t _amount = Monero::Wallet::amountFromString(std::string(amount));
transaction = m_wallet->createTransaction(std::string(address), _payment_id, _amount, m_wallet->defaultMixin(), priority, subaddr_account); transaction = m_wallet->createTransaction(std::string(address), _payment_id, _amount, m_wallet->defaultMixin(), priority, subaddr_account, {}, _preferred_inputs);
} }
else else
{ {
transaction = m_wallet->createTransaction(std::string(address), _payment_id, Monero::optional<uint64_t>(), m_wallet->defaultMixin(), priority, subaddr_account); transaction = m_wallet->createTransaction(std::string(address), _payment_id, Monero::optional<uint64_t>(), m_wallet->defaultMixin(), priority, subaddr_account, {}, _preferred_inputs);
} }
int status = transaction->status(); int status = transaction->status();
if (status == Monero::PendingTransaction::Status::Status_Error || status == Monero::PendingTransaction::Status::Status_Critical) if (status == Monero::PendingTransaction::Status::Status_Error || status == Monero::PendingTransaction::Status::Status_Critical)
@ -519,7 +604,9 @@ extern "C"
} }
bool transaction_create_mult_dest(char **addresses, char *payment_id, char **amounts, uint32_t size, bool transaction_create_mult_dest(char **addresses, char *payment_id, char **amounts, uint32_t size,
uint8_t priority_raw, uint32_t subaddr_account, Utf8Box &error, PendingTransactionRaw &pendingTransaction) uint8_t priority_raw, uint32_t subaddr_account,
char **preferred_inputs, uint32_t preferred_inputs_size,
Utf8Box &error, PendingTransactionRaw &pendingTransaction)
{ {
nice(19); nice(19);
@ -533,6 +620,13 @@ extern "C"
amounts++; amounts++;
} }
std::set<std::string> _preferred_inputs;
for (int i = 0; i < preferred_inputs_size; i++) {
_preferred_inputs.insert(std::string(*preferred_inputs));
preferred_inputs++;
}
auto priority = static_cast<Monero::PendingTransaction::Priority>(priority_raw); auto priority = static_cast<Monero::PendingTransaction::Priority>(priority_raw);
std::string _payment_id; std::string _payment_id;
Monero::PendingTransaction *transaction; Monero::PendingTransaction *transaction;
@ -792,6 +886,91 @@ extern "C"
return m_wallet->trustedDaemon(); return m_wallet->trustedDaemon();
} }
CoinsInfoRow* coin(int index)
{
if (index >= 0 && index < m_coins_info.size()) {
std::list<Monero::CoinsInfo*>::iterator it = m_coins_info.begin();
std::advance(it, index);
Monero::CoinsInfo* element = *it;
std::cout << "Element at index " << index << ": " << element << std::endl;
return new CoinsInfoRow(element);
} else {
std::cout << "Invalid index." << std::endl;
return nullptr; // Return a default value (nullptr) for invalid index
}
}
void refresh_coins(uint32_t accountIndex)
{
m_coins_info.clear();
m_coins->refresh();
for (const auto i : m_coins->getAll()) {
if (i->subaddrAccount() == accountIndex && !(i->spent())) {
m_coins_info.push_back(i);
}
}
}
uint64_t coins_count()
{
return m_coins_info.size();
}
CoinsInfoRow** coins_from_account(uint32_t accountIndex)
{
std::vector<CoinsInfoRow*> matchingCoins;
for (int i = 0; i < coins_count(); i++) {
CoinsInfoRow* coinInfo = coin(i);
if (coinInfo->subaddrAccount == accountIndex) {
matchingCoins.push_back(coinInfo);
}
}
CoinsInfoRow** result = new CoinsInfoRow*[matchingCoins.size()];
std::copy(matchingCoins.begin(), matchingCoins.end(), result);
return result;
}
CoinsInfoRow** coins_from_txid(const char* txid, size_t* count)
{
std::vector<CoinsInfoRow*> matchingCoins;
for (int i = 0; i < coins_count(); i++) {
CoinsInfoRow* coinInfo = coin(i);
if (std::string(coinInfo->hash) == txid) {
matchingCoins.push_back(coinInfo);
}
}
*count = matchingCoins.size();
CoinsInfoRow** result = new CoinsInfoRow*[*count];
std::copy(matchingCoins.begin(), matchingCoins.end(), result);
return result;
}
CoinsInfoRow** coins_from_key_image(const char** keyimages, size_t keyimageCount, size_t* count)
{
std::vector<CoinsInfoRow*> matchingCoins;
for (int i = 0; i < coins_count(); i++) {
CoinsInfoRow* coinsInfoRow = coin(i);
for (size_t j = 0; j < keyimageCount; j++) {
if (coinsInfoRow->keyImageKnown && std::string(coinsInfoRow->keyImage) == keyimages[j]) {
matchingCoins.push_back(coinsInfoRow);
break;
}
}
}
*count = matchingCoins.size();
CoinsInfoRow** result = new CoinsInfoRow*[*count];
std::copy(matchingCoins.begin(), matchingCoins.end(), result);
return result;
}
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -37,10 +37,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: async name: async
sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.10.0" version: "2.11.0"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -117,10 +117,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: characters name: characters
sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.1" version: "1.3.0"
checked_yaml: checked_yaml:
dependency: transitive dependency: transitive
description: description:
@ -149,10 +149,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: collection name: collection
sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.17.0" version: "1.17.1"
convert: convert:
dependency: transitive dependency: transitive
description: description:
@ -286,10 +286,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: http name: http
sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.13.5" version: "1.1.0"
http_multi_server: http_multi_server:
dependency: transitive dependency: transitive
description: description:
@ -310,10 +310,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: intl name: intl
sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.17.0" version: "0.18.1"
io: io:
dependency: transitive dependency: transitive
description: description:
@ -326,10 +326,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: js name: js
sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.6.5" version: "0.6.7"
json_annotation: json_annotation:
dependency: transitive dependency: transitive
description: description:
@ -350,10 +350,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.12.13" version: "0.12.15"
material_color_utilities: material_color_utilities:
dependency: transitive dependency: transitive
description: description:
@ -366,10 +366,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.8.0" version: "1.9.1"
mime: mime:
dependency: transitive dependency: transitive
description: description:
@ -406,10 +406,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: path name: path
sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.8.2" version: "1.8.3"
path_provider: path_provider:
dependency: "direct main" dependency: "direct main"
description: description:
@ -603,10 +603,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.4.16" version: "0.5.1"
timing: timing:
dependency: transitive dependency: transitive
description: description:
@ -672,5 +672,5 @@ packages:
source: hosted source: hosted
version: "3.1.1" version: "3.1.1"
sdks: sdks:
dart: ">=2.19.0 <3.0.0" dart: ">=3.0.0 <4.0.0"
flutter: ">=3.0.0" flutter: ">=3.0.0"

View file

@ -8,25 +8,6 @@ PODS:
- Flutter - Flutter
- ReachabilitySwift - ReachabilitySwift
- CryptoSwift (1.7.1) - CryptoSwift (1.7.1)
- cw_haven (0.0.1):
- cw_haven/Boost (= 0.0.1)
- cw_haven/Haven (= 0.0.1)
- cw_haven/OpenSSL (= 0.0.1)
- cw_haven/Sodium (= 0.0.1)
- cw_shared_external
- Flutter
- cw_haven/Boost (0.0.1):
- cw_shared_external
- Flutter
- cw_haven/Haven (0.0.1):
- cw_shared_external
- Flutter
- cw_haven/OpenSSL (0.0.1):
- cw_shared_external
- Flutter
- cw_haven/Sodium (0.0.1):
- cw_shared_external
- Flutter
- cw_monero (0.0.2): - cw_monero (0.0.2):
- cw_monero/Boost (= 0.0.2) - cw_monero/Boost (= 0.0.2)
- cw_monero/Monero (= 0.0.2) - cw_monero/Monero (= 0.0.2)
@ -159,7 +140,6 @@ DEPENDENCIES:
- barcode_scan2 (from `.symlinks/plugins/barcode_scan2/ios`) - barcode_scan2 (from `.symlinks/plugins/barcode_scan2/ios`)
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
- CryptoSwift - CryptoSwift
- cw_haven (from `.symlinks/plugins/cw_haven/ios`)
- cw_monero (from `.symlinks/plugins/cw_monero/ios`) - cw_monero (from `.symlinks/plugins/cw_monero/ios`)
- cw_shared_external (from `.symlinks/plugins/cw_shared_external/ios`) - cw_shared_external (from `.symlinks/plugins/cw_shared_external/ios`)
- device_display_brightness (from `.symlinks/plugins/device_display_brightness/ios`) - device_display_brightness (from `.symlinks/plugins/device_display_brightness/ios`)
@ -205,8 +185,6 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/barcode_scan2/ios" :path: ".symlinks/plugins/barcode_scan2/ios"
connectivity_plus: connectivity_plus:
:path: ".symlinks/plugins/connectivity_plus/ios" :path: ".symlinks/plugins/connectivity_plus/ios"
cw_haven:
:path: ".symlinks/plugins/cw_haven/ios"
cw_monero: cw_monero:
:path: ".symlinks/plugins/cw_monero/ios" :path: ".symlinks/plugins/cw_monero/ios"
cw_shared_external: cw_shared_external:
@ -261,7 +239,6 @@ SPEC CHECKSUMS:
BigInt: f668a80089607f521586bbe29513d708491ef2f7 BigInt: f668a80089607f521586bbe29513d708491ef2f7
connectivity_plus: 413a8857dd5d9f1c399a39130850d02fe0feaf7e connectivity_plus: 413a8857dd5d9f1c399a39130850d02fe0feaf7e
CryptoSwift: d3d18dc357932f7e6d580689e065cf1f176007c1 CryptoSwift: d3d18dc357932f7e6d580689e065cf1f176007c1
cw_haven: b3e54e1fbe7b8e6fda57a93206bc38f8e89b898a
cw_monero: 4cf3b96f2da8e95e2ef7d6703dd4d2c509127b7d cw_monero: 4cf3b96f2da8e95e2ef7d6703dd4d2c509127b7d
cw_shared_external: 2972d872b8917603478117c9957dfca611845a92 cw_shared_external: 2972d872b8917603478117c9957dfca611845a92
device_display_brightness: 1510e72c567a1f6ce6ffe393dcd9afd1426034f7 device_display_brightness: 1510e72c567a1f6ce6ffe393dcd9afd1426034f7

View file

@ -232,6 +232,7 @@
files = ( files = (
); );
inputPaths = ( inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
); );
name = "Thin Binary"; name = "Thin Binary";
outputPaths = ( outputPaths = (

View file

@ -246,6 +246,7 @@ class BackupService {
final useEtherscan = data[PreferencesKey.useEtherscan] as bool?; final useEtherscan = data[PreferencesKey.useEtherscan] as bool?;
final syncAll = data[PreferencesKey.syncAllKey] as bool?; final syncAll = data[PreferencesKey.syncAllKey] as bool?;
final syncMode = data[PreferencesKey.syncModeKey] as int?; final syncMode = data[PreferencesKey.syncModeKey] as int?;
final autoGenerateSubaddressStatus = data[PreferencesKey.autoGenerateSubaddressStatusKey] as int?;
await _sharedPreferences.setString(PreferencesKey.currentWalletName, currentWalletName); await _sharedPreferences.setString(PreferencesKey.currentWalletName, currentWalletName);
@ -296,6 +297,9 @@ class BackupService {
if (fiatApiMode != null) if (fiatApiMode != null)
await _sharedPreferences.setInt(PreferencesKey.currentFiatApiModeKey, fiatApiMode); await _sharedPreferences.setInt(PreferencesKey.currentFiatApiModeKey, fiatApiMode);
if (autoGenerateSubaddressStatus != null)
await _sharedPreferences.setInt(PreferencesKey.autoGenerateSubaddressStatusKey,
autoGenerateSubaddressStatus);
if (currentPinLength != null) if (currentPinLength != null)
await _sharedPreferences.setInt(PreferencesKey.currentPinLength, currentPinLength); await _sharedPreferences.setInt(PreferencesKey.currentPinLength, currentPinLength);
@ -523,6 +527,8 @@ class BackupService {
_sharedPreferences.getInt(PreferencesKey.syncModeKey), _sharedPreferences.getInt(PreferencesKey.syncModeKey),
PreferencesKey.syncAllKey: PreferencesKey.syncAllKey:
_sharedPreferences.getBool(PreferencesKey.syncAllKey), _sharedPreferences.getBool(PreferencesKey.syncAllKey),
PreferencesKey.autoGenerateSubaddressStatusKey:
_sharedPreferences.getInt(PreferencesKey.autoGenerateSubaddressStatusKey),
}; };
return json.encode(preferences); return json.encode(preferences);

View file

@ -21,7 +21,7 @@ Future<double> _fetchPrice(Map<String, dynamic> args) async {
'key': secrets.fiatApiKey, 'key': secrets.fiatApiKey,
}; };
double price = 0.0; num price = 0.0;
try { try {
late final Uri uri; late final Uri uri;
@ -41,12 +41,12 @@ Future<double> _fetchPrice(Map<String, dynamic> args) async {
final results = responseJSON['results'] as Map<String, dynamic>; final results = responseJSON['results'] as Map<String, dynamic>;
if (results.isNotEmpty) { if (results.isNotEmpty) {
price = results.values.first as double; price = results.values.first as num;
} }
return price; return price.toDouble();
} catch (e) { } catch (e) {
return price; return price.toDouble();
} }
} }

View file

@ -6,6 +6,7 @@ import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
import 'package:cake_wallet/buy/payfura/payfura_buy_provider.dart'; import 'package:cake_wallet/buy/payfura/payfura_buy_provider.dart';
import 'package:cake_wallet/core/yat_service.dart'; import 'package:cake_wallet/core/yat_service.dart';
import 'package:cake_wallet/entities/background_tasks.dart'; import 'package:cake_wallet/entities/background_tasks.dart';
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
import 'package:cake_wallet/entities/exchange_api_mode.dart'; import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/entities/parse_address_from_domain.dart'; import 'package:cake_wallet/entities/parse_address_from_domain.dart';
import 'package:cake_wallet/entities/receive_page_option.dart'; import 'package:cake_wallet/entities/receive_page_option.dart';
@ -250,7 +251,6 @@ Future<void> setup({
if (!_isSetupFinished) { if (!_isSetupFinished) {
getIt.registerSingletonAsync<SharedPreferences>(() => SharedPreferences.getInstance()); getIt.registerSingletonAsync<SharedPreferences>(() => SharedPreferences.getInstance());
} }
if (!_isSetupFinished) { if (!_isSetupFinished) {
getIt.registerFactory(() => BackgroundTasks()); getIt.registerFactory(() => BackgroundTasks());
} }

View file

@ -0,0 +1,13 @@
enum AutoGenerateSubaddressStatus {
initialized(1),
enabled(2),
disabled(3);
const AutoGenerateSubaddressStatus(this.value);
final int value;
static AutoGenerateSubaddressStatus deserialize({required int raw}) =>
AutoGenerateSubaddressStatus.values.firstWhere((e) => e.value == raw);
}

View file

@ -1,4 +1,4 @@
import 'dart:io' show File, Platform; import 'dart:io' show Directory, File, Platform;
import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/entities/exchange_api_mode.dart'; import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/pathForWallet.dart';
@ -6,7 +6,7 @@ import 'package:cake_wallet/entities/secret_store_key.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:cake_wallet/core/secure_storage.dart'; import 'package:cake_wallet/core/secure_storage.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:share_plus/share_plus.dart'; import 'package:path_provider/path_provider.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
@ -28,7 +28,7 @@ const cakeWalletLitecoinElectrumUri = 'ltc-electrum.cakewallet.com:50002';
const havenDefaultNodeUri = 'nodes.havenprotocol.org:443'; const havenDefaultNodeUri = 'nodes.havenprotocol.org:443';
const ethereumDefaultNodeUri = 'ethereum.publicnode.com'; const ethereumDefaultNodeUri = 'ethereum.publicnode.com';
Future defaultSettingsMigration( Future<void> defaultSettingsMigration(
{required int version, {required int version,
required SharedPreferences sharedPreferences, required SharedPreferences sharedPreferences,
required SecureStorage secureStorage, required SecureStorage secureStorage,
@ -43,6 +43,8 @@ Future defaultSettingsMigration(
// check current nodes for nullability regardless of the version // check current nodes for nullability regardless of the version
await checkCurrentNodes(nodes, sharedPreferences); await checkCurrentNodes(nodes, sharedPreferences);
await _validateWalletInfoBoxData(walletInfoSource);
final isNewInstall = sharedPreferences final isNewInstall = sharedPreferences
.getInt(PreferencesKey.currentDefaultSettingsMigrationVersion) == null; .getInt(PreferencesKey.currentDefaultSettingsMigrationVersion) == null;
@ -179,6 +181,66 @@ Future defaultSettingsMigration(
PreferencesKey.currentDefaultSettingsMigrationVersion, version); PreferencesKey.currentDefaultSettingsMigrationVersion, version);
} }
Future<void> _validateWalletInfoBoxData(Box<WalletInfo> walletInfoSource) async {
final root = await getApplicationDocumentsDirectory();
for (var type in WalletType.values) {
if (type == WalletType.none) {
continue;
}
String prefix = walletTypeToString(type).toLowerCase();
Directory walletsDir = Directory('${root.path}/wallets/$prefix/');
if (!walletsDir.existsSync()) {
continue;
}
List<String> walletNames = walletsDir.listSync().map((e) => e.path.split("/").last).toList();
for (var name in walletNames) {
final dir = Directory(await pathForWalletDir(name: name, type: type));
final walletFiles = dir.listSync();
final hasCacheFile = walletFiles.any((element) => element.path.contains("$name/$name"));
if (!hasCacheFile) {
continue;
}
if (type == WalletType.monero || type == WalletType.haven) {
final hasKeysFile = walletFiles.any((element) => element.path.contains(".keys"));
if (!hasKeysFile) {
continue;
}
}
final id = prefix + '_' + name;
final exist = walletInfoSource.values.any((el) => el.id == id);
if (exist) {
continue;
}
final walletInfo = WalletInfo.external(
id: id,
type: type,
name: name,
isRecovery: true,
restoreHeight: 0,
date: DateTime.now(),
dirPath: dir.path,
path: '${dir.path}/$name',
address: '',
showIntroCakePayCard: false,
);
walletInfoSource.add(walletInfo);
}
}
}
Future<void> validateBitcoinSavedTransactionPriority(SharedPreferences sharedPreferences) async { Future<void> validateBitcoinSavedTransactionPriority(SharedPreferences sharedPreferences) async {
if (bitcoin == null) { if (bitcoin == null) {
return; return;
@ -226,7 +288,7 @@ Future<void> changeMoneroCurrentNodeToDefault(
{required SharedPreferences sharedPreferences, {required SharedPreferences sharedPreferences,
required Box<Node> nodes}) async { required Box<Node> nodes}) async {
final node = getMoneroDefaultNode(nodes: nodes); final node = getMoneroDefaultNode(nodes: nodes);
final nodeId = node?.key as int ?? 0; // 0 - England final nodeId = node.key as int? ?? 0; // 0 - England
await sharedPreferences.setInt(PreferencesKey.currentNodeIdKey, nodeId); await sharedPreferences.setInt(PreferencesKey.currentNodeIdKey, nodeId);
} }
@ -279,7 +341,7 @@ Future<void> changeBitcoinCurrentElectrumServerToDefault(
{required SharedPreferences sharedPreferences, {required SharedPreferences sharedPreferences,
required Box<Node> nodes}) async { required Box<Node> nodes}) async {
final server = getBitcoinDefaultElectrumServer(nodes: nodes); final server = getBitcoinDefaultElectrumServer(nodes: nodes);
final serverId = server?.key as int ?? 0; final serverId = server?.key as int? ?? 0;
await sharedPreferences.setInt(PreferencesKey.currentBitcoinElectrumSererIdKey, serverId); await sharedPreferences.setInt(PreferencesKey.currentBitcoinElectrumSererIdKey, serverId);
} }
@ -288,7 +350,7 @@ Future<void> changeLitecoinCurrentElectrumServerToDefault(
{required SharedPreferences sharedPreferences, {required SharedPreferences sharedPreferences,
required Box<Node> nodes}) async { required Box<Node> nodes}) async {
final server = getLitecoinDefaultElectrumServer(nodes: nodes); final server = getLitecoinDefaultElectrumServer(nodes: nodes);
final serverId = server?.key as int ?? 0; final serverId = server?.key as int? ?? 0;
await sharedPreferences.setInt(PreferencesKey.currentLitecoinElectrumSererIdKey, serverId); await sharedPreferences.setInt(PreferencesKey.currentLitecoinElectrumSererIdKey, serverId);
} }
@ -297,7 +359,7 @@ Future<void> changeHavenCurrentNodeToDefault(
{required SharedPreferences sharedPreferences, {required SharedPreferences sharedPreferences,
required Box<Node> nodes}) async { required Box<Node> nodes}) async {
final node = getHavenDefaultNode(nodes: nodes); final node = getHavenDefaultNode(nodes: nodes);
final nodeId = node?.key as int ?? 0; final nodeId = node?.key as int? ?? 0;
await sharedPreferences.setInt(PreferencesKey.currentHavenNodeIdKey, nodeId); await sharedPreferences.setInt(PreferencesKey.currentHavenNodeIdKey, nodeId);
} }

View file

@ -50,6 +50,7 @@ class PreferencesKey {
'${PreferencesKey.moneroWalletPasswordUpdateV1Base}_${name}'; '${PreferencesKey.moneroWalletPasswordUpdateV1Base}_${name}';
static const exchangeProvidersSelection = 'exchange-providers-selection'; static const exchangeProvidersSelection = 'exchange-providers-selection';
static const autoGenerateSubaddressStatusKey = 'auto_generate_subaddress_status';
static const clearnetDonationLink = 'clearnet_donation_link'; static const clearnetDonationLink = 'clearnet_donation_link';
static const onionDonationLink = 'onion_donation_link'; static const onionDonationLink = 'onion_donation_link';
static const lastSeenAppVersion = 'last_seen_app_version'; static const lastSeenAppVersion = 'last_seen_app_version';

View file

@ -6,7 +6,9 @@ import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/locales/locale.dart'; import 'package:cake_wallet/locales/locale.dart';
import 'package:cake_wallet/store/yat/yat_store.dart'; import 'package:cake_wallet/store/yat/yat_store.dart';
import 'package:cake_wallet/utils/exception_handler.dart'; import 'package:cake_wallet/utils/exception_handler.dart';
import 'package:cw_core/address_info.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart'; import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:cw_core/hive_type_ids.dart';
import 'package:cw_core/root_dir.dart'; import 'package:cw_core/root_dir.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart'; import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@ -40,6 +42,7 @@ import 'package:uni_links/uni_links.dart';
import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_core/unspent_coins_info.dart';
import 'package:cake_wallet/monero/monero.dart'; import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/wallet_type_utils.dart'; import 'package:cake_wallet/wallet_type_utils.dart';
import 'package:cw_core/cake_hive.dart';
final navigatorKey = GlobalKey<NavigatorState>(); final navigatorKey = GlobalKey<NavigatorState>();
final rootKey = GlobalKey<RootState>(); final rootKey = GlobalKey<RootState>();
@ -58,7 +61,8 @@ Future<void> main() async {
return true; return true;
}; };
await Hive.close();
await CakeHive.close();
await initializeAppConfigs(); await initializeAppConfigs();
@ -71,69 +75,73 @@ Future<void> main() async {
Future<void> initializeAppConfigs() async { Future<void> initializeAppConfigs() async {
setRootDirFromEnv(); setRootDirFromEnv();
final appDir = await getAppDir(); final appDir = await getAppDir();
Hive.init(appDir.path); CakeHive.init(appDir.path);
if (!Hive.isAdapterRegistered(Contact.typeId)) { if (!CakeHive.isAdapterRegistered(Contact.typeId)) {
Hive.registerAdapter(ContactAdapter()); CakeHive.registerAdapter(ContactAdapter());
} }
if (!Hive.isAdapterRegistered(Node.typeId)) { if (!CakeHive.isAdapterRegistered(Node.typeId)) {
Hive.registerAdapter(NodeAdapter()); CakeHive.registerAdapter(NodeAdapter());
} }
if (!Hive.isAdapterRegistered(TransactionDescription.typeId)) { if (!CakeHive.isAdapterRegistered(TransactionDescription.typeId)) {
Hive.registerAdapter(TransactionDescriptionAdapter()); CakeHive.registerAdapter(TransactionDescriptionAdapter());
} }
if (!Hive.isAdapterRegistered(Trade.typeId)) { if (!CakeHive.isAdapterRegistered(Trade.typeId)) {
Hive.registerAdapter(TradeAdapter()); CakeHive.registerAdapter(TradeAdapter());
} }
if (!Hive.isAdapterRegistered(WalletInfo.typeId)) { if (!CakeHive.isAdapterRegistered(AddressInfo.typeId)) {
Hive.registerAdapter(WalletInfoAdapter()); CakeHive.registerAdapter(AddressInfoAdapter());
} }
if (!Hive.isAdapterRegistered(walletTypeTypeId)) { if (!CakeHive.isAdapterRegistered(WalletInfo.typeId)) {
Hive.registerAdapter(WalletTypeAdapter()); CakeHive.registerAdapter(WalletInfoAdapter());
} }
if (!Hive.isAdapterRegistered(Template.typeId)) { if (!CakeHive.isAdapterRegistered(WALLET_TYPE_TYPE_ID)) {
Hive.registerAdapter(TemplateAdapter()); CakeHive.registerAdapter(WalletTypeAdapter());
} }
if (!Hive.isAdapterRegistered(ExchangeTemplate.typeId)) { if (!CakeHive.isAdapterRegistered(Template.typeId)) {
Hive.registerAdapter(ExchangeTemplateAdapter()); CakeHive.registerAdapter(TemplateAdapter());
} }
if (!Hive.isAdapterRegistered(Order.typeId)) { if (!CakeHive.isAdapterRegistered(ExchangeTemplate.typeId)) {
Hive.registerAdapter(OrderAdapter()); CakeHive.registerAdapter(ExchangeTemplateAdapter());
} }
if (!isMoneroOnly && !Hive.isAdapterRegistered(UnspentCoinsInfo.typeId)) { if (!CakeHive.isAdapterRegistered(Order.typeId)) {
Hive.registerAdapter(UnspentCoinsInfoAdapter()); CakeHive.registerAdapter(OrderAdapter());
} }
if (!Hive.isAdapterRegistered(AnonpayInvoiceInfo.typeId)) { if (!isMoneroOnly && !CakeHive.isAdapterRegistered(UnspentCoinsInfo.typeId)) {
Hive.registerAdapter(AnonpayInvoiceInfoAdapter()); CakeHive.registerAdapter(UnspentCoinsInfoAdapter());
} }
final secureStorage = secureStorageShared; if (!CakeHive.isAdapterRegistered(AnonpayInvoiceInfo.typeId)) {
final transactionDescriptionsBoxKey = CakeHive.registerAdapter(AnonpayInvoiceInfoAdapter());
await getEncryptionKey(secureStorage: secureStorage, forKey: TransactionDescription.boxKey); }
final tradesBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Trade.boxKey);
final ordersBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Order.boxKey); final secureStorage = secureStorageShared;
final contacts = await Hive.openBox<Contact>(Contact.boxName); final transactionDescriptionsBoxKey =
final nodes = await Hive.openBox<Node>(Node.boxName); await getEncryptionKey(secureStorage: secureStorage, forKey: TransactionDescription.boxKey);
final transactionDescriptions = await Hive.openBox<TransactionDescription>( final tradesBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Trade.boxKey);
TransactionDescription.boxName, final ordersBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Order.boxKey);
encryptionKey: transactionDescriptionsBoxKey); final contacts = await CakeHive.openBox<Contact>(Contact.boxName);
final trades = await Hive.openBox<Trade>(Trade.boxName, encryptionKey: tradesBoxKey); final nodes = await CakeHive.openBox<Node>(Node.boxName);
final orders = await Hive.openBox<Order>(Order.boxName, encryptionKey: ordersBoxKey); final transactionDescriptions = await CakeHive.openBox<TransactionDescription>(
final walletInfoSource = await Hive.openBox<WalletInfo>(WalletInfo.boxName); TransactionDescription.boxName,
final templates = await Hive.openBox<Template>(Template.boxName); encryptionKey: transactionDescriptionsBoxKey);
final exchangeTemplates = await Hive.openBox<ExchangeTemplate>(ExchangeTemplate.boxName); final trades = await CakeHive.openBox<Trade>(Trade.boxName, encryptionKey: tradesBoxKey);
final anonpayInvoiceInfo = await Hive.openBox<AnonpayInvoiceInfo>(AnonpayInvoiceInfo.boxName); final orders = await CakeHive.openBox<Order>(Order.boxName, encryptionKey: ordersBoxKey);
final unspentCoinsInfoSource = await Hive.openBox<UnspentCoinsInfo>(UnspentCoinsInfo.boxName); final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
final templates = await CakeHive.openBox<Template>(Template.boxName);
final exchangeTemplates = await CakeHive.openBox<ExchangeTemplate>(ExchangeTemplate.boxName);
final anonpayInvoiceInfo = await CakeHive.openBox<AnonpayInvoiceInfo>(AnonpayInvoiceInfo.boxName);
final unspentCoinsInfoSource = await CakeHive.openBox<UnspentCoinsInfo>(UnspentCoinsInfo.boxName);
await initialSetup( await initialSetup(
sharedPreferences: await SharedPreferences.getInstance(), sharedPreferences: await SharedPreferences.getInstance(),

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
import 'package:cake_wallet/entities/fiat_api_mode.dart'; import 'package:cake_wallet/entities/fiat_api_mode.dart';
import 'package:cake_wallet/entities/update_haven_rate.dart'; import 'package:cake_wallet/entities/update_haven_rate.dart';
import 'package:cake_wallet/ethereum/ethereum.dart'; import 'package:cake_wallet/ethereum/ethereum.dart';
@ -21,36 +22,36 @@ ReactionDisposer? _onCurrentWalletChangeReaction;
ReactionDisposer? _onCurrentWalletChangeFiatRateUpdateReaction; ReactionDisposer? _onCurrentWalletChangeFiatRateUpdateReaction;
//ReactionDisposer _onCurrentWalletAddressChangeReaction; //ReactionDisposer _onCurrentWalletAddressChangeReaction;
void startCurrentWalletChangeReaction(AppStore appStore, void startCurrentWalletChangeReaction(
SettingsStore settingsStore, FiatConversionStore fiatConversionStore) { AppStore appStore, SettingsStore settingsStore, FiatConversionStore fiatConversionStore) {
_onCurrentWalletChangeReaction?.reaction.dispose(); _onCurrentWalletChangeReaction?.reaction.dispose();
_onCurrentWalletChangeFiatRateUpdateReaction?.reaction.dispose(); _onCurrentWalletChangeFiatRateUpdateReaction?.reaction.dispose();
//_onCurrentWalletAddressChangeReaction?.reaction?dispose(); //_onCurrentWalletAddressChangeReaction?.reaction?dispose();
//_onCurrentWalletAddressChangeReaction = reaction((_) => appStore.wallet.walletAddresses.address, //_onCurrentWalletAddressChangeReaction = reaction((_) => appStore.wallet.walletAddresses.address,
//(String address) async { //(String address) async {
//if (address == appStore.wallet.walletInfo.yatLastUsedAddress) { //if (address == appStore.wallet.walletInfo.yatLastUsedAddress) {
// return; // return;
//} //}
//try { //try {
// final yatStore = getIt.get<YatStore>(); // final yatStore = getIt.get<YatStore>();
// await updateEmojiIdAddress( // await updateEmojiIdAddress(
// appStore.wallet.walletInfo.yatEmojiId, // appStore.wallet.walletInfo.yatEmojiId,
// appStore.wallet.walletAddresses.address, // appStore.wallet.walletAddresses.address,
// yatStore.apiKey, // yatStore.apiKey,
// appStore.wallet.type // appStore.wallet.type
// ); // );
// appStore.wallet.walletInfo.yatLastUsedAddress = address; // appStore.wallet.walletInfo.yatLastUsedAddress = address;
// await appStore.wallet.walletInfo.save(); // await appStore.wallet.walletInfo.save();
//} catch (e) { //} catch (e) {
// print(e.toString()); // print(e.toString());
//} //}
//}); //});
_onCurrentWalletChangeReaction = reaction((_) => appStore.wallet, (WalletBase< _onCurrentWalletChangeReaction = reaction((_) => appStore.wallet,
Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>? (WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>?
wallet) async { wallet) async {
try { try {
if (wallet == null) { if (wallet == null) {
return; return;
@ -59,11 +60,13 @@ void startCurrentWalletChangeReaction(AppStore appStore,
final node = settingsStore.getCurrentNode(wallet.type); final node = settingsStore.getCurrentNode(wallet.type);
startWalletSyncStatusChangeReaction(wallet, fiatConversionStore); startWalletSyncStatusChangeReaction(wallet, fiatConversionStore);
startCheckConnectionReaction(wallet, settingsStore); startCheckConnectionReaction(wallet, settingsStore);
await getIt.get<SharedPreferences>().setString(PreferencesKey.currentWalletName, wallet.name);
await getIt await getIt
.get<SharedPreferences>() .get<SharedPreferences>()
.setString(PreferencesKey.currentWalletName, wallet.name); .setInt(PreferencesKey.currentWalletType, serializeToInt(wallet.type));
await getIt.get<SharedPreferences>().setInt( if (wallet.type == WalletType.monero) {
PreferencesKey.currentWalletType, serializeToInt(wallet.type)); _setAutoGenerateSubaddressStatus(wallet, settingsStore);
}
await wallet.connectToNode(node: node); await wallet.connectToNode(node: node);
if (wallet.type == WalletType.haven) { if (wallet.type == WalletType.haven) {
@ -82,9 +85,8 @@ void startCurrentWalletChangeReaction(AppStore appStore,
} }
}); });
_onCurrentWalletChangeFiatRateUpdateReaction = _onCurrentWalletChangeFiatRateUpdateReaction = reaction((_) => appStore.wallet,
reaction((_) => appStore.wallet, (WalletBase<Balance, (WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>?
TransactionHistoryBase<TransactionInfo>, TransactionInfo>?
wallet) async { wallet) async {
try { try {
if (wallet == null || settingsStore.fiatApiMode == FiatApiMode.disabled) { if (wallet == null || settingsStore.fiatApiMode == FiatApiMode.disabled) {
@ -92,11 +94,10 @@ void startCurrentWalletChangeReaction(AppStore appStore,
} }
fiatConversionStore.prices[wallet.currency] = 0; fiatConversionStore.prices[wallet.currency] = 0;
fiatConversionStore.prices[wallet.currency] = fiatConversionStore.prices[wallet.currency] = await FiatConversionService.fetchPrice(
await FiatConversionService.fetchPrice( crypto: wallet.currency,
crypto: wallet.currency, fiat: settingsStore.fiatCurrency,
fiat: settingsStore.fiatCurrency, torOnly: settingsStore.fiatApiMode == FiatApiMode.torOnly);
torOnly: settingsStore.fiatApiMode == FiatApiMode.torOnly);
if (wallet.type == WalletType.ethereum) { if (wallet.type == WalletType.ethereum) {
final currencies = final currencies =
@ -116,3 +117,17 @@ void startCurrentWalletChangeReaction(AppStore appStore,
} }
}); });
} }
void _setAutoGenerateSubaddressStatus(
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> wallet,
SettingsStore settingsStore,
) async {
final walletHasAddresses = await wallet.walletAddresses.addressesMap.length > 1;
if (settingsStore.autoGenerateSubaddressStatus == AutoGenerateSubaddressStatus.initialized &&
walletHasAddresses) {
settingsStore.autoGenerateSubaddressStatus = AutoGenerateSubaddressStatus.disabled;
}
wallet.isEnabledAutoGenerateSubaddress =
settingsStore.autoGenerateSubaddressStatus == AutoGenerateSubaddressStatus.enabled ||
settingsStore.autoGenerateSubaddressStatus == AutoGenerateSubaddressStatus.initialized;
}

View file

@ -73,12 +73,12 @@ class DesktopDashboardActions extends StatelessWidget {
), ),
], ],
), ),
Expanded( Expanded(
child: MarketPlacePage( child: MarketPlacePage(
dashboardViewModel: dashboardViewModel, dashboardViewModel: dashboardViewModel,
marketPlaceViewModel: getIt.get<MarketPlaceViewModel>(), marketPlaceViewModel: getIt.get<MarketPlaceViewModel>(),
),
), ),
),
], ],
); );
} }

View file

@ -1,9 +1,10 @@
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart'; import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart'; import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/monero_accounts/monero_account_list_page.dart';
import 'package:cake_wallet/anonpay/anonpay_donation_link_info.dart'; import 'package:cake_wallet/anonpay/anonpay_donation_link_info.dart';
import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/entities/receive_page_option.dart'; import 'package:cake_wallet/entities/receive_page_option.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/present_receive_option_picker.dart'; import 'package:cake_wallet/src/screens/dashboard/widgets/present_receive_option_picker.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/src/widgets/gradient_background.dart'; import 'package:cake_wallet/src/widgets/gradient_background.dart';
@ -28,7 +29,6 @@ import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:keyboard_actions/keyboard_actions.dart'; import 'package:keyboard_actions/keyboard_actions.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart'; import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart'; import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
@ -178,7 +178,11 @@ class AddressPage extends BasePage {
Observer(builder: (_) { Observer(builder: (_) {
if (addressListViewModel.hasAddressList) { if (addressListViewModel.hasAddressList) {
return GestureDetector( return GestureDetector(
onTap: () => Navigator.of(context).pushNamed(Routes.receive), onTap: () async => dashboardViewModel.isAutoGenerateSubaddressesEnabled
? await showPopUp<void>(
context: context,
builder: (_) => getIt.get<MoneroAccountListPage>())
: Navigator.of(context).pushNamed(Routes.receive),
child: Container( child: Container(
height: 50, height: 50,
padding: EdgeInsets.only(left: 24, right: 12), padding: EdgeInsets.only(left: 24, right: 12),
@ -197,17 +201,26 @@ class AddressPage extends BasePage {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[ children: <Widget>[
Observer( Observer(
builder: (_) => Text( builder: (_) {
addressListViewModel.hasAccounts String label = addressListViewModel.hasAccounts
? S.of(context).accounts_subaddresses ? S.of(context).accounts_subaddresses
: S.of(context).addresses, : S.of(context).addresses;
style: TextStyle(
fontSize: 14, if (dashboardViewModel.isAutoGenerateSubaddressesEnabled) {
fontWeight: FontWeight.w500, label = addressListViewModel.hasAccounts
color: Theme.of(context) ? S.of(context).accounts
: S.of(context).account;
}
return Text(
label,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Theme.of(context)
.extension<SyncIndicatorTheme>()! .extension<SyncIndicatorTheme>()!
.textColor), .textColor),
)), );
},),
Icon( Icon(
Icons.arrow_forward_ios, Icons.arrow_forward_ios,
size: 14, size: 14,
@ -217,7 +230,7 @@ class AddressPage extends BasePage {
), ),
), ),
); );
} else if (addressListViewModel.showElectrumAddressDisclaimer) { } else if (dashboardViewModel.isAutoGenerateSubaddressesEnabled || addressListViewModel.showElectrumAddressDisclaimer) {
return Text(S.of(context).electrum_address_disclaimer, return Text(S.of(context).electrum_address_disclaimer,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(

View file

@ -48,15 +48,15 @@ class MarketPlacePage extends StatelessWidget {
child: ListView( child: ListView(
controller: _scrollController, controller: _scrollController,
children: <Widget>[ children: <Widget>[
SizedBox(height: 20), // SizedBox(height: 20),
DashBoardRoundedCardWidget( // DashBoardRoundedCardWidget(
onTap: () => launchUrl( // onTap: () => launchUrl(
Uri.parse("https://cakelabs.com/news/cake-pay-mobile-to-shut-down/"), // Uri.parse("https://cakelabs.com/news/cake-pay-mobile-to-shut-down/"),
mode: LaunchMode.externalApplication, // mode: LaunchMode.externalApplication,
), // ),
title: S.of(context).cake_pay_title, // title: S.of(context).cake_pay_title,
subTitle: S.of(context).cake_pay_subtitle, // subTitle: S.of(context).cake_pay_subtitle,
), // ),
SizedBox(height: 20), SizedBox(height: 20),
DashBoardRoundedCardWidget( DashBoardRoundedCardWidget(
onTap: () => launchUrl( onTap: () => launchUrl(

View file

@ -5,13 +5,14 @@ import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
class AccountTile extends StatelessWidget { class AccountTile extends StatelessWidget {
AccountTile( AccountTile({
{required this.isCurrent, required this.isCurrent,
required this.accountName, required this.accountName,
this.accountBalance, this.accountBalance,
required this.currency, required this.currency,
required this.onTap, required this.onTap,
required this.onEdit}); required this.onEdit,
});
final bool isCurrent; final bool isCurrent;
final String accountName; final String accountName;

View file

@ -75,7 +75,7 @@ class RestoreOptionsPage extends BasePage {
await restoreFromQRViewModel.create(restoreWallet: restoreWallet); await restoreFromQRViewModel.create(restoreWallet: restoreWallet);
if (restoreFromQRViewModel.state is FailureState) { if (restoreFromQRViewModel.state is FailureState) {
_onWalletCreateFailure(context, _onWalletCreateFailure(context,
'Create wallet state: ${restoreFromQRViewModel.state.runtimeType.toString()}'); 'Create wallet state: ${(restoreFromQRViewModel.state as FailureState).error}');
} }
} catch (e) { } catch (e) {
_onWalletCreateFailure(context, e.toString()); _onWalletCreateFailure(context, e.toString());

View file

@ -21,60 +21,66 @@ class DisplaySettingsPage extends BasePage {
@override @override
Widget body(BuildContext context) { Widget body(BuildContext context) {
return Observer(builder: (_) { return SingleChildScrollView(
return Container( child: Observer(builder: (_) {
padding: EdgeInsets.only(top: 10), return Container(
child: Column( padding: EdgeInsets.only(top: 10),
children: [ child: Column(
SettingsSwitcherCell( children: [
title: S.current.settings_display_balance, SettingsSwitcherCell(
value: _displaySettingsViewModel.shouldDisplayBalance, title: S.current.settings_display_balance,
onValueChange: (_, bool value) { value: _displaySettingsViewModel.shouldDisplayBalance,
_displaySettingsViewModel.setShouldDisplayBalance(value); onValueChange: (_, bool value) {
}), _displaySettingsViewModel.setShouldDisplayBalance(value);
SettingsSwitcherCell( }),
title: S.current.show_market_place, SettingsSwitcherCell(
value: _displaySettingsViewModel.shouldShowMarketPlaceInDashboard, title: S.current.show_market_place,
onValueChange: (_, bool value) { value: _displaySettingsViewModel.shouldShowMarketPlaceInDashboard,
_displaySettingsViewModel.setShouldShowMarketPlaceInDashbaord(value); onValueChange: (_, bool value) {
}, _displaySettingsViewModel.setShouldShowMarketPlaceInDashbaord(value);
),
//if (!isHaven) it does not work correctly
if(!_displaySettingsViewModel.disabledFiatApiMode)
SettingsPickerCell<FiatCurrency>(
title: S.current.settings_currency,
searchHintText: S.current.search_currency,
items: FiatCurrency.all,
selectedItem: _displaySettingsViewModel.fiatCurrency,
onItemSelected: (FiatCurrency currency) => _displaySettingsViewModel.setFiatCurrency(currency),
images: FiatCurrency.all.map((e) => Image.asset("assets/images/flags/${e.countryCode}.png")).toList(),
isGridView: true,
matchingCriteria: (FiatCurrency currency, String searchText) {
return currency.title.toLowerCase().contains(searchText) ||
currency.fullName.toLowerCase().contains(searchText);
}, },
), ),
SettingsPickerCell<String>( //if (!isHaven) it does not work correctly
title: S.current.settings_change_language, if (!_displaySettingsViewModel.disabledFiatApiMode)
searchHintText: S.current.search_language, SettingsPickerCell<FiatCurrency>(
items: LanguageService.list.keys.toList(), title: S.current.settings_currency,
displayItem: (dynamic code) { searchHintText: S.current.search_currency,
return LanguageService.list[code] ?? ''; items: FiatCurrency.all,
}, selectedItem: _displaySettingsViewModel.fiatCurrency,
selectedItem: _displaySettingsViewModel.languageCode, onItemSelected: (FiatCurrency currency) =>
onItemSelected: _displaySettingsViewModel.onLanguageSelected, _displaySettingsViewModel.setFiatCurrency(currency),
images: LanguageService.list.keys images: FiatCurrency.all
.map((e) => Image.asset("assets/images/flags/${LanguageService.localeCountryCode[e]}.png")) .map((e) => Image.asset("assets/images/flags/${e.countryCode}.png"))
.toList(), .toList(),
matchingCriteria: (String code, String searchText) { isGridView: true,
return LanguageService.list[code]?.toLowerCase().contains(searchText) ?? false; matchingCriteria: (FiatCurrency currency, String searchText) {
}, return currency.title.toLowerCase().contains(searchText) ||
), currency.fullName.toLowerCase().contains(searchText);
if (ResponsiveLayoutUtil.instance.isMobile && DeviceInfo.instance.isMobile) },
SettingsThemeChoicesCell(_displaySettingsViewModel), ),
], SettingsPickerCell<String>(
), title: S.current.settings_change_language,
); searchHintText: S.current.search_language,
}); items: LanguageService.list.keys.toList(),
displayItem: (dynamic code) {
return LanguageService.list[code] ?? '';
},
selectedItem: _displaySettingsViewModel.languageCode,
onItemSelected: _displaySettingsViewModel.onLanguageSelected,
images: LanguageService.list.keys
.map((e) => Image.asset(
"assets/images/flags/${LanguageService.localeCountryCode[e]}.png"))
.toList(),
matchingCriteria: (String code, String searchText) {
return LanguageService.list[code]?.toLowerCase().contains(searchText) ?? false;
},
),
if (ResponsiveLayoutUtil.instance.isMobile && DeviceInfo.instance.isMobile)
SettingsThemeChoicesCell(_displaySettingsViewModel),
],
),
);
}),
);
} }
} }

View file

@ -42,36 +42,40 @@ class ManageNodesPage extends BasePage {
return nodeListViewModel.nodes.length; return nodeListViewModel.nodes.length;
}, },
itemBuilder: (_, index) { itemBuilder: (_, index) {
final node = nodeListViewModel.nodes[index]; return Observer(
final isSelected = node.keyIndex == nodeListViewModel.currentNode.keyIndex; builder: (context) {
final nodeListRow = NodeListRow( final node = nodeListViewModel.nodes[index];
title: node.uriRaw, final isSelected = node.keyIndex == nodeListViewModel.currentNode.keyIndex;
node: node, final nodeListRow = NodeListRow(
isSelected: isSelected, title: node.uriRaw,
onTap: (_) async { node: node,
if (isSelected) { isSelected: isSelected,
return; onTap: (_) async {
} if (isSelected) {
return;
}
await showPopUp<void>( await showPopUp<void>(
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return AlertWithTwoActions( return AlertWithTwoActions(
alertTitle: S.of(context).change_current_node_title, alertTitle: S.of(context).change_current_node_title,
alertContent: nodeListViewModel.getAlertContent(node.uriRaw), alertContent: nodeListViewModel.getAlertContent(node.uriRaw),
leftButtonText: S.of(context).cancel, leftButtonText: S.of(context).cancel,
rightButtonText: S.of(context).change, rightButtonText: S.of(context).change,
actionLeftButton: () => Navigator.of(context).pop(), actionLeftButton: () => Navigator.of(context).pop(),
actionRightButton: () async { actionRightButton: () async {
await nodeListViewModel.setAsCurrent(node); await nodeListViewModel.setAsCurrent(node);
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
); );
}); },
);
},
);
return nodeListRow;
}, },
); );
return nodeListRow;
}, },
), ),
); );

View file

@ -50,6 +50,14 @@ class PrivacyPage extends BasePage {
onValueChange: (BuildContext _, bool value) { onValueChange: (BuildContext _, bool value) {
_privacySettingsViewModel.setShouldSaveRecipientAddress(value); _privacySettingsViewModel.setShouldSaveRecipientAddress(value);
}), }),
if (_privacySettingsViewModel.isAutoGenerateSubaddressesVisible)
SettingsSwitcherCell(
title: S.current.auto_generate_subaddresses,
value: _privacySettingsViewModel.isAutoGenerateSubaddressesEnabled,
onValueChange: (BuildContext _, bool value) {
_privacySettingsViewModel.setAutoGenerateSubaddresses(value);
},
),
if (DeviceInfo.instance.isMobile) if (DeviceInfo.instance.isMobile)
SettingsSwitcherCell( SettingsSwitcherCell(
title: S.current.prevent_screenshots, title: S.current.prevent_screenshots,

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart'; import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -44,7 +45,7 @@ class SupportTile extends StatelessWidget {
style: TextStyle( style: TextStyle(
fontSize: 20, fontSize: 20,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Theme.of(context).dialogTheme.backgroundColor, color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
), ),
), ),
Padding( Padding(

View file

@ -17,7 +17,7 @@ class SearchBarWidget extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return TextFormField( return TextFormField(
controller: searchController, controller: searchController,
style: TextStyle(color: Theme.of(context).extension<PickerTheme>()!.searchTextColor), style: TextStyle(color: Theme.of(context).extension<PickerTheme>()!.searchHintColor),
decoration: InputDecoration( decoration: InputDecoration(
hintText: hintText ?? S.of(context).search_currency, hintText: hintText ?? S.of(context).search_currency,
hintStyle: TextStyle(color: Theme.of(context).extension<PickerTheme>()!.searchHintColor), hintStyle: TextStyle(color: Theme.of(context).extension<PickerTheme>()!.searchHintColor),

View file

@ -1,6 +1,7 @@
import 'dart:io'; import 'dart:io';
import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
import 'package:cake_wallet/entities/cake_2fa_preset_options.dart'; import 'package:cake_wallet/entities/cake_2fa_preset_options.dart';
import 'package:cake_wallet/entities/background_tasks.dart'; import 'package:cake_wallet/entities/background_tasks.dart';
import 'package:cake_wallet/entities/exchange_api_mode.dart'; import 'package:cake_wallet/entities/exchange_api_mode.dart';
@ -43,6 +44,7 @@ abstract class SettingsStoreBase with Store {
required FiatCurrency initialFiatCurrency, required FiatCurrency initialFiatCurrency,
required BalanceDisplayMode initialBalanceDisplayMode, required BalanceDisplayMode initialBalanceDisplayMode,
required bool initialSaveRecipientAddress, required bool initialSaveRecipientAddress,
required AutoGenerateSubaddressStatus initialAutoGenerateSubaddressStatus,
required bool initialAppSecure, required bool initialAppSecure,
required bool initialDisableBuy, required bool initialDisableBuy,
required bool initialDisableSell, required bool initialDisableSell,
@ -88,6 +90,7 @@ abstract class SettingsStoreBase with Store {
fiatCurrency = initialFiatCurrency, fiatCurrency = initialFiatCurrency,
balanceDisplayMode = initialBalanceDisplayMode, balanceDisplayMode = initialBalanceDisplayMode,
shouldSaveRecipientAddress = initialSaveRecipientAddress, shouldSaveRecipientAddress = initialSaveRecipientAddress,
autoGenerateSubaddressStatus = initialAutoGenerateSubaddressStatus,
fiatApiMode = initialFiatMode, fiatApiMode = initialFiatMode,
allowBiometricalAuthentication = initialAllowBiometricalAuthentication, allowBiometricalAuthentication = initialAllowBiometricalAuthentication,
selectedCake2FAPreset = initialCake2FAPresetOptions, selectedCake2FAPreset = initialCake2FAPresetOptions,
@ -198,6 +201,11 @@ abstract class SettingsStoreBase with Store {
(bool disableSell) => (bool disableSell) =>
sharedPreferences.setBool(PreferencesKey.disableSellKey, disableSell)); sharedPreferences.setBool(PreferencesKey.disableSellKey, disableSell));
reaction(
(_) => autoGenerateSubaddressStatus,
(AutoGenerateSubaddressStatus autoGenerateSubaddressStatus) => sharedPreferences.setInt(
PreferencesKey.autoGenerateSubaddressStatusKey, autoGenerateSubaddressStatus.value));
reaction( reaction(
(_) => fiatApiMode, (_) => fiatApiMode,
(FiatApiMode mode) => (FiatApiMode mode) =>
@ -339,6 +347,7 @@ abstract class SettingsStoreBase with Store {
static const defaultActionsMode = 11; static const defaultActionsMode = 11;
static const defaultPinCodeTimeOutDuration = PinCodeRequiredDuration.tenminutes; static const defaultPinCodeTimeOutDuration = PinCodeRequiredDuration.tenminutes;
static final walletPasswordDirectInput = Platform.isLinux; static final walletPasswordDirectInput = Platform.isLinux;
static const defaultAutoGenerateSubaddressStatus = AutoGenerateSubaddressStatus.initialized;
@observable @observable
FiatCurrency fiatCurrency; FiatCurrency fiatCurrency;
@ -361,6 +370,9 @@ abstract class SettingsStoreBase with Store {
@observable @observable
bool shouldSaveRecipientAddress; bool shouldSaveRecipientAddress;
@observable
AutoGenerateSubaddressStatus autoGenerateSubaddressStatus;
@observable @observable
bool isAppSecure; bool isAppSecure;
@ -601,15 +613,15 @@ abstract class SettingsStoreBase with Store {
final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId); final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId);
final havenNode = nodeSource.get(havenNodeId); final havenNode = nodeSource.get(havenNodeId);
final ethereumNode = nodeSource.get(ethereumNodeId); final ethereumNode = nodeSource.get(ethereumNodeId);
final packageInfo = await PackageInfo.fromPlatform();
final deviceName = await _getDeviceName() ?? ''; final deviceName = await _getDeviceName() ?? '';
final shouldShowYatPopup = sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? true; final shouldShowYatPopup = sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? true;
var appVersion = ''; final generateSubaddresses =
sharedPreferences.getInt(PreferencesKey.autoGenerateSubaddressStatusKey);
try {
final packageInfo = await PackageInfo.fromPlatform();
appVersion = packageInfo.version;
} catch(_) {}
final autoGenerateSubaddressStatus = generateSubaddresses != null
? AutoGenerateSubaddressStatus.deserialize(raw: generateSubaddresses)
: defaultAutoGenerateSubaddressStatus;
final nodes = <WalletType, Node>{}; final nodes = <WalletType, Node>{};
if (moneroNode != null) { if (moneroNode != null) {
@ -641,12 +653,13 @@ abstract class SettingsStoreBase with Store {
sharedPreferences: sharedPreferences, sharedPreferences: sharedPreferences,
initialShouldShowMarketPlaceInDashboard: shouldShowMarketPlaceInDashboard, initialShouldShowMarketPlaceInDashboard: shouldShowMarketPlaceInDashboard,
nodes: nodes, nodes: nodes,
appVersion: appVersion, appVersion: packageInfo.version,
deviceName: deviceName, deviceName: deviceName,
isBitcoinBuyEnabled: isBitcoinBuyEnabled, isBitcoinBuyEnabled: isBitcoinBuyEnabled,
initialFiatCurrency: currentFiatCurrency, initialFiatCurrency: currentFiatCurrency,
initialBalanceDisplayMode: currentBalanceDisplayMode, initialBalanceDisplayMode: currentBalanceDisplayMode,
initialSaveRecipientAddress: shouldSaveRecipientAddress, initialSaveRecipientAddress: shouldSaveRecipientAddress,
initialAutoGenerateSubaddressStatus: autoGenerateSubaddressStatus,
initialAppSecure: isAppSecure, initialAppSecure: isAppSecure,
initialDisableBuy: disableBuy, initialDisableBuy: disableBuy,
initialDisableSell: disableSell, initialDisableSell: disableSell,
@ -716,6 +729,13 @@ abstract class SettingsStoreBase with Store {
priority[WalletType.ethereum]!; priority[WalletType.ethereum]!;
} }
final generateSubaddresses =
sharedPreferences.getInt(PreferencesKey.autoGenerateSubaddressStatusKey);
autoGenerateSubaddressStatus = generateSubaddresses != null
? AutoGenerateSubaddressStatus.deserialize(raw: generateSubaddresses)
: defaultAutoGenerateSubaddressStatus;
balanceDisplayMode = BalanceDisplayMode.deserialize( balanceDisplayMode = BalanceDisplayMode.deserialize(
raw: sharedPreferences.getInt(PreferencesKey.currentBalanceDisplayModeKey)!); raw: sharedPreferences.getInt(PreferencesKey.currentBalanceDisplayModeKey)!);
shouldSaveRecipientAddress = shouldSaveRecipientAddress =
@ -726,8 +746,6 @@ abstract class SettingsStoreBase with Store {
numberOfFailedTokenTrials = numberOfFailedTokenTrials =
sharedPreferences.getInt(PreferencesKey.failedTotpTokenTrials) ?? numberOfFailedTokenTrials; sharedPreferences.getInt(PreferencesKey.failedTotpTokenTrials) ?? numberOfFailedTokenTrials;
sharedPreferences.getBool(PreferencesKey.shouldSaveRecipientAddressKey) ??
shouldSaveRecipientAddress;
isAppSecure = sharedPreferences.getBool(PreferencesKey.isAppSecureKey) ?? isAppSecure; isAppSecure = sharedPreferences.getBool(PreferencesKey.isAppSecureKey) ?? isAppSecure;
disableBuy = sharedPreferences.getBool(PreferencesKey.disableBuyKey) ?? disableBuy; disableBuy = sharedPreferences.getBool(PreferencesKey.disableBuyKey) ?? disableBuy;
disableSell = sharedPreferences.getBool(PreferencesKey.disableSellKey) ?? disableSell; disableSell = sharedPreferences.getBool(PreferencesKey.disableSellKey) ?? disableSell;
@ -856,7 +874,6 @@ abstract class SettingsStoreBase with Store {
if (Platform.isAndroid) { if (Platform.isAndroid) {
final androidInfo = await deviceInfoPlugin.androidInfo; final androidInfo = await deviceInfoPlugin.androidInfo;
deviceName = '${androidInfo.brand}%20${androidInfo.manufacturer}%20${androidInfo.model}'; deviceName = '${androidInfo.brand}%20${androidInfo.manufacturer}%20${androidInfo.model}';
print(deviceName);
} else if (Platform.isIOS) { } else if (Platform.isIOS) {
final iosInfo = await deviceInfoPlugin.iosInfo; final iosInfo = await deviceInfoPlugin.iosInfo;
deviceName = iosInfo.model; deviceName = iosInfo.model;

View file

@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
import 'package:cake_wallet/entities/contact_base.dart'; import 'package:cake_wallet/entities/contact_base.dart';
import 'package:cake_wallet/entities/wallet_contact.dart'; import 'package:cake_wallet/entities/wallet_contact.dart';
import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/store/settings_store.dart';
@ -10,6 +11,7 @@ import 'package:cake_wallet/entities/contact_record.dart';
import 'package:cake_wallet/entities/contact.dart'; import 'package:cake_wallet/entities/contact.dart';
import 'package:cake_wallet/utils/mobx.dart'; import 'package:cake_wallet/utils/mobx.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:collection/collection.dart';
part 'contact_list_view_model.g.dart'; part 'contact_list_view_model.g.dart';
@ -20,12 +22,26 @@ abstract class ContactListViewModelBase with Store {
ContactListViewModelBase(this.contactSource, this.walletInfoSource, ContactListViewModelBase(this.contactSource, this.walletInfoSource,
this._currency, this.settingsStore) this._currency, this.settingsStore)
: contacts = ObservableList<ContactRecord>(), : contacts = ObservableList<ContactRecord>(),
walletContacts = [] { walletContacts = [],
isAutoGenerateEnabled =
settingsStore.autoGenerateSubaddressStatus == AutoGenerateSubaddressStatus.enabled {
walletInfoSource.values.forEach((info) { walletInfoSource.values.forEach((info) {
if (info.addresses?.isNotEmpty ?? false) { if (isAutoGenerateEnabled && info.type == WalletType.monero && info.addressInfos != null) {
info.addresses?.forEach((address, label) { info.addressInfos!.forEach((key, value) {
final name = label.isNotEmpty ? info.name + ' ($label)' : info.name; final nextUnusedAddress = value.firstWhereOrNull(
(addressInfo) => !(info.usedAddresses?.contains(addressInfo.address) ?? false));
if (nextUnusedAddress != null) {
final name = _createName(info.name, nextUnusedAddress.label);
walletContacts.add(WalletContact(
nextUnusedAddress.address,
name,
walletTypeToCryptoCurrency(info.type),
));
}
});
} else if (info.addresses?.isNotEmpty == true) {
info.addresses!.forEach((address, label) {
final name = _createName(info.name, label);
walletContacts.add(WalletContact( walletContacts.add(WalletContact(
address, address,
name, name,
@ -40,6 +56,11 @@ abstract class ContactListViewModelBase with Store {
initialFire: true); initialFire: true);
} }
String _createName(String walletName, String label) {
return label.isNotEmpty ? '$walletName ($label)' : walletName;
}
final bool isAutoGenerateEnabled;
final Box<Contact> contactSource; final Box<Contact> contactSource;
final Box<WalletInfo> walletInfoSource; final Box<WalletInfo> walletInfoSource;
final ObservableList<ContactRecord> contacts; final ObservableList<ContactRecord> contacts;

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
import 'package:cake_wallet/entities/exchange_api_mode.dart'; import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart'; import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart';
import 'package:cake_wallet/view_model/dashboard/anonpay_transaction_list_item.dart'; import 'package:cake_wallet/view_model/dashboard/anonpay_transaction_list_item.dart';
@ -235,6 +236,10 @@ abstract class DashboardViewModelBase with Store {
@computed @computed
double get price => balanceViewModel.price; double get price => balanceViewModel.price;
@computed
bool get isAutoGenerateSubaddressesEnabled =>
settingsStore.autoGenerateSubaddressStatus != AutoGenerateSubaddressStatus.disabled;
@computed @computed
List<ActionListItem> get items { List<ActionListItem> get items {
final _items = <ActionListItem>[]; final _items = <ActionListItem>[];

View file

@ -76,6 +76,7 @@ abstract class NodeListViewModelBase with Store {
@action @action
Future<void> delete(Node node) async => node.delete(); Future<void> delete(Node node) async => node.delete();
@action
Future<void> setAsCurrent(Node node) async => settingsStore.nodes[_appStore.wallet!.type] = node; Future<void> setAsCurrent(Node node) async => settingsStore.nodes[_appStore.wallet!.type] = node;
@action @action

View file

@ -1,6 +1,10 @@
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
import 'package:cake_wallet/entities/exchange_api_mode.dart'; import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/ethereum/ethereum.dart'; import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/store/settings_store.dart';
import 'package:cw_core/balance.dart';
import 'package:cw_core/transaction_history.dart';
import 'package:cw_core/transaction_info.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
@ -14,11 +18,27 @@ abstract class PrivacySettingsViewModelBase with Store {
PrivacySettingsViewModelBase(this._settingsStore, this._wallet); PrivacySettingsViewModelBase(this._settingsStore, this._wallet);
final SettingsStore _settingsStore; final SettingsStore _settingsStore;
final WalletBase _wallet; final WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> _wallet;
@computed @computed
ExchangeApiMode get exchangeStatus => _settingsStore.exchangeStatus; ExchangeApiMode get exchangeStatus => _settingsStore.exchangeStatus;
@computed
bool get isAutoGenerateSubaddressesEnabled =>
_settingsStore.autoGenerateSubaddressStatus != AutoGenerateSubaddressStatus.disabled;
@action
void setAutoGenerateSubaddresses(bool value) {
_wallet.isEnabledAutoGenerateSubaddress = value;
if (value) {
_settingsStore.autoGenerateSubaddressStatus = AutoGenerateSubaddressStatus.enabled;
} else {
_settingsStore.autoGenerateSubaddressStatus = AutoGenerateSubaddressStatus.disabled;
}
}
bool get isAutoGenerateSubaddressesVisible => _wallet.type == WalletType.monero;
@computed @computed
bool get shouldSaveRecipientAddress => _settingsStore.shouldSaveRecipientAddress; bool get shouldSaveRecipientAddress => _settingsStore.shouldSaveRecipientAddress;

View file

@ -3,11 +3,9 @@ import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/entities/unspent_transaction_output.dart'; import 'package:cake_wallet/entities/unspent_transaction_output.dart';
import 'package:cake_wallet/monero/monero.dart'; import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_item.dart'; import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_item.dart';
import 'package:cw_bitcoin/bitcoin_wallet.dart';
import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_core/unspent_coins_info.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:cw_monero/monero_wallet.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';

View file

@ -57,11 +57,11 @@ DEPENDENCIES:
- FlutterMacOS (from `Flutter/ephemeral`) - FlutterMacOS (from `Flutter/ephemeral`)
- in_app_review (from `Flutter/ephemeral/.symlinks/plugins/in_app_review/macos`) - in_app_review (from `Flutter/ephemeral/.symlinks/plugins/in_app_review/macos`)
- package_info (from `Flutter/ephemeral/.symlinks/plugins/package_info/macos`) - package_info (from `Flutter/ephemeral/.symlinks/plugins/package_info/macos`)
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/macos`) - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
- platform_device_id (from `Flutter/ephemeral/.symlinks/plugins/platform_device_id/macos`) - platform_device_id (from `Flutter/ephemeral/.symlinks/plugins/platform_device_id/macos`)
- platform_device_id_macos (from `Flutter/ephemeral/.symlinks/plugins/platform_device_id_macos/macos`) - platform_device_id_macos (from `Flutter/ephemeral/.symlinks/plugins/platform_device_id_macos/macos`)
- share_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/share_plus_macos/macos`) - share_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/share_plus_macos/macos`)
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/macos`) - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
- wakelock_macos (from `Flutter/ephemeral/.symlinks/plugins/wakelock_macos/macos`) - wakelock_macos (from `Flutter/ephemeral/.symlinks/plugins/wakelock_macos/macos`)
@ -87,7 +87,7 @@ EXTERNAL SOURCES:
package_info: package_info:
:path: Flutter/ephemeral/.symlinks/plugins/package_info/macos :path: Flutter/ephemeral/.symlinks/plugins/package_info/macos
path_provider_foundation: path_provider_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/macos :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
platform_device_id: platform_device_id:
:path: Flutter/ephemeral/.symlinks/plugins/platform_device_id/macos :path: Flutter/ephemeral/.symlinks/plugins/platform_device_id/macos
platform_device_id_macos: platform_device_id_macos:
@ -95,7 +95,7 @@ EXTERNAL SOURCES:
share_plus_macos: share_plus_macos:
:path: Flutter/ephemeral/.symlinks/plugins/share_plus_macos/macos :path: Flutter/ephemeral/.symlinks/plugins/share_plus_macos/macos
shared_preferences_foundation: shared_preferences_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/macos :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
url_launcher_macos: url_launcher_macos:
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
wakelock_macos: wakelock_macos:

View file

@ -1,8 +1,8 @@
#!/bin/sh #!/bin/sh
cd cw_core && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. cd cw_core; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
cd cw_monero && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. cd cw_monero; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
cd cw_bitcoin && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. cd cw_bitcoin; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
cd cw_haven && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. cd cw_haven; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
cd cw_ethereum && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. cd cw_ethereum; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
flutter packages pub run build_runner build --delete-conflicting-outputs dart run build_runner build --delete-conflicting-outputs

View file

@ -683,6 +683,8 @@
"support_description_other_links": "انضم إلى مجتمعاتنا أو تصل إلينا شركائنا من خلال أساليب أخرى", "support_description_other_links": "انضم إلى مجتمعاتنا أو تصل إلينا شركائنا من خلال أساليب أخرى",
"select_destination": ".ﻲﻃﺎﻴﺘﺣﻻﺍ ﺦﺴﻨﻟﺍ ﻒﻠﻣ ﺔﻬﺟﻭ ﺪﻳﺪﺤﺗ ءﺎﺟﺮﻟﺍ", "select_destination": ".ﻲﻃﺎﻴﺘﺣﻻﺍ ﺦﺴﻨﻟﺍ ﻒﻠﻣ ﺔﻬﺟﻭ ﺪﻳﺪﺤﺗ ءﺎﺟﺮﻟﺍ",
"save_to_downloads": "ﺕﻼﻳﺰﻨﺘﻟﺍ ﻲﻓ ﻆﻔﺣ", "save_to_downloads": "ﺕﻼﻳﺰﻨﺘﻟﺍ ﻲﻓ ﻆﻔﺣ",
"support_description_other_links": "انضم إلى مجتمعاتنا أو تصل إلينا شركائنا من خلال أساليب أخرى",
"auto_generate_subaddresses": "تلقائي توليد subddresses",
"invalid_password": "رمز مرور خاطئ", "invalid_password": "رمز مرور خاطئ",
"unlock": "الغاء القفل", "unlock": "الغاء القفل",
"enter_wallet_password": "أدخل كلمة مرور المحفظة", "enter_wallet_password": "أدخل كلمة مرور المحفظة",

View file

@ -626,6 +626,7 @@
"setup_totp_recommended": "Настройка на TOTP (препоръчително)", "setup_totp_recommended": "Настройка на TOTP (препоръчително)",
"disable_buy": "Деактивирайте действието за покупка", "disable_buy": "Деактивирайте действието за покупка",
"disable_sell": "Деактивирайте действието за продажба", "disable_sell": "Деактивирайте действието за продажба",
"auto_generate_subaddresses": "Автоматично генериране на подадреси",
"cake_2fa_preset": "Торта 2FA Preset", "cake_2fa_preset": "Торта 2FA Preset",
"narrow": "Тесен", "narrow": "Тесен",
"normal": "нормално", "normal": "нормално",

View file

@ -626,6 +626,7 @@
"setup_totp_recommended": "Nastavit TOTP (doporučeno)", "setup_totp_recommended": "Nastavit TOTP (doporučeno)",
"disable_buy": "Zakázat akci nákupu", "disable_buy": "Zakázat akci nákupu",
"disable_sell": "Zakázat akci prodeje", "disable_sell": "Zakázat akci prodeje",
"auto_generate_subaddresses": "Automaticky generovat podadresy",
"cake_2fa_preset": "Předvolba Cake 2FA", "cake_2fa_preset": "Předvolba Cake 2FA",
"narrow": "Úzký", "narrow": "Úzký",
"normal": "Normální", "normal": "Normální",

View file

@ -640,6 +640,7 @@
"high_contrast_theme": "Kontrastreiches Thema", "high_contrast_theme": "Kontrastreiches Thema",
"matrix_green_dark_theme": "Matrix Green Dark Theme", "matrix_green_dark_theme": "Matrix Green Dark Theme",
"monero_light_theme": "Monero Light-Thema", "monero_light_theme": "Monero Light-Thema",
"auto_generate_subaddresses": "Unteradressen automatisch generieren",
"cake_2fa_preset": "Cake 2FA-Voreinstellung", "cake_2fa_preset": "Cake 2FA-Voreinstellung",
"narrow": "Eng", "narrow": "Eng",
"normal": "Normal", "normal": "Normal",
@ -693,4 +694,4 @@
"repeat_wallet_password": "Wiederholen Sie das Brieftaschenkennwort", "repeat_wallet_password": "Wiederholen Sie das Brieftaschenkennwort",
"wallet_password_is_empty": "Brieftaschenkennwort ist leer. Brieftaschenkennwort sollte nicht leer sein", "wallet_password_is_empty": "Brieftaschenkennwort ist leer. Brieftaschenkennwort sollte nicht leer sein",
"repeated_password_is_incorrect": "Wiederholtes Passwort ist falsch. Bitte wiederholen Sie das Brieftaschenkennwort erneut." "repeated_password_is_incorrect": "Wiederholtes Passwort ist falsch. Bitte wiederholen Sie das Brieftaschenkennwort erneut."
} }

View file

@ -568,6 +568,7 @@
"privacy": "Privacy", "privacy": "Privacy",
"display_settings": "Display settings", "display_settings": "Display settings",
"other_settings": "Other settings", "other_settings": "Other settings",
"auto_generate_subaddresses": "Auto generate subaddresses",
"require_pin_after": "Require PIN after", "require_pin_after": "Require PIN after",
"always": "Always", "always": "Always",
"minutes_to_pin_code": "${minute} minutes", "minutes_to_pin_code": "${minute} minutes",

View file

@ -640,6 +640,7 @@
"high_contrast_theme": "Tema de alto contraste", "high_contrast_theme": "Tema de alto contraste",
"matrix_green_dark_theme": "Matrix verde oscuro tema", "matrix_green_dark_theme": "Matrix verde oscuro tema",
"monero_light_theme": "Tema ligero de Monero", "monero_light_theme": "Tema ligero de Monero",
"auto_generate_subaddresses": "Generar subdirecciones automáticamente",
"cake_2fa_preset": "Pastel 2FA preestablecido", "cake_2fa_preset": "Pastel 2FA preestablecido",
"narrow": "Angosto", "narrow": "Angosto",
"normal": "Normal", "normal": "Normal",

View file

@ -640,6 +640,7 @@
"high_contrast_theme": "Thème à contraste élevé", "high_contrast_theme": "Thème à contraste élevé",
"matrix_green_dark_theme": "Thème Matrix Green Dark", "matrix_green_dark_theme": "Thème Matrix Green Dark",
"monero_light_theme": "Thème de lumière Monero", "monero_light_theme": "Thème de lumière Monero",
"auto_generate_subaddresses": "Générer automatiquement des sous-adresses",
"cake_2fa_preset": "Gâteau 2FA prédéfini", "cake_2fa_preset": "Gâteau 2FA prédéfini",
"narrow": "Étroit", "narrow": "Étroit",
"normal": "Normal", "normal": "Normal",

View file

@ -618,6 +618,7 @@
"high_contrast_theme": "Babban Jigon Kwatance", "high_contrast_theme": "Babban Jigon Kwatance",
"matrix_green_dark_theme": "Matrix Green Dark Jigo", "matrix_green_dark_theme": "Matrix Green Dark Jigo",
"monero_light_theme": "Jigon Hasken Monero", "monero_light_theme": "Jigon Hasken Monero",
"auto_generate_subaddresses": "Saɓaƙa subaddresses ta kai tsaye",
"cake_2fa_preset": "Cake 2FA saiti", "cake_2fa_preset": "Cake 2FA saiti",
"narrow": "kunkuntar", "narrow": "kunkuntar",
"normal": "Na al'ada", "normal": "Na al'ada",

View file

@ -640,6 +640,7 @@
"high_contrast_theme": "उच्च कंट्रास्ट थीम", "high_contrast_theme": "उच्च कंट्रास्ट थीम",
"matrix_green_dark_theme": "मैट्रिक्स ग्रीन डार्क थीम", "matrix_green_dark_theme": "मैट्रिक्स ग्रीन डार्क थीम",
"monero_light_theme": "मोनेरो लाइट थीम", "monero_light_theme": "मोनेरो लाइट थीम",
"auto_generate_subaddresses": "स्वचालित रूप से उप-पते उत्पन्न करें",
"cake_2fa_preset": "केक 2एफए प्रीसेट", "cake_2fa_preset": "केक 2एफए प्रीसेट",
"narrow": "सँकरा", "narrow": "सँकरा",
"normal": "सामान्य", "normal": "सामान्य",

View file

@ -640,6 +640,7 @@
"high_contrast_theme": "Tema visokog kontrasta", "high_contrast_theme": "Tema visokog kontrasta",
"matrix_green_dark_theme": "Matrix Green Dark Theme", "matrix_green_dark_theme": "Matrix Green Dark Theme",
"monero_light_theme": "Monero lagana tema", "monero_light_theme": "Monero lagana tema",
"auto_generate_subaddresses": "Automatski generirajte podadrese",
"cake_2fa_preset": "Cake 2FA Preset", "cake_2fa_preset": "Cake 2FA Preset",
"narrow": "Usko", "narrow": "Usko",
"normal": "Normalno", "normal": "Normalno",

View file

@ -622,6 +622,7 @@
"setup_totp_recommended": "Siapkan TOTP (Disarankan)", "setup_totp_recommended": "Siapkan TOTP (Disarankan)",
"disable_buy": "Nonaktifkan tindakan beli", "disable_buy": "Nonaktifkan tindakan beli",
"disable_sell": "Nonaktifkan aksi jual", "disable_sell": "Nonaktifkan aksi jual",
"auto_generate_subaddresses": "Menghasilkan subalamat secara otomatis",
"cake_2fa_preset": "Preset Kue 2FA", "cake_2fa_preset": "Preset Kue 2FA",
"narrow": "Sempit", "narrow": "Sempit",
"normal": "Normal", "normal": "Normal",

View file

@ -634,6 +634,7 @@
"setup_totp_recommended": "Imposta TOTP (consigliato)", "setup_totp_recommended": "Imposta TOTP (consigliato)",
"disable_buy": "Disabilita l'azione di acquisto", "disable_buy": "Disabilita l'azione di acquisto",
"disable_sell": "Disabilita l'azione di vendita", "disable_sell": "Disabilita l'azione di vendita",
"auto_generate_subaddresses": "Genera automaticamente sottindirizzi",
"cake_2fa_preset": "Torta 2FA Preset", "cake_2fa_preset": "Torta 2FA Preset",
"narrow": "Stretto", "narrow": "Stretto",
"normal": "Normale", "normal": "Normale",

View file

@ -687,10 +687,11 @@
"support_description_other_links": "私たちのコミュニティに参加するか、他の方法を通して私たちのパートナーに連絡してください", "support_description_other_links": "私たちのコミュニティに参加するか、他の方法を通して私たちのパートナーに連絡してください",
"select_destination": "バックアップファイルの保存先を選択してください。", "select_destination": "バックアップファイルの保存先を選択してください。",
"save_to_downloads": "ダウンロードに保存", "save_to_downloads": "ダウンロードに保存",
"auto_generate_subaddresses": "Autoはサブアドレスを生成します",
"invalid_password": "無効なパスワード", "invalid_password": "無効なパスワード",
"unlock": "ロックを解除します", "unlock": "ロックを解除します",
"enter_wallet_password": "ウォレットパスワードを入力します", "enter_wallet_password": "ウォレットパスワードを入力します",
"repeat_wallet_password": "ウォレットパスワードを繰り返します", "repeat_wallet_password": "ウォレットパスワードを繰り返します",
"wallet_password_is_empty": "ウォレットパスワードは空です。ウォレットのパスワードは空にしてはいけません", "wallet_password_is_empty": "ウォレットパスワードは空です。ウォレットのパスワードは空にしてはいけません",
"repeated_password_is_incorrect": "繰り返しパスワードが正しくありません。ウォレットのパスワードをもう一度繰り返してください。" "repeated_password_is_incorrect": "繰り返しパスワードが正しくありません。ウォレットのパスワードをもう一度繰り返してください。"
} }

View file

@ -687,10 +687,11 @@
"support_description_other_links": "다른 방법을 통해 커뮤니티에 가입하거나 파트너에게 연락하십시오.", "support_description_other_links": "다른 방법을 통해 커뮤니티에 가입하거나 파트너에게 연락하십시오.",
"select_destination": "백업 파일의 대상을 선택하십시오.", "select_destination": "백업 파일의 대상을 선택하십시오.",
"save_to_downloads": "다운로드에 저장", "save_to_downloads": "다운로드에 저장",
"auto_generate_subaddresses": "자동 생성 서브 아드 드레스",
"invalid_password": "유효하지 않은 비밀번호", "invalid_password": "유효하지 않은 비밀번호",
"unlock": "터놓다", "unlock": "터놓다",
"enter_wallet_password": "지갑 암호를 입력하십시오", "enter_wallet_password": "지갑 암호를 입력하십시오",
"repeat_wallet_password": "지갑 암호를 반복하십시오", "repeat_wallet_password": "지갑 암호를 반복하십시오",
"wallet_password_is_empty": "지갑 암호는 비어 있습니다. 지갑 암호는 비어 있지 않아야합니다", "wallet_password_is_empty": "지갑 암호는 비어 있습니다. 지갑 암호는 비어 있지 않아야합니다",
"repeated_password_is_incorrect": "반복 된 비밀번호가 올바르지 않습니다. 지갑 암호를 다시 반복하십시오." "repeated_password_is_incorrect": "반복 된 비밀번호가 올바르지 않습니다. 지갑 암호를 다시 반복하십시오."
} }

View file

@ -685,10 +685,11 @@
"support_description_other_links": "ကျွန်ုပ်တို့၏လူမှုအသိုင်းအဝိုင်းများသို့ 0 င်ရောက်ပါ", "support_description_other_links": "ကျွန်ုပ်တို့၏လူမှုအသိုင်းအဝိုင်းများသို့ 0 င်ရောက်ပါ",
"select_destination": "အရန်ဖိုင်အတွက် ဦးတည်ရာကို ရွေးပါ။", "select_destination": "အရန်ဖိုင်အတွက် ဦးတည်ရာကို ရွေးပါ။",
"save_to_downloads": "ဒေါင်းလုဒ်များထံ သိမ်းဆည်းပါ။", "save_to_downloads": "ဒေါင်းလုဒ်များထံ သိမ်းဆည်းပါ။",
"auto_generate_subaddresses": "အော်တို Generate Subaddresses",
"invalid_password": "မမှန်ကန်သောစကားဝှက်", "invalid_password": "မမှန်ကန်သောစကားဝှက်",
"unlock": "သော့ဖွင့်", "unlock": "သော့ဖွင့်",
"enter_wallet_password": "ပိုက်ဆံအိတ်စကားဝှက်ကိုရိုက်ထည့်ပါ", "enter_wallet_password": "ပိုက်ဆံအိတ်စကားဝှက်ကိုရိုက်ထည့်ပါ",
"repeat_wallet_password": "ပိုက်ဆံအိတ်စကားဝှက်ကိုပြန်လုပ်ပါ", "repeat_wallet_password": "ပိုက်ဆံအိတ်စကားဝှက်ကိုပြန်လုပ်ပါ",
"wallet_password_is_empty": "ပိုက်ဆံအိတ်စကားဝှက်သည်ဗလာဖြစ်သည်။ ပိုက်ဆံအိတ်စကားဝှက်သည်အချည်းနှီးဖြစ်သင့်သည်", "wallet_password_is_empty": "ပိုက်ဆံအိတ်စကားဝှက်သည်ဗလာဖြစ်သည်။ ပိုက်ဆံအိတ်စကားဝှက်သည်အချည်းနှီးဖြစ်သင့်သည်",
"repeated_password_is_incorrect": "ထပ်ခါတလဲလဲစကားဝှက်မမှန်ကန်ပါ ကျေးဇူးပြုပြီးပိုက်ဆံအိတ်စကားဝှက်ကိုပြန်လုပ်ပါ။" "repeated_password_is_incorrect": "ထပ်ခါတလဲလဲစကားဝှက်မမှန်ကန်ပါ ကျေးဇူးပြုပြီးပိုက်ဆံအိတ်စကားဝှက်ကိုပြန်လုပ်ပါ။"
} }

View file

@ -634,6 +634,7 @@
"setup_totp_recommended": "TOTP instellen (aanbevolen)", "setup_totp_recommended": "TOTP instellen (aanbevolen)",
"disable_buy": "Koopactie uitschakelen", "disable_buy": "Koopactie uitschakelen",
"disable_sell": "Verkoopactie uitschakelen", "disable_sell": "Verkoopactie uitschakelen",
"auto_generate_subaddresses": "Automatisch subadressen genereren",
"cake_2fa_preset": "Taart 2FA Voorinstelling", "cake_2fa_preset": "Taart 2FA Voorinstelling",
"narrow": "Smal", "narrow": "Smal",
"normal": "Normaal", "normal": "Normaal",

View file

@ -634,6 +634,7 @@
"setup_totp_recommended": "Skonfiguruj TOTP (zalecane)", "setup_totp_recommended": "Skonfiguruj TOTP (zalecane)",
"disable_buy": "Wyłącz akcję kupna", "disable_buy": "Wyłącz akcję kupna",
"disable_sell": "Wyłącz akcję sprzedaży", "disable_sell": "Wyłącz akcję sprzedaży",
"auto_generate_subaddresses": "Automatycznie generuj podadresy",
"cake_2fa_preset": "Ciasto 2FA Preset", "cake_2fa_preset": "Ciasto 2FA Preset",
"narrow": "Wąski", "narrow": "Wąski",
"normal": "Normalna", "normal": "Normalna",

View file

@ -633,6 +633,7 @@
"setup_totp_recommended": "Configurar TOTP (recomendado)", "setup_totp_recommended": "Configurar TOTP (recomendado)",
"disable_buy": "Desativar ação de compra", "disable_buy": "Desativar ação de compra",
"disable_sell": "Desativar ação de venda", "disable_sell": "Desativar ação de venda",
"auto_generate_subaddresses": "Gerar subendereços automaticamente",
"cake_2fa_preset": "Predefinição de bolo 2FA", "cake_2fa_preset": "Predefinição de bolo 2FA",
"narrow": "Estreito", "narrow": "Estreito",
"normal": "Normal", "normal": "Normal",

View file

@ -687,10 +687,11 @@
"support_description_other_links": "Присоединяйтесь к нашим сообществам или охватите нас наших партнеров с помощью других методов", "support_description_other_links": "Присоединяйтесь к нашим сообществам или охватите нас наших партнеров с помощью других методов",
"select_destination": "Пожалуйста, выберите место для файла резервной копии.", "select_destination": "Пожалуйста, выберите место для файла резервной копии.",
"save_to_downloads": "Сохранить в загрузках", "save_to_downloads": "Сохранить в загрузках",
"auto_generate_subaddresses": "Авто генерируйте Subaddresses",
"invalid_password": "Неверный пароль", "invalid_password": "Неверный пароль",
"unlock": "Разблокировать", "unlock": "Разблокировать",
"enter_wallet_password": "Введите пароль кошелька", "enter_wallet_password": "Введите пароль кошелька",
"repeat_wallet_password": "Повторите пароль кошелька", "repeat_wallet_password": "Повторите пароль кошелька",
"wallet_password_is_empty": "Пароль кошелька пуст. Пароль кошелька не должен быть пустым", "wallet_password_is_empty": "Пароль кошелька пуст. Пароль кошелька не должен быть пустым",
"repeated_password_is_incorrect": "Повторный пароль неверен. Пожалуйста, повторите пароль кошелька снова." "repeated_password_is_incorrect": "Повторный пароль неверен. Пожалуйста, повторите пароль кошелька снова."
} }

View file

@ -685,10 +685,11 @@
"support_description_other_links": "เข้าร่วมชุมชนของเราหรือเข้าถึงเราพันธมิตรของเราผ่านวิธีการอื่น ๆ", "support_description_other_links": "เข้าร่วมชุมชนของเราหรือเข้าถึงเราพันธมิตรของเราผ่านวิธีการอื่น ๆ",
"select_destination": "โปรดเลือกปลายทางสำหรับไฟล์สำรอง", "select_destination": "โปรดเลือกปลายทางสำหรับไฟล์สำรอง",
"save_to_downloads": "บันทึกลงดาวน์โหลด", "save_to_downloads": "บันทึกลงดาวน์โหลด",
"auto_generate_subaddresses": "Auto สร้าง subaddresses",
"invalid_password": "รหัสผ่านไม่ถูกต้อง", "invalid_password": "รหัสผ่านไม่ถูกต้อง",
"unlock": "ปลดล็อค", "unlock": "ปลดล็อค",
"enter_wallet_password": "ป้อนรหัสผ่านกระเป๋าเงิน", "enter_wallet_password": "ป้อนรหัสผ่านกระเป๋าเงิน",
"repeat_wallet_password": "ทำซ้ำรหัสผ่านกระเป๋าเงิน", "repeat_wallet_password": "ทำซ้ำรหัสผ่านกระเป๋าเงิน",
"wallet_password_is_empty": "รหัสผ่านกระเป๋าเงินว่างเปล่า รหัสผ่านกระเป๋าเงินไม่ควรว่างเปล่า", "wallet_password_is_empty": "รหัสผ่านกระเป๋าเงินว่างเปล่า รหัสผ่านกระเป๋าเงินไม่ควรว่างเปล่า",
"repeated_password_is_incorrect": "รหัสผ่านซ้ำไม่ถูกต้อง โปรดทำซ้ำรหัสผ่านกระเป๋าเงินอีกครั้ง" "repeated_password_is_incorrect": "รหัสผ่านซ้ำไม่ถูกต้อง โปรดทำซ้ำรหัสผ่านกระเป๋าเงินอีกครั้ง"
} }

View file

@ -632,6 +632,7 @@
"setup_totp_recommended": "TOTP'yi kurun (Önerilir)", "setup_totp_recommended": "TOTP'yi kurun (Önerilir)",
"disable_buy": "Satın alma işlemini devre dışı bırak", "disable_buy": "Satın alma işlemini devre dışı bırak",
"disable_sell": "Satış işlemini devre dışı bırak", "disable_sell": "Satış işlemini devre dışı bırak",
"auto_generate_subaddresses": "Alt adresleri otomatik olarak oluştur",
"cake_2fa_preset": "Kek 2FA Ön Ayarı", "cake_2fa_preset": "Kek 2FA Ön Ayarı",
"narrow": "Dar", "narrow": "Dar",
"normal": "Normal", "normal": "Normal",

View file

@ -634,6 +634,7 @@
"setup_totp_recommended": "Налаштувати TOTP (рекомендовано)", "setup_totp_recommended": "Налаштувати TOTP (рекомендовано)",
"disable_buy": "Вимкнути дію покупки", "disable_buy": "Вимкнути дію покупки",
"disable_sell": "Вимкнути дію продажу", "disable_sell": "Вимкнути дію продажу",
"auto_generate_subaddresses": "Автоматично генерувати підадреси",
"cake_2fa_preset": "Торт 2FA Preset", "cake_2fa_preset": "Торт 2FA Preset",
"narrow": "вузькі", "narrow": "вузькі",
"normal": "нормальний", "normal": "нормальний",

View file

@ -679,10 +679,11 @@
"support_description_other_links": "ہماری برادریوں میں شامل ہوں یا دوسرے طریقوں سے ہمارے شراکت داروں تک پہنچیں", "support_description_other_links": "ہماری برادریوں میں شامل ہوں یا دوسرے طریقوں سے ہمارے شراکت داروں تک پہنچیں",
"select_destination": "۔ﮟﯾﺮﮐ ﺏﺎﺨﺘﻧﺍ ﺎﮐ ﻝﺰﻨﻣ ﮯﯿﻟ ﮯﮐ ﻞﺋﺎﻓ ﭖﺍ ﮏﯿﺑ ﻡﺮﮐ ﮦﺍﺮﺑ", "select_destination": "۔ﮟﯾﺮﮐ ﺏﺎﺨﺘﻧﺍ ﺎﮐ ﻝﺰﻨﻣ ﮯﯿﻟ ﮯﮐ ﻞﺋﺎﻓ ﭖﺍ ﮏﯿﺑ ﻡﺮﮐ ﮦﺍﺮﺑ",
"save_to_downloads": "۔ﮟﯾﺮﮐ ﻅﻮﻔﺤﻣ ﮟﯿﻣ ﺯﮈﻮﻟ ﻥﺅﺍﮈ", "save_to_downloads": "۔ﮟﯾﺮﮐ ﻅﻮﻔﺤﻣ ﮟﯿﻣ ﺯﮈﻮﻟ ﻥﺅﺍﮈ",
"auto_generate_subaddresses": "آٹو سب ایڈریس تیار کرتا ہے",
"invalid_password": "غلط پاسورڈ", "invalid_password": "غلط پاسورڈ",
"unlock": "غیر مقفل", "unlock": "غیر مقفل",
"enter_wallet_password": "پرس کا پاس ورڈ درج کریں", "enter_wallet_password": "پرس کا پاس ورڈ درج کریں",
"repeat_wallet_password": "بٹوے کا پاس ورڈ دہرائیں", "repeat_wallet_password": "بٹوے کا پاس ورڈ دہرائیں",
"wallet_password_is_empty": "پرس کا پاس ورڈ خالی ہے۔ پرس کا پاس ورڈ خالی نہیں ہونا چاہئے", "wallet_password_is_empty": "پرس کا پاس ورڈ خالی ہے۔ پرس کا پاس ورڈ خالی نہیں ہونا چاہئے",
"repeated_password_is_incorrect": "بار بار پاس ورڈ غلط ہے۔ براہ کرم دوبارہ پرس کا پاس ورڈ دہرائیں۔" "repeated_password_is_incorrect": "بار بار پاس ورڈ غلط ہے۔ براہ کرم دوبارہ پرس کا پاس ورڈ دہرائیں۔"
} }

View file

@ -681,10 +681,11 @@
"monero_light_theme": "Monero Light Akori", "monero_light_theme": "Monero Light Akori",
"select_destination": "Jọwọ yan ibi ti o nlo fun faili afẹyinti.", "select_destination": "Jọwọ yan ibi ti o nlo fun faili afẹyinti.",
"save_to_downloads": "Fipamọ si Awọn igbasilẹ", "save_to_downloads": "Fipamọ si Awọn igbasilẹ",
"auto_generate_subaddresses": "Aṣiṣe Ibi-Afọwọkọ",
"invalid_password": "Ọrọ igbaniwọle ti ko wulo", "invalid_password": "Ọrọ igbaniwọle ti ko wulo",
"unlock": "Sisalẹ", "unlock": "Sisalẹ",
"enter_wallet_password": "Tẹ ọrọ igbaniwọle apamọwọ", "enter_wallet_password": "Tẹ ọrọ igbaniwọle apamọwọ",
"repeat_wallet_password": "Tun ọrọ igbaniwọle apamọwọ naa", "repeat_wallet_password": "Tun ọrọ igbaniwọle apamọwọ naa",
"wallet_password_is_empty": "Ọrọ igbaniwọle apamọwọ ti ṣofo. Ọrọ igbaniwọle apamọwọ ko yẹ ki o ṣofo", "wallet_password_is_empty": "Ọrọ igbaniwọle apamọwọ ti ṣofo. Ọrọ igbaniwọle apamọwọ ko yẹ ki o ṣofo",
"repeated_password_is_incorrect": "Ọrọ igbaniwọle tun jẹ aṣiṣe. Jọwọ tun ọrọigbaniwọle apamọwọ lẹẹkansi." "repeated_password_is_incorrect": "Ọrọ igbaniwọle tun jẹ aṣiṣe. Jọwọ tun ọrọigbaniwọle apamọwọ lẹẹkansi."
} }

View file

@ -686,10 +686,11 @@
"monero_light_theme": "门罗币浅色主题", "monero_light_theme": "门罗币浅色主题",
"select_destination": "请选择备份文件的目的地。", "select_destination": "请选择备份文件的目的地。",
"save_to_downloads": "保存到下载", "save_to_downloads": "保存到下载",
"auto_generate_subaddresses": "自动生成子辅助",
"invalid_password": "无效的密码", "invalid_password": "无效的密码",
"unlock": "开锁", "unlock": "开锁",
"enter_wallet_password": "输入钱包密码", "enter_wallet_password": "输入钱包密码",
"repeat_wallet_password": "重复钱包密码", "repeat_wallet_password": "重复钱包密码",
"wallet_password_is_empty": "钱包密码为空。钱包密码不应为空", "wallet_password_is_empty": "钱包密码为空。钱包密码不应为空",
"repeated_password_is_incorrect": "重复密码不正确。请再次重复钱包密码。" "repeated_password_is_incorrect": "重复密码不正确。请再次重复钱包密码。"
} }

View file

@ -14,14 +14,14 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
APP_ANDROID_TYPE=$1 APP_ANDROID_TYPE=$1
MONERO_COM_NAME="Monero.com" MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.5.1" MONERO_COM_VERSION="1.6.0"
MONERO_COM_BUILD_NUMBER=55 MONERO_COM_BUILD_NUMBER=56
MONERO_COM_BUNDLE_ID="com.monero.app" MONERO_COM_BUNDLE_ID="com.monero.app"
MONERO_COM_PACKAGE="com.monero.app" MONERO_COM_PACKAGE="com.monero.app"
CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.8.1" CAKEWALLET_VERSION="4.9.0"
CAKEWALLET_BUILD_NUMBER=168 CAKEWALLET_BUILD_NUMBER=169
CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet" CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet" CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"

View file

@ -5,8 +5,8 @@ HAVEN_VERSION=tags/v3.0.7
HAVEN_SRC_DIR=${WORKDIR}/haven HAVEN_SRC_DIR=${WORKDIR}/haven
git clone https://github.com/haven-protocol-org/haven-main.git ${HAVEN_SRC_DIR} git clone https://github.com/haven-protocol-org/haven-main.git ${HAVEN_SRC_DIR}
git checkout ${HAVEN_VERSION}
cd $HAVEN_SRC_DIR cd $HAVEN_SRC_DIR
git checkout ${HAVEN_VERSION}
git submodule init git submodule init
git submodule update git submodule update

View file

@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
APP_IOS_TYPE=$1 APP_IOS_TYPE=$1
MONERO_COM_NAME="Monero.com" MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.5.1" MONERO_COM_VERSION="1.6.0"
MONERO_COM_BUILD_NUMBER=53 MONERO_COM_BUILD_NUMBER=54
MONERO_COM_BUNDLE_ID="com.cakewallet.monero" MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.8.1" CAKEWALLET_VERSION="4.9.0"
CAKEWALLET_BUILD_NUMBER=176 CAKEWALLET_BUILD_NUMBER=178
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
HAVEN_NAME="Haven" HAVEN_NAME="Haven"

View file

@ -14,8 +14,8 @@ if [ -n "$1" ]; then
fi fi
CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="1.0.2" CAKEWALLET_VERSION="1.1.0"
CAKEWALLET_BUILD_NUMBER=3 CAKEWALLET_BUILD_NUMBER=4
if ! [[ " ${TYPES[*]} " =~ " ${APP_LINUX_TYPE} " ]]; then if ! [[ " ${TYPES[*]} " =~ " ${APP_LINUX_TYPE} " ]]; then
echo "Wrong app type." echo "Wrong app type."

View file

@ -15,8 +15,8 @@ if [ -n "$1" ]; then
fi fi
CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="1.1.1" CAKEWALLET_VERSION="1.2.0"
CAKEWALLET_BUILD_NUMBER=30 CAKEWALLET_BUILD_NUMBER=31
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then

View file

@ -1,15 +1,6 @@
import 'dart:convert'; import 'utils/translation/arb_file_utils.dart';
import 'dart:io'; import 'utils/translation/translation_constants.dart';
import 'utils/translation/translation_utils.dart';
import 'package:translator/translator.dart';
const defaultLang = "en";
const langs = [
"ar", "bg", "cs", "de", "en", "es", "fr", "ha", "hi", "hr", "id", "it",
"ja", "ko", "my", "nl", "pl", "pt", "ru", "th", "tr", "uk", "ur", "yo",
"zh-cn" // zh, but Google Translate uses zh-cn for Chinese (Simplified)
];
final translator = GoogleTranslator();
void main(List<String> args) async { void main(List<String> args) async {
if (args.length != 2) { if (args.length != 2) {
@ -23,44 +14,9 @@ void main(List<String> args) async {
print('Appending "$name": "$text"'); print('Appending "$name": "$text"');
for (var lang in langs) { for (var lang in langs) {
final fileName = getFileName(lang); final fileName = getArbFileName(lang);
final translation = await getTranslation(text, lang); final translation = await getTranslation(text, lang);
appendArbFile(fileName, name, translation); appendStringToArbFile(fileName, name, translation);
} }
} }
void appendArbFile(String fileName, String name, String text) {
final file = File(fileName);
final inputContent = file.readAsStringSync();
final arbObj = json.decode(inputContent) as Map<String, dynamic>;
if (arbObj.containsKey(name)) {
print("String $name already exists in $fileName!");
return;
}
arbObj.addAll({name: text});
final outputContent = json
.encode(arbObj)
.replaceAll('","', '",\n "')
.replaceAll('{"', '{\n "')
.replaceAll('"}', '"\n}')
.replaceAll('":"', '": "');
file.writeAsStringSync(outputContent);
}
Future<String> getTranslation(String text, String lang) async {
if (lang == defaultLang) return text;
return (await translator.translate(text, from: defaultLang, to: lang)).text;
}
String getFileName(String lang) {
final shortLang = lang
.split("-")
.first;
return "./res/values/strings_$shortLang.arb";
}

View file

@ -0,0 +1,37 @@
import 'dart:io';
import 'utils/translation/arb_file_utils.dart';
import 'utils/translation/translation_constants.dart';
import 'utils/translation/translation_utils.dart';
void main(List<String> args) async {
print('Checking Consistency of all arb-files. Default: $defaultLang');
final doFix = args.contains("--fix");
if (doFix)
print('Auto fixing enabled!\n');
else
print('Auto fixing disabled!\nRun with arg "--fix" to enable autofix\n');
final fileName = getArbFileName(defaultLang);
final file = File(fileName);
final arbObj = readArbFile(file);
for (var lang in langs) {
final fileName = getArbFileName(lang);
final missingKeys = getMissingKeysInArbFile(fileName, arbObj.keys);
if (missingKeys.isNotEmpty) {
final missingDefaults = <String, String>{};
missingKeys.forEach((key) {
print('Missing in "$lang": "$key"');
if (doFix)
missingDefaults[key] = arbObj[key] as String;
});
if (missingDefaults.isNotEmpty)
await appendTranslations(lang, missingDefaults);
}
}
}

View file

@ -0,0 +1,66 @@
import 'dart:convert';
import 'dart:io';
void appendStringToArbFile(String fileName, String name, String text) {
final file = File(fileName);
final arbObj = readArbFile(file);
if (arbObj.containsKey(name)) {
print("String $name already exists in $fileName!");
return;
}
arbObj.addAll({name: text});
final outputContent = json
.encode(arbObj)
.replaceAll('","', '",\n "')
.replaceAll('{"', '{\n "')
.replaceAll('"}', '"\n}')
.replaceAll('":"', '": "');
file.writeAsStringSync(outputContent);
}
void appendStringsToArbFile(String fileName, Map<String, String> strings) {
final file = File(fileName);
final arbObj = readArbFile(file);
arbObj.addAll(strings);
final outputContent = json
.encode(arbObj)
.replaceAll('","', '",\n "')
.replaceAll('{"', '{\n "')
.replaceAll('"}', '"\n}')
.replaceAll('":"', '": "');
file.writeAsStringSync(outputContent);
}
Map<String, dynamic> readArbFile(File file) {
final inputContent = file.readAsStringSync();
return json.decode(inputContent) as Map<String, dynamic>;
}
String getArbFileName(String lang) {
final shortLang = lang
.split("-")
.first;
return "./res/values/strings_$shortLang.arb";
}
List<String> getMissingKeysInArbFile(String fileName, Iterable<String> langKeys) {
final file = File(fileName);
final arbObj = readArbFile(file);
final results = <String>[];
for (var langKey in langKeys) {
if (!arbObj.containsKey(langKey)) {
results.add(langKey);
}
}
return results;
}

View file

@ -0,0 +1,6 @@
const defaultLang = "en";
const langs = [
"ar", "bg", "cs", "de", "en", "es", "fr", "ha", "hi", "hr", "id", "it",
"ja", "ko", "my", "nl", "pl", "pt", "ru", "th", "tr", "uk", "ur", "yo",
"zh-cn" // zh, but Google Translate uses zh-cn for Chinese (Simplified)
];

View file

@ -0,0 +1,37 @@
import 'package:translator/translator.dart';
import 'arb_file_utils.dart';
import 'translation_constants.dart';
final translator = GoogleTranslator();
Future<void> appendTranslation(String lang, String key, String text) async {
final fileName = getArbFileName(lang);
final translation = await getTranslation(text, lang);
appendStringToArbFile(fileName, key, translation);
}
Future<void> appendTranslations(String lang, Map<String, String> defaults) async {
final fileName = getArbFileName(lang);
final translations = <String, String>{};
for (var key in defaults.keys) {
final value = defaults[key]!;
if (value.contains("{")) continue;
final translation = await getTranslation(value, lang);
translations[key] = translation;
}
print(translations);
appendStringsToArbFile(fileName, translations);
}
Future<String> getTranslation(String text, String lang) async {
if (lang == defaultLang) return text;
return (await translator.translate(text, from: defaultLang, to: lang)).text;
}