Hv (#295)

* hv * Change build version

mkyq committed Mar 30, 2022 at 17:57 UTC 01150ef2a715296ab0f8a37f1d7aa4e46ff2c9fe
213 files changed +23969 -669
.gitignore
+5 -2
@@ -111,8 +111,11 @@ ios/build
111 *.sublime-project
112
113 shared_external/**
114 -cw_shared_external/**
115 -cw_haven/**
114 +cw_shared_external/ios/External/
115 +# cw_haven/**
116 +cw_haven/ios/External/
117 +cw_haven/android/.externalNativeBuild/
118 +cw_haven/android/.cxx/
119
120 lib/bitcoin/bitcoin.dart
121 lib/monero/monero.dart
android/app/src/main/java/com/cakewallet/haven/Application.java new
+11
@@ -0,0 +1,11 @@
1 +package com.cakewallet.haven;
2 +
3 +import io.flutter.app.FlutterApplication;
4 +import io.flutter.plugin.common.PluginRegistry;
5 +import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback;
6 +import io.flutter.plugins.GeneratedPluginRegistrant;
7 +
8 +public class Application extends FlutterApplication implements PluginRegistrantCallback {
9 + @Override
10 + public void registerWith(PluginRegistry registry) {}
11 +}
\ No newline at end of file
android/app/src/main/java/com/cakewallet/haven/MainActivity.java new
+90
@@ -0,0 +1,90 @@
1 +package com.cakewallet.haven;
2 +
3 +import androidx.annotation.NonNull;
4 +
5 +import io.flutter.embedding.android.FlutterFragmentActivity;
6 +import io.flutter.embedding.engine.FlutterEngine;
7 +import io.flutter.plugins.GeneratedPluginRegistrant;
8 +
9 +import io.flutter.plugin.common.MethodCall;
10 +import io.flutter.plugin.common.MethodChannel;
11 +
12 +import android.os.AsyncTask;
13 +import android.os.Build;
14 +import android.os.Handler;
15 +import android.os.Looper;
16 +import android.view.WindowManager;
17 +
18 +import com.unstoppabledomains.resolution.DomainResolution;
19 +import com.unstoppabledomains.resolution.Resolution;
20 +
21 +import java.security.SecureRandom;
22 +
23 +public class MainActivity extends FlutterFragmentActivity {
24 + final String UTILS_CHANNEL = "com.cake_wallet/native_utils";
25 + final int UNSTOPPABLE_DOMAIN_MIN_VERSION_SDK = 24;
26 +
27 + @Override
28 + public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
29 + GeneratedPluginRegistrant.registerWith(flutterEngine);
30 +
31 + MethodChannel utilsChannel =
32 + new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(),
33 + UTILS_CHANNEL);
34 +
35 + utilsChannel.setMethodCallHandler(this::handle);
36 + }
37 +
38 + private void handle(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
39 + Handler handler = new Handler(Looper.getMainLooper());
40 +
41 + try {
42 + switch (call.method) {
43 + case "enableWakeScreen":
44 + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
45 + handler.post(() -> result.success(true));
46 + break;
47 + case "disableWakeScreen":
48 + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
49 + handler.post(() -> result.success(true));
50 + break;
51 + case "sec_random":
52 + int count = call.argument("count");
53 + SecureRandom random = new SecureRandom();
54 + byte bytes[] = new byte[count];
55 + random.nextBytes(bytes);
56 + handler.post(() -> result.success(bytes));
57 + break;
58 + case "getUnstoppableDomainAddress":
59 + int version = Build.VERSION.SDK_INT;
60 + if (version >= UNSTOPPABLE_DOMAIN_MIN_VERSION_SDK) {
61 + getUnstoppableDomainAddress(call, result);
62 + } else {
63 + handler.post(() -> result.success(""));
64 + }
65 + break;
66 + default:
67 + handler.post(() -> result.notImplemented());
68 + }
69 + } catch (Exception e) {
70 + handler.post(() -> result.error("UNCAUGHT_ERROR", e.getMessage(), null));
71 + }
72 + }
73 +
74 + private void getUnstoppableDomainAddress(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
75 + DomainResolution resolution = new Resolution();
76 + Handler handler = new Handler(Looper.getMainLooper());
77 + String domain = call.argument("domain");
78 + String ticker = call.argument("ticker");
79 +
80 + AsyncTask.execute(() -> {
81 + try {
82 + String address = resolution.getAddress(domain, ticker);
83 + handler.post(() -> result.success(address));
84 + } catch (Exception e) {
85 + System.out.println("Expected Address, but got " + e.getMessage());
86 + handler.post(() -> result.success(""));
87 + }
88 + });
89 + }
90 +}
\ No newline at end of file
assets/haven_node_list.yml new
+6
@@ -0,0 +1,6 @@
1 +-
2 + uri: vault.havenprotocol.org:443
3 + login: super
4 + password: super
5 + useSSL: true
6 + is_default: true
\ No newline at end of file
assets/images/haven_logo.png
Binary files /dev/null and b/assets/images/haven_logo.png differ
assets/images/haven_menu.png
Binary files /dev/null and b/assets/images/haven_menu.png differ
cw_bitcoin/lib/electrum_wallet.dart
+8 -7
@@ -33,6 +33,7 @@ import 'package:cw_core/transaction_priority.dart';
33 import 'package:cw_core/wallet_info.dart';
34 import 'package:cw_bitcoin/electrum.dart';
35 import 'package:hex/hex.dart';
36 +import 'package:cw_core/crypto_currency.dart';
37
38 part 'electrum_wallet.g.dart';
39
@@ -49,9 +50,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
50 @required this.mnemonic,
51 ElectrumClient electrumClient,
52 ElectrumBalance initialBalance})
52 - : balance = initialBalance ??
53 - const ElectrumBalance(confirmed: 0, unconfirmed: 0),
54 - hd = bitcoin.HDWallet.fromSeed(mnemonicToSeedBytes(mnemonic),
53 + : hd = bitcoin.HDWallet.fromSeed(mnemonicToSeedBytes(mnemonic),
54 network: networkType)
55 .derivePath("m/0'/0"),
56 syncStatus = NotConnectedSyncStatus(),
@@ -59,6 +58,8 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
58 _feeRates = <int>[],
59 _isTransactionUpdating = false,
60 super(walletInfo) {
61 + balance = ObservableMap<CryptoCurrency, ElectrumBalance>.of({
62 + currency: initialBalance ?? const ElectrumBalance(confirmed: 0, unconfirmed: 0)});
63 this.electrumClient = electrumClient ?? ElectrumClient();
64 this.walletInfo = walletInfo;
65 this.unspentCoinsInfo = unspentCoinsInfo;
@@ -82,7 +83,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
83
84 @override
85 @observable
85 - ElectrumBalance balance;
86 + ObservableMap<CryptoCurrency, ElectrumBalance> balance;
87
88 @override
89 @observable
@@ -233,7 +234,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
234
235 final totalAmount = amount + fee;
236
236 - if (totalAmount > balance.confirmed || totalAmount > allInputsAmount) {
237 + if (totalAmount > balance[currency].confirmed || totalAmount > allInputsAmount) {
238 throw BitcoinTransactionWrongBalanceException(currency);
239 }
240
@@ -326,7 +327,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
327 'account_index': walletAddresses.currentReceiveAddressIndex.toString(),
328 'change_address_index': walletAddresses.currentChangeAddressIndex.toString(),
329 'addresses': walletAddresses.addresses.map((addr) => addr.toJSON()).toList(),
329 - 'balance': balance?.toJSON()
330 + 'balance': balance[currency]?.toJSON()
331 });
332
333 int feeRate(TransactionPriority priority) {
@@ -617,7 +618,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
618 }
619
620 Future<void> _updateBalance() async {
620 - balance = await _fetchBalances();
621 + balance[currency] = await _fetchBalances();
622 await save();
623 }
624
cw_core/lib/account.dart renamed
+1 -7
@@ -1,5 +1,3 @@
1 -import 'package:cw_monero/api/structs/account_row.dart';
2 -
1 class Account {
2 Account({this.id, this.label});
3
@@ -7,10 +5,6 @@ class Account {
5 : this.id = map['id'] == null ? 0 : int.parse(map['id'] as String),
6 this.label = (map['label'] ?? '') as String;
7
10 - Account.fromRow(AccountRow row)
11 - : this.id = row.getId(),
12 - this.label = row.getLabel();
13 -
8 final int id;
9 final String label;
16 -}
10 +}
\ No newline at end of file
cw_core/lib/account_list.dart new
+16
@@ -0,0 +1,16 @@
1 +import 'package:mobx/mobx.dart';
2 +
3 +abstract class AccountList<T> {
4 +
5 + ObservableList<T> get accounts;
6 +
7 + void update();
8 +
9 + List<T> getAll();
10 +
11 + Future addAccount({String label});
12 +
13 + Future setLabelAccount({int accountIndex, String label});
14 +
15 + void refresh();
16 +}
cw_core/lib/crypto_currency.dart
+73 -1
@@ -23,7 +23,8 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
23 CryptoCurrency.usdt,
24 CryptoCurrency.usdterc20,
25 CryptoCurrency.xlm,
26 - CryptoCurrency.xrp
26 + CryptoCurrency.xrp,
27 + CryptoCurrency.xhv
28 ];
29 static const xmr = CryptoCurrency(title: 'XMR', raw: 0);
30 static const ada = CryptoCurrency(title: 'ADA', raw: 1);
@@ -41,6 +42,21 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
42 static const usdterc20 = CryptoCurrency(title: 'USDTERC20', raw: 13);
43 static const xlm = CryptoCurrency(title: 'XLM', raw: 14);
44 static const xrp = CryptoCurrency(title: 'XRP', raw: 15);
45 + static const xhv = CryptoCurrency(title: 'XHV', raw: 16);
46 +
47 + static const xag = CryptoCurrency(title: 'XAG', raw: 17);
48 + static const xau = CryptoCurrency(title: 'XAU', raw: 18);
49 + static const xaud = CryptoCurrency(title: 'XAUD', raw: 19);
50 + static const xbtc = CryptoCurrency(title: 'XBTC', raw: 20);
51 + static const xcad = CryptoCurrency(title: 'XCAD', raw: 21);
52 + static const xchf = CryptoCurrency(title: 'XCHF', raw: 22);
53 + static const xcny = CryptoCurrency(title: 'XCNY', raw: 23);
54 + static const xeur = CryptoCurrency(title: 'XEUR', raw: 24);
55 + static const xgbp = CryptoCurrency(title: 'XGBP', raw: 25);
56 + static const xjpy = CryptoCurrency(title: 'XJPY', raw: 26);
57 + static const xnok = CryptoCurrency(title: 'XNOK', raw: 27);
58 + static const xnzd = CryptoCurrency(title: 'XNZD', raw: 28);
59 + static const xusd = CryptoCurrency(title: 'XUSD', raw: 29);
60
61 static CryptoCurrency deserialize({int raw}) {
62 switch (raw) {
@@ -76,6 +92,34 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
92 return CryptoCurrency.xlm;
93 case 15:
94 return CryptoCurrency.xrp;
95 + case 16:
96 + return CryptoCurrency.xhv;
97 + case 17:
98 + return CryptoCurrency.xag;
99 + case 18:
100 + return CryptoCurrency.xau;
101 + case 19:
102 + return CryptoCurrency.xaud;
103 + case 20:
104 + return CryptoCurrency.xbtc;
105 + case 21:
106 + return CryptoCurrency.xcad;
107 + case 22:
108 + return CryptoCurrency.xchf;
109 + case 23:
110 + return CryptoCurrency.xcny;
111 + case 24:
112 + return CryptoCurrency.xeur;
113 + case 25:
114 + return CryptoCurrency.xgbp;
115 + case 26:
116 + return CryptoCurrency.xjpy;
117 + case 27:
118 + return CryptoCurrency.xnok;
119 + case 28:
120 + return CryptoCurrency.xnzd;
121 + case 29:
122 + return CryptoCurrency.xusd;
123 default:
124 return null;
125 }
@@ -115,6 +159,34 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
159 return CryptoCurrency.xlm;
160 case 'xrp':
161 return CryptoCurrency.xrp;
162 + case 'xhv':
163 + return CryptoCurrency.xhv;
164 + case 'xag':
165 + return CryptoCurrency.xag;
166 + case 'xau':
167 + return CryptoCurrency.xau;
168 + case 'xaud':
169 + return CryptoCurrency.xaud;
170 + case 'xbtc':
171 + return CryptoCurrency.xbtc;
172 + case 'xcad':
173 + return CryptoCurrency.xcad;
174 + case 'xchf':
175 + return CryptoCurrency.xchf;
176 + case 'xcny':
177 + return CryptoCurrency.xcny;
178 + case 'xeur':
179 + return CryptoCurrency.xeur;
180 + case 'xgbp':
181 + return CryptoCurrency.xgbp;
182 + case 'xjpy':
183 + return CryptoCurrency.xjpy;
184 + case 'xnok':
185 + return CryptoCurrency.xnok;
186 + case 'xnzd':
187 + return CryptoCurrency.xnzd;
188 + case 'xusd':
189 + return CryptoCurrency.xusd;
190 default:
191 return null;
192 }
cw_core/lib/currency_for_wallet_type.dart
+2
@@ -9,6 +9,8 @@ CryptoCurrency currencyForWalletType(WalletType type) {
9 return CryptoCurrency.xmr;
10 case WalletType.litecoin:
11 return CryptoCurrency.ltc;
12 + case WalletType.haven:
13 + return CryptoCurrency.xhv;
14 default:
15 return null;
16 }
cw_core/lib/get_height_by_date.dart renamed
cw_core/lib/monero_amount_format.dart renamed
+2 -1
@@ -8,7 +8,8 @@ final moneroAmountFormat = NumberFormat()
8 ..minimumFractionDigits = 1;
9
10 String moneroAmountToString({int amount}) => moneroAmountFormat
11 - .format(cryptoAmountToDouble(amount: amount, divider: moneroAmountDivider));
11 + .format(cryptoAmountToDouble(amount: amount, divider: moneroAmountDivider))
12 + .replaceAll(',', '');
13
14 double moneroAmountToDouble({int amount}) =>
15 cryptoAmountToDouble(amount: amount, divider: moneroAmountDivider);
cw_core/lib/monero_balance.dart renamed
+1 -1
@@ -1,6 +1,6 @@
1 import 'package:cw_core/balance.dart';
2 import 'package:flutter/foundation.dart';
3 -import 'package:cw_monero/monero_amount_format.dart';
3 +import 'package:cw_core/monero_amount_format.dart';
4
5 class MoneroBalance extends Balance {
6 MoneroBalance({@required this.fullBalance, @required this.unlockedBalance})
cw_core/lib/monero_transaction_priority.dart renamed
cw_core/lib/monero_wallet_keys.dart renamed
cw_core/lib/monero_wallet_utils.dart renamed
cw_core/lib/node.dart
+2
@@ -60,6 +60,8 @@ class Node extends HiveObject with Keyable {
60 return createUriFromElectrumAddress(uriRaw);
61 case WalletType.litecoin:
62 return createUriFromElectrumAddress(uriRaw);
63 + case WalletType.haven:
64 + return Uri.http(uriRaw, '');
65 default:
66 return null;
67 }
cw_core/lib/subaddress.dart new
+12
@@ -0,0 +1,12 @@
1 +class Subaddress {
2 + Subaddress({this.id, this.address, this.label});
3 +
4 + Subaddress.fromMap(Map map)
5 + : this.id = map['id'] == null ? 0 : int.parse(map['id'] as String),
6 + this.address = (map['address'] ?? '') as String,
7 + this.label = (map['label'] ?? '') as String;
8 +
9 + final int id;
10 + final String address;
11 + final String label;
12 +}
cw_core/lib/wallet_addresses_with_account.dart new
+13
@@ -0,0 +1,13 @@
1 +import 'package:cw_core/wallet_addresses.dart';
2 +import 'package:cw_core/account_list.dart';
3 +import 'package:cw_core/wallet_info.dart';
4 +
5 +abstract class WalletAddressesWithAccount<T> extends WalletAddresses {
6 + WalletAddressesWithAccount(WalletInfo walletInfo) : super(walletInfo);
7 +
8 + T get account;
9 +
10 + set account(T account);
11 +
12 + AccountList<T> get accountList;
13 +}
\ No newline at end of file
cw_core/lib/wallet_base.dart
+2 -1
@@ -1,3 +1,4 @@
1 +import 'package:mobx/mobx.dart';
2 import 'package:cw_core/balance.dart';
3 import 'package:cw_core/transaction_info.dart';
4 import 'package:cw_core/transaction_priority.dart';
@@ -35,7 +36,7 @@ abstract class WalletBase<
36
37 //set address(String address);
38
38 - BalanceType get balance;
39 + ObservableMap<CryptoCurrency, BalanceType> get balance;
40
41 SyncStatus get syncStatus;
42
cw_core/lib/wallet_type.dart
+16 -2
@@ -6,7 +6,8 @@ part 'wallet_type.g.dart';
6 const walletTypes = [
7 WalletType.monero,
8 WalletType.bitcoin,
9 - WalletType.litecoin
9 + WalletType.litecoin,
10 + WalletType.haven
11 ];
12 const walletTypeTypeId = 5;
13
@@ -22,7 +23,10 @@ enum WalletType {
23 bitcoin,
24
25 @HiveField(3)
25 - litecoin
26 + litecoin,
27 +
28 + @HiveField(4)
29 + haven
30 }
31
32 int serializeToInt(WalletType type) {
@@ -33,6 +37,8 @@ int serializeToInt(WalletType type) {
37 return 1;
38 case WalletType.litecoin:
39 return 2;
40 + case WalletType.haven:
41 + return 3;
42 default:
43 return -1;
44 }
@@ -46,6 +52,8 @@ WalletType deserializeFromInt(int raw) {
52 return WalletType.bitcoin;
53 case 2:
54 return WalletType.litecoin;
55 + case 3:
56 + return WalletType.haven;
57 default:
58 return null;
59 }
@@ -59,6 +67,8 @@ String walletTypeToString(WalletType type) {
67 return 'Bitcoin';
68 case WalletType.litecoin:
69 return 'Litecoin';
70 + case WalletType.haven:
71 + return 'Haven';
72 default:
73 return '';
74 }
@@ -72,6 +82,8 @@ String walletTypeToDisplayName(WalletType type) {
82 return 'Bitcoin (Electrum)';
83 case WalletType.litecoin:
84 return 'Litecoin (Electrum)';
85 + case WalletType.haven:
86 + return 'Haven';
87 default:
88 return '';
89 }
@@ -85,6 +97,8 @@ CryptoCurrency walletTypeToCryptoCurrency(WalletType type) {
97 return CryptoCurrency.btc;
98 case WalletType.litecoin:
99 return CryptoCurrency.ltc;
100 + case WalletType.haven:
101 + return CryptoCurrency.xhv;
102 default:
103 return null;
104 }
cw_haven/.gitignore new
+7
@@ -0,0 +1,7 @@
1 +.DS_Store
2 +.dart_tool/
3 +
4 +.packages
5 +.pub/
6 +
7 +build/
cw_haven/.metadata new
+10
@@ -0,0 +1,10 @@
1 +# This file tracks properties of this Flutter project.
2 +# Used by Flutter tool to assess capabilities and perform upgrades etc.
3 +#
4 +# This file should be version controlled and should not be manually edited.
5 +
6 +version:
7 + revision: 4d7946a68d26794349189cf21b3f68cc6fe61dcb
8 + channel: stable
9 +
10 +project_type: plugin
cw_haven/CHANGELOG.md new
+3
@@ -0,0 +1,3 @@
1 +## 0.0.1
2 +
3 +* TODO: Describe initial release.
cw_haven/LICENSE new
+1
@@ -0,0 +1 @@
1 +TODO: Add your license here.
cw_haven/README.md new
+15
@@ -0,0 +1,15 @@
1 +# cw_haven
2 +
3 +A new flutter plugin project.
4 +
5 +## Getting Started
6 +
7 +This project is a starting point for a Flutter
8 +[plug-in package](https://flutter.dev/developing-packages/),
9 +a specialized package that includes platform-specific implementation code for
10 +Android and/or iOS.
11 +
12 +For help getting started with Flutter, view our
13 +[online documentation](https://flutter.dev/docs), which offers tutorials,
14 +samples, guidance on mobile development, and a full API reference.
15 +
cw_haven/android/.gitignore new
+8
@@ -0,0 +1,8 @@
1 +*.iml
2 +.gradle
3 +/local.properties
4 +/.idea/workspace.xml
5 +/.idea/libraries
6 +.DS_Store
7 +/build
8 +/captures
cw_haven/android/CMakeLists.txt new
+220
@@ -0,0 +1,220 @@
1 +cmake_minimum_required(VERSION 3.4.1)
2 +
3 +add_library( cw_haven
4 + SHARED
5 + ../ios/Classes/haven_api.cpp)
6 +
7 + find_library( log-lib log )
8 +
9 +set(EXTERNAL_LIBS_DIR ${CMAKE_SOURCE_DIR}/../ios/External/android)
10 +
11 +############
12 +# libsodium
13 +############
14 +
15 +add_library(sodium STATIC IMPORTED)
16 +set_target_properties(sodium PROPERTIES IMPORTED_LOCATION
17 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libsodium.a)
18 +
19 +############
20 +# OpenSSL
21 +############
22 +
23 +add_library(crypto STATIC IMPORTED)
24 +set_target_properties(crypto PROPERTIES IMPORTED_LOCATION
25 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libcrypto.a)
26 +
27 +add_library(ssl STATIC IMPORTED)
28 +set_target_properties(ssl PROPERTIES IMPORTED_LOCATION
29 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libssl.a)
30 +
31 +############
32 +# Boost
33 +############
34 +
35 +add_library(boost_chrono STATIC IMPORTED)
36 +set_target_properties(boost_chrono PROPERTIES IMPORTED_LOCATION
37 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_chrono.a)
38 +
39 +add_library(boost_date_time STATIC IMPORTED)
40 +set_target_properties(boost_date_time PROPERTIES IMPORTED_LOCATION
41 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_date_time.a)
42 +
43 +add_library(boost_filesystem STATIC IMPORTED)
44 +set_target_properties(boost_filesystem PROPERTIES IMPORTED_LOCATION
45 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_filesystem.a)
46 +
47 +add_library(boost_program_options STATIC IMPORTED)
48 +set_target_properties(boost_program_options PROPERTIES IMPORTED_LOCATION
49 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_program_options.a)
50 +
51 +add_library(boost_regex STATIC IMPORTED)
52 +set_target_properties(boost_regex PROPERTIES IMPORTED_LOCATION
53 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_regex.a)
54 +
55 +add_library(boost_serialization STATIC IMPORTED)
56 +set_target_properties(boost_serialization PROPERTIES IMPORTED_LOCATION
57 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_serialization.a)
58 +
59 +add_library(boost_system STATIC IMPORTED)
60 +set_target_properties(boost_system PROPERTIES IMPORTED_LOCATION
61 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_system.a)
62 +
63 +add_library(boost_thread STATIC IMPORTED)
64 +set_target_properties(boost_thread PROPERTIES IMPORTED_LOCATION
65 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_thread.a)
66 +
67 +add_library(boost_wserialization STATIC IMPORTED)
68 +set_target_properties(boost_wserialization PROPERTIES IMPORTED_LOCATION
69 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_wserialization.a)
70 +
71 +#############
72 +# Haven
73 +#############
74 +
75 +add_library(wallet_api STATIC IMPORTED)
76 +set_target_properties(wallet_api PROPERTIES IMPORTED_LOCATION
77 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libwallet_api.a)
78 +
79 +add_library(wallet STATIC IMPORTED)
80 +set_target_properties(wallet PROPERTIES IMPORTED_LOCATION
81 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libwallet.a)
82 +
83 +add_library(cryptonote_core STATIC IMPORTED)
84 +set_target_properties(cryptonote_core PROPERTIES IMPORTED_LOCATION
85 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libcryptonote_core.a)
86 +
87 +add_library(cryptonote_basic STATIC IMPORTED)
88 +set_target_properties(cryptonote_basic PROPERTIES IMPORTED_LOCATION
89 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libcryptonote_basic.a)
90 +
91 +add_library(mnemonics STATIC IMPORTED)
92 +set_target_properties(mnemonics PROPERTIES IMPORTED_LOCATION
93 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libmnemonics.a)
94 +
95 +add_library(common STATIC IMPORTED)
96 +set_target_properties(common PROPERTIES IMPORTED_LOCATION
97 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libcommon.a)
98 +
99 +add_library(cncrypto STATIC IMPORTED)
100 +set_target_properties(cncrypto PROPERTIES IMPORTED_LOCATION
101 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libcncrypto.a)
102 +
103 +add_library(ringct STATIC IMPORTED)
104 +set_target_properties(ringct PROPERTIES IMPORTED_LOCATION
105 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libringct.a)
106 +
107 +add_library(ringct_basic STATIC IMPORTED)
108 +set_target_properties(ringct_basic PROPERTIES IMPORTED_LOCATION
109 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libringct_basic.a)
110 +
111 +add_library(blockchain_db STATIC IMPORTED)
112 +set_target_properties(blockchain_db PROPERTIES IMPORTED_LOCATION
113 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libblockchain_db.a)
114 +
115 +add_library(lmdb STATIC IMPORTED)
116 +set_target_properties(lmdb PROPERTIES IMPORTED_LOCATION
117 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/liblmdb.a)
118 +
119 +add_library(easylogging STATIC IMPORTED)
120 +set_target_properties(easylogging PROPERTIES IMPORTED_LOCATION
121 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libeasylogging.a)
122 +
123 +add_library(unbound STATIC IMPORTED)
124 +set_target_properties(unbound PROPERTIES IMPORTED_LOCATION
125 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libunbound.a)
126 +
127 +add_library(epee STATIC IMPORTED)
128 +set_target_properties(epee PROPERTIES IMPORTED_LOCATION
129 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libepee.a)
130 +
131 +add_library(checkpoints STATIC IMPORTED)
132 +set_target_properties(checkpoints PROPERTIES IMPORTED_LOCATION
133 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libcheckpoints.a)
134 +
135 +add_library(device STATIC IMPORTED)
136 +set_target_properties(device PROPERTIES IMPORTED_LOCATION
137 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libdevice.a)
138 +
139 +add_library(device_trezor STATIC IMPORTED)
140 +set_target_properties(device_trezor PROPERTIES IMPORTED_LOCATION
141 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libdevice_trezor.a)
142 +
143 +add_library(multisig STATIC IMPORTED)
144 +set_target_properties(multisig PROPERTIES IMPORTED_LOCATION
145 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libmultisig.a)
146 +
147 +add_library(version STATIC IMPORTED)
148 +set_target_properties(version PROPERTIES IMPORTED_LOCATION
149 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libversion.a)
150 +
151 +add_library(net STATIC IMPORTED)
152 +set_target_properties(net PROPERTIES IMPORTED_LOCATION
153 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libnet.a)
154 +
155 +add_library(hardforks STATIC IMPORTED)
156 +set_target_properties(hardforks PROPERTIES IMPORTED_LOCATION
157 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libhardforks.a)
158 +
159 +add_library(randomx STATIC IMPORTED)
160 +set_target_properties(randomx PROPERTIES IMPORTED_LOCATION
161 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/librandomx.a)
162 +
163 +add_library(offshore STATIC IMPORTED)
164 +set_target_properties(offshore PROPERTIES IMPORTED_LOCATION
165 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/liboffshore.a)
166 +
167 +
168 +add_library(rpc_base STATIC IMPORTED)
169 +set_target_properties(rpc_base PROPERTIES IMPORTED_LOCATION
170 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/librpc_base.a)
171 +
172 +add_library(wallet-crypto STATIC IMPORTED)
173 +set_target_properties(wallet-crypto PROPERTIES IMPORTED_LOCATION
174 + ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/haven/libwallet-crypto.a)
175 +
176 +include_directories( ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/include )
177 +
178 +target_link_libraries( cw_haven
179 +
180 + wallet_api
181 + wallet
182 + cryptonote_core
183 + cryptonote_basic
184 + mnemonics
185 + ringct
186 + ringct_basic
187 + net
188 + common
189 + cncrypto
190 + blockchain_db
191 + lmdb
192 + easylogging
193 + unbound
194 + epee
195 + checkpoints
196 + device
197 + device_trezor
198 + multisig
199 + version
200 + randomx
201 + offshore
202 + hardforks
203 + rpc_base
204 +
205 + boost_chrono
206 + boost_date_time
207 + boost_filesystem
208 + boost_program_options
209 + boost_regex
210 + boost_serialization
211 + boost_system
212 + boost_thread
213 + boost_wserialization
214 +
215 + ssl
216 + crypto
217 +
218 + sodium
219 +
220 + ${log-lib} )
\ No newline at end of file
cw_haven/android/build.gradle new
+45
@@ -0,0 +1,45 @@
1 +group 'com.cakewallet.cw_haven'
2 +version '1.0-SNAPSHOT'
3 +
4 +buildscript {
5 + ext.kotlin_version = '1.3.50'
6 + repositories {
7 + google()
8 + jcenter()
9 + }
10 +
11 + dependencies {
12 + classpath 'com.android.tools.build:gradle:4.1.0'
13 + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
14 + }
15 +}
16 +
17 +rootProject.allprojects {
18 + repositories {
19 + google()
20 + jcenter()
21 + }
22 +}
23 +
24 +apply plugin: 'com.android.library'
25 +apply plugin: 'kotlin-android'
26 +
27 +android {
28 + compileSdkVersion 28
29 +
30 + sourceSets {
31 + main.java.srcDirs += 'src/main/kotlin'
32 + }
33 + defaultConfig {
34 + minSdkVersion 21
35 + }
36 + externalNativeBuild {
37 + cmake {
38 + path "CMakeLists.txt"
39 + }
40 + }
41 +}
42 +
43 +dependencies {
44 + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
45 +}
cw_haven/android/gradle.properties new
+3
@@ -0,0 +1,3 @@
1 +org.gradle.jvmargs=-Xmx1536M
2 +android.useAndroidX=true
3 +android.enableJetifier=true
cw_haven/android/gradle/wrapper/gradle-wrapper.properties new
+5
@@ -0,0 +1,5 @@
1 +distributionBase=GRADLE_USER_HOME
2 +distributionPath=wrapper/dists
3 +zipStoreBase=GRADLE_USER_HOME
4 +zipStorePath=wrapper/dists
5 +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
cw_haven/android/settings.gradle new
+1
@@ -0,0 +1 @@
1 +rootProject.name = 'cw_haven'
cw_haven/android/src/main/AndroidManifest.xml new
+3
@@ -0,0 +1,3 @@
1 +<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2 + package="com.cakewallet.cw_haven">
3 +</manifest>
cw_haven/android/src/main/kotlin/com/cakewallet/cw_haven/CwHavenPlugin.kt new
+36
@@ -0,0 +1,36 @@
1 +package com.cakewallet.cw_haven
2 +
3 +import androidx.annotation.NonNull
4 +
5 +import io.flutter.embedding.engine.plugins.FlutterPlugin
6 +import io.flutter.plugin.common.MethodCall
7 +import io.flutter.plugin.common.MethodChannel
8 +import io.flutter.plugin.common.MethodChannel.MethodCallHandler
9 +import io.flutter.plugin.common.MethodChannel.Result
10 +import io.flutter.plugin.common.PluginRegistry.Registrar
11 +
12 +/** CwHavenPlugin */
13 +class CwHavenPlugin: FlutterPlugin, MethodCallHandler {
14 + /// The MethodChannel that will the communication between Flutter and native Android
15 + ///
16 + /// This local reference serves to register the plugin with the Flutter Engine and unregister it
17 + /// when the Flutter Engine is detached from the Activity
18 + private lateinit var channel : MethodChannel
19 +
20 + override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
21 + channel = MethodChannel(flutterPluginBinding.binaryMessenger, "cw_haven")
22 + channel.setMethodCallHandler(this)
23 + }
24 +
25 + override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
26 + if (call.method == "getPlatformVersion") {
27 + result.success("Android ${android.os.Build.VERSION.RELEASE}")
28 + } else {
29 + result.notImplemented()
30 + }
31 + }
32 +
33 + override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
34 + channel.setMethodCallHandler(null)
35 + }
36 +}
cw_haven/ios/.gitignore new
+37
@@ -0,0 +1,37 @@
1 +.idea/
2 +.vagrant/
3 +.sconsign.dblite
4 +.svn/
5 +
6 +.DS_Store
7 +*.swp
8 +profile
9 +
10 +DerivedData/
11 +build/
12 +GeneratedPluginRegistrant.h
13 +GeneratedPluginRegistrant.m
14 +
15 +.generated/
16 +
17 +*.pbxuser
18 +*.mode1v3
19 +*.mode2v3
20 +*.perspectivev3
21 +
22 +!default.pbxuser
23 +!default.mode1v3
24 +!default.mode2v3
25 +!default.perspectivev3
26 +
27 +xcuserdata
28 +
29 +*.moved-aside
30 +
31 +*.pyc
32 +*sync/
33 +Icon?
34 +.tags*
35 +
36 +/Flutter/Generated.xcconfig
37 +/Flutter/flutter_export_environment.sh
\ No newline at end of file
cw_haven/ios/Assets/.gitkeep
cw_haven/ios/Classes/CwHavenPlugin.h new
+4
@@ -0,0 +1,4 @@
1 +#import <Flutter/Flutter.h>
2 +
3 +@interface CwHavenPlugin : NSObject<FlutterPlugin>
4 +@end
cw_haven/ios/Classes/CwHavenPlugin.m new
+15
@@ -0,0 +1,15 @@
1 +#import "CwHavenPlugin.h"
2 +#if __has_include(<cw_haven/cw_haven-Swift.h>)
3 +#import <cw_haven/cw_haven-Swift.h>
4 +#else
5 +// Support project import fallback if the generated compatibility header
6 +// is not copied when this plugin is created as a library.
7 +// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816
8 +#import "cw_haven-Swift.h"
9 +#endif
10 +
11 +@implementation CwHavenPlugin
12 ++ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
13 + [SwiftCwHavenPlugin registerWithRegistrar:registrar];
14 +}
15 +@end
cw_haven/ios/Classes/SwiftCwHavenPlugin.swift new
+14
@@ -0,0 +1,14 @@
1 +import Flutter
2 +import UIKit
3 +
4 +public class SwiftCwHavenPlugin: NSObject, FlutterPlugin {
5 + public static func register(with registrar: FlutterPluginRegistrar) {
6 + let channel = FlutterMethodChannel(name: "cw_haven", binaryMessenger: registrar.messenger())
7 + let instance = SwiftCwHavenPlugin()
8 + registrar.addMethodCallDelegate(instance, channel: channel)
9 + }
10 +
11 + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
12 + result("iOS " + UIDevice.current.systemVersion)
13 + }
14 +}
cw_haven/ios/Classes/haven_api.cpp new
+922
@@ -0,0 +1,922 @@
1 +#include <stdint.h>
2 +#include "cstdlib"
3 +#include <chrono>
4 +#include <functional>
5 +#include <iostream>
6 +#include <unistd.h>
7 +#include <mutex>
8 +#include "thread"
9 +#if __APPLE__
10 +// Fix for randomx on ios
11 +void __clear_cache(void* start, void* end) { }
12 +#include "../External/ios/include/wallet2_api.h"
13 +#else
14 +#include "../External/android/x86/include/wallet2_api.h"
15 +#endif
16 +
17 +using namespace std::chrono_literals;
18 +
19 +#ifdef __cplusplus
20 +extern "C"
21 +{
22 +#endif
23 + const uint64_t MONERO_BLOCK_SIZE = 1000;
24 +
25 + struct Utf8Box
26 + {
27 + char *value;
28 +
29 + Utf8Box(char *_value)
30 + {
31 + value = _value;
32 + }
33 + };
34 +
35 +
36 + struct SubaddressRow
37 + {
38 + uint64_t id;
39 + char *address;
40 + char *label;
41 +
42 + SubaddressRow(std::size_t _id, char *_address, char *_label)
43 + {
44 + id = static_cast<uint64_t>(_id);
45 + address = _address;
46 + label = _label;
47 + }
48 + };
49 +
50 + struct AccountRow
51 + {
52 + uint64_t id;
53 + char *label;
54 +
55 + AccountRow(std::size_t _id, char *_label)
56 + {
57 + id = static_cast<uint64_t>(_id);
58 + label = _label;
59 + }
60 + };
61 +
62 + struct HavenBalance
63 + {
64 + uint64_t amount;
65 + char *assetType;
66 +
67 + HavenBalance(char *_assetType, uint64_t _amount)
68 + {
69 + amount = _amount;
70 + assetType = _assetType;
71 + }
72 + };
73 +
74 + struct HavenRate
75 + {
76 + uint64_t rate;
77 + char *assetType;
78 +
79 + HavenRate(char *_assetType, uint64_t _rate)
80 + {
81 + rate = _rate;
82 + assetType = _assetType;
83 + }
84 + };
85 +
86 + struct MoneroWalletListener : Monero::WalletListener
87 + {
88 + uint64_t m_height;
89 + bool m_need_to_refresh;
90 + bool m_new_transaction;
91 +
92 + MoneroWalletListener()
93 + {
94 + m_height = 0;
95 + m_need_to_refresh = false;
96 + m_new_transaction = false;
97 + }
98 +
99 + void moneySpent(const std::string &txId, uint64_t amount, std::string assetType)
100 + {
101 + m_new_transaction = true;
102 + }
103 +
104 + void moneyReceived(const std::string &txId, uint64_t amount, std::string assetType)
105 + {
106 + m_new_transaction = true;
107 + }
108 +
109 + void unconfirmedMoneyReceived(const std::string &txId, uint64_t amount)
110 + {
111 + m_new_transaction = true;
112 + }
113 +
114 + void newBlock(uint64_t height)
115 + {
116 + m_height = height;
117 + }
118 +
119 + void updated()
120 + {
121 + m_new_transaction = true;
122 + }
123 +
124 + void refreshed()
125 + {
126 + m_need_to_refresh = true;
127 + }
128 +
129 + void resetNeedToRefresh()
130 + {
131 + m_need_to_refresh = false;
132 + }
133 +
134 + bool isNeedToRefresh()
135 + {
136 + return m_need_to_refresh;
137 + }
138 +
139 + bool isNewTransactionExist()
140 + {
141 + return m_new_transaction;
142 + }
143 +
144 + void resetIsNewTransactionExist()
145 + {
146 + m_new_transaction = false;
147 + }
148 +
149 + uint64_t height()
150 + {
151 + return m_height;
152 + }
153 + };
154 +
155 + struct TransactionInfoRow
156 + {
157 + uint64_t amount;
158 + uint64_t fee;
159 + uint64_t blockHeight;
160 + uint64_t confirmations;
161 + uint32_t subaddrAccount;
162 + int8_t direction;
163 + int8_t isPending;
164 + uint32_t subaddrIndex;
165 +
166 + char *hash;
167 + char *paymentId;
168 + char *assetType;
169 +
170 + int64_t datetime;
171 +
172 + TransactionInfoRow(Monero::TransactionInfo *transaction)
173 + {
174 + amount = transaction->amount();
175 + fee = transaction->fee();
176 + blockHeight = transaction->blockHeight();
177 + subaddrAccount = transaction->subaddrAccount();
178 + std::set<uint32_t>::iterator it = transaction->subaddrIndex().begin();
179 + subaddrIndex = *it;
180 + confirmations = transaction->confirmations();
181 + datetime = static_cast<int64_t>(transaction->timestamp());
182 + direction = transaction->direction();
183 + isPending = static_cast<int8_t>(transaction->isPending());
184 + std::string *hash_str = new std::string(transaction->hash());
185 + hash = strdup(hash_str->c_str());
186 + paymentId = strdup(transaction->paymentId().c_str());
187 + assetType = strdup(transaction->assetType().c_str());
188 + }
189 + };
190 +
191 + struct PendingTransactionRaw
192 + {
193 + uint64_t amount;
194 + uint64_t fee;
195 + char *hash;
196 + Monero::PendingTransaction *transaction;
197 +
198 + PendingTransactionRaw(Monero::PendingTransaction *_transaction)
199 + {
200 + transaction = _transaction;
201 + amount = _transaction->amount();
202 + fee = _transaction->fee();
203 + hash = strdup(_transaction->txid()[0].c_str());
204 + }
205 + };
206 +
207 + Monero::Wallet *m_wallet;
208 + Monero::TransactionHistory *m_transaction_history;
209 + MoneroWalletListener *m_listener;
210 + Monero::Subaddress *m_subaddress;
211 + Monero::SubaddressAccount *m_account;
212 + uint64_t m_last_known_wallet_height;
213 + uint64_t m_cached_syncing_blockchain_height = 0;
214 + std::mutex store_lock;
215 + bool is_storing = false;
216 +
217 + void change_current_wallet(Monero::Wallet *wallet)
218 + {
219 + m_wallet = wallet;
220 + m_listener = nullptr;
221 +
222 +
223 + if (wallet != nullptr)
224 + {
225 + m_transaction_history = wallet->history();
226 + }
227 + else
228 + {
229 + m_transaction_history = nullptr;
230 + }
231 +
232 + if (wallet != nullptr)
233 + {
234 + m_account = wallet->subaddressAccount();
235 + }
236 + else
237 + {
238 + m_account = nullptr;
239 + }
240 +
241 + if (wallet != nullptr)
242 + {
243 + m_subaddress = wallet->subaddress();
244 + }
245 + else
246 + {
247 + m_subaddress = nullptr;
248 + }
249 + }
250 +
251 + Monero::Wallet *get_current_wallet()
252 + {
253 + return m_wallet;
254 + }
255 +
256 + bool create_wallet(char *path, char *password, char *language, int32_t networkType, char *error)
257 + {
258 + Monero::WalletManagerFactory::setLogLevel(4);
259 +
260 + Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
261 + Monero::WalletManager *walletManager = Monero::WalletManagerFactory::getWalletManager();
262 + Monero::Wallet *wallet = walletManager->createWallet(path, password, language, _networkType);
263 +
264 + int status;
265 + std::string errorString;
266 +
267 + wallet->statusWithErrorString(status, errorString);
268 +
269 + if (wallet->status() != Monero::Wallet::Status_Ok)
270 + {
271 + error = strdup(wallet->errorString().c_str());
272 + return false;
273 + }
274 +
275 + change_current_wallet(wallet);
276 +
277 + return true;
278 + }
279 +
280 + bool restore_wallet_from_seed(char *path, char *password, char *seed, int32_t networkType, uint64_t restoreHeight, char *error)
281 + {
282 + Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
283 + Monero::Wallet *wallet = Monero::WalletManagerFactory::getWalletManager()->recoveryWallet(
284 + std::string(path),
285 + std::string(password),
286 + std::string(seed),
287 + _networkType,
288 + (uint64_t)restoreHeight);
289 +
290 + int status;
291 + std::string errorString;
292 +
293 + wallet->statusWithErrorString(status, errorString);
294 +
295 + if (status != Monero::Wallet::Status_Ok || !errorString.empty())
296 + {
297 + error = strdup(errorString.c_str());
298 + return false;
299 + }
300 +
301 + change_current_wallet(wallet);
302 + return true;
303 + }
304 +
305 + bool restore_wallet_from_keys(char *path, char *password, char *language, char *address, char *viewKey, char *spendKey, int32_t networkType, uint64_t restoreHeight, char *error)
306 + {
307 + Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
308 + Monero::Wallet *wallet = Monero::WalletManagerFactory::getWalletManager()->createWalletFromKeys(
309 + std::string(path),
310 + std::string(password),
311 + std::string(language),
312 + _networkType,
313 + (uint64_t)restoreHeight,
314 + std::string(address),
315 + std::string(viewKey),
316 + std::string(spendKey));
317 +
318 + int status;
319 + std::string errorString;
320 +
321 + wallet->statusWithErrorString(status, errorString);
322 +
323 + if (status != Monero::Wallet::Status_Ok || !errorString.empty())
324 + {
325 + error = strdup(errorString.c_str());
326 + return false;
327 + }
328 +
329 + change_current_wallet(wallet);
330 + return true;
331 + }
332 +
333 + bool load_wallet(char *path, char *password, int32_t nettype)
334 + {
335 + nice(19);
336 + Monero::NetworkType networkType = static_cast<Monero::NetworkType>(nettype);
337 + Monero::WalletManager *walletManager = Monero::WalletManagerFactory::getWalletManager();
338 + Monero::Wallet *wallet = walletManager->openWallet(std::string(path), std::string(password), networkType);
339 + int status;
340 + std::string errorString;
341 +
342 + wallet->statusWithErrorString(status, errorString);
343 + change_current_wallet(wallet);
344 +
345 + return !(status != Monero::Wallet::Status_Ok || !errorString.empty());
346 + }
347 +
348 + char *error_string() {
349 + return strdup(get_current_wallet()->errorString().c_str());
350 + }
351 +
352 +
353 + bool is_wallet_exist(char *path)
354 + {
355 + return Monero::WalletManagerFactory::getWalletManager()->walletExists(std::string(path));
356 + }
357 +
358 + void close_current_wallet()
359 + {
360 + Monero::WalletManagerFactory::getWalletManager()->closeWallet(get_current_wallet());
361 + change_current_wallet(nullptr);
362 + }
363 +
364 + char *get_filename()
365 + {
366 + return strdup(get_current_wallet()->filename().c_str());
367 + }
368 +
369 + char *secret_view_key()
370 + {
371 + return strdup(get_current_wallet()->secretViewKey().c_str());
372 + }
373 +
374 + char *public_view_key()
375 + {
376 + return strdup(get_current_wallet()->publicViewKey().c_str());
377 + }
378 +
379 + char *secret_spend_key()
380 + {
381 + return strdup(get_current_wallet()->secretSpendKey().c_str());
382 + }
383 +
384 + char *public_spend_key()
385 + {
386 + return strdup(get_current_wallet()->publicSpendKey().c_str());
387 + }
388 +
389 + char *get_address(uint32_t account_index, uint32_t address_index)
390 + {
391 + return strdup(get_current_wallet()->address(account_index, address_index).c_str());
392 + }
393 +
394 +
395 + const char *seed()
396 + {
397 + return strdup(get_current_wallet()->seed().c_str());
398 + }
399 +
400 + int64_t *get_full_balance(uint32_t account_index)
401 + {
402 + std::map<std::string, uint64_t> accountBalance;
403 + std::map<uint32_t, std::map<std::string, uint64_t>> balanceSubaddresses = get_current_wallet()->balance(account_index);
404 + std::vector<std::string> assetList = Monero::Assets::list();
405 + //prefill balances
406 + for (const auto &asset_type : assetList) {
407 +
408 + accountBalance[asset_type] = 0;
409 + }
410 + // balances are mapped to their subaddress
411 + // we compute total balances of account
412 + for (auto const& balanceSubaddress : balanceSubaddresses)
413 + {
414 +
415 + std::map<std::string, uint64_t> balanceOfSubaddress = balanceSubaddress.second;
416 +
417 + for (auto const& balance : balanceOfSubaddress)
418 + {
419 +
420 + const std::string &assetType = balance.first;
421 + const uint64_t &amount = balance.second;
422 + accountBalance[assetType] +=amount;
423 + }
424 + }
425 +
426 + size_t size = accountBalance.size();
427 + int64_t *balanceAddresses = (int64_t *)malloc(size * sizeof(int64_t));
428 + int i = 0;
429 +
430 + for (auto const& balance : accountBalance)
431 + {
432 + char *assetType = strdup(balance.first.c_str());
433 + HavenBalance *hb = new HavenBalance(assetType, balance.second);
434 + balanceAddresses[i] = reinterpret_cast<int64_t>(hb);
435 + i++;
436 + }
437 + return balanceAddresses;
438 + }
439 +
440 + int64_t *get_unlocked_balance(uint32_t account_index)
441 + {
442 + std::map<std::string, uint64_t> accountBalance;
443 + std::map<uint32_t, std::map<std::string, uint64_t>> balanceSubaddresses = get_current_wallet()->unlockedBalance(account_index);
444 + std::vector<std::string> assetList = Monero::Assets::list();
445 +
446 + //prefill balances
447 + for (const auto &asset_type : assetList) {
448 +
449 + accountBalance[asset_type] = 0;
450 + }
451 + // balances are mapped to their subaddress
452 + // we compute total balances of account
453 + for (auto const& balanceSubaddress : balanceSubaddresses)
454 + {
455 +
456 + std::map<std::string, uint64_t> balanceOfSubaddress = balanceSubaddress.second;
457 +
458 + for (auto const& balance : balanceOfSubaddress)
459 + {
460 +
461 + const std::string &assetType = balance.first;
462 + const uint64_t &amount = balance.second;
463 + accountBalance[assetType] +=amount;
464 + }
465 + }
466 +
467 + size_t size = accountBalance.size();
468 + int64_t *balanceAddresses = (int64_t *)malloc(size * sizeof(int64_t));
469 + int i = 0;
470 +
471 + for (auto const& balance : accountBalance)
472 + {
473 + char *assetType = strdup(balance.first.c_str());
474 + HavenBalance *hb = new HavenBalance(assetType, balance.second);
475 + balanceAddresses[i] = reinterpret_cast<int64_t>(hb);
476 + i++;
477 + }
478 + return balanceAddresses;
479 + }
480 +
481 + uint64_t get_current_height()
482 + {
483 + return get_current_wallet()->blockChainHeight();
484 + }
485 +
486 + uint64_t get_node_height()
487 + {
488 + return get_current_wallet()->daemonBlockChainHeight();
489 + }
490 +
491 + bool connect_to_node(char *error)
492 + {
493 + nice(19);
494 + bool is_connected = get_current_wallet()->connectToDaemon();
495 +
496 + if (!is_connected)
497 + {
498 + error = strdup(get_current_wallet()->errorString().c_str());
499 + }
500 +
501 + return is_connected;
502 + }
503 +
504 + bool setup_node(char *address, char *login, char *password, bool use_ssl, bool is_light_wallet, char *error)
505 + {
506 + nice(19);
507 + Monero::Wallet *wallet = get_current_wallet();
508 +
509 + std::string _login = "";
510 + std::string _password = "";
511 +
512 + if (login != nullptr)
513 + {
514 + _login = std::string(login);
515 + }
516 +
517 + if (password != nullptr)
518 + {
519 + _password = std::string(password);
520 + }
521 +
522 + bool inited = wallet->init(std::string(address), 0, _login, _password, use_ssl, is_light_wallet);
523 +
524 + if (!inited)
525 + {
526 + error = strdup(wallet->errorString().c_str());
527 + } else if (!wallet->connectToDaemon()) {
528 + error = strdup(wallet->errorString().c_str());
529 + }
530 +
531 + return inited;
532 + }
533 +
534 + bool is_connected()
535 + {
536 + return get_current_wallet()->connected();
537 + }
538 +
539 + void start_refresh()
540 + {
541 + get_current_wallet()->refreshAsync();
542 + get_current_wallet()->startRefresh();
543 + }
544 +
545 + void set_refresh_from_block_height(uint64_t height)
546 + {
547 + get_current_wallet()->setRefreshFromBlockHeight(height);
548 + }
549 +
550 + void set_recovering_from_seed(bool is_recovery)
551 + {
552 + get_current_wallet()->setRecoveringFromSeed(is_recovery);
553 + }
554 +
555 + void store(char *path)
556 + {
557 + store_lock.lock();
558 + if (is_storing) {
559 + return;
560 + }
561 +
562 + is_storing = true;
563 + get_current_wallet()->store(std::string(path));
564 + is_storing = false;
565 + store_lock.unlock();
566 + }
567 +
568 + bool transaction_create(char *address, char *asset_type, char *payment_id, char *amount,
569 + uint8_t priority_raw, uint32_t subaddr_account, Utf8Box &error, PendingTransactionRaw &pendingTransaction)
570 + {
571 + nice(19);
572 +
573 + auto priority = static_cast<Monero::PendingTransaction::Priority>(priority_raw);
574 + std::string _payment_id;
575 + Monero::PendingTransaction *transaction;
576 +
577 + if (payment_id != nullptr)
578 + {
579 + _payment_id = std::string(payment_id);
580 + }
581 +
582 + if (amount != nullptr)
583 + {
584 + uint64_t _amount = Monero::Wallet::amountFromString(std::string(amount));
585 + transaction = m_wallet->createTransaction(std::string(address), _payment_id, _amount, std::string(asset_type), std::string(asset_type), m_wallet->defaultMixin(), priority, subaddr_account, {});
586 + }
587 + else
588 + {
589 + transaction = m_wallet->createTransaction(std::string(address), _payment_id, Monero::optional<uint64_t>(),std::string(asset_type), std::string(asset_type), m_wallet->defaultMixin(), priority, subaddr_account, {});
590 + }
591 +
592 + int status = transaction->status();
593 +
594 + if (status == Monero::PendingTransaction::Status::Status_Error || status == Monero::PendingTransaction::Status::Status_Critical)
595 + {
596 + error = Utf8Box(strdup(transaction->errorString().c_str()));
597 + return false;
598 + }
599 +
600 + if (m_listener != nullptr) {
601 + m_listener->m_new_transaction = true;
602 + }
603 +
604 + pendingTransaction = PendingTransactionRaw(transaction);
605 + return true;
606 + }
607 +
608 + bool transaction_create_mult_dest(char **addresses, char *asset_type, char *payment_id, char **amounts, uint32_t size,
609 + uint8_t priority_raw, uint32_t subaddr_account, Utf8Box &error, PendingTransactionRaw &pendingTransaction)
610 + {
611 + nice(19);
612 +
613 + std::vector<std::string> _addresses;
614 + std::vector<uint64_t> _amounts;
615 +
616 + for (int i = 0; i < size; i++) {
617 + _addresses.push_back(std::string(*addresses));
618 + _amounts.push_back(Monero::Wallet::amountFromString(std::string(*amounts)));
619 + addresses++;
620 + amounts++;
621 + }
622 +
623 + auto priority = static_cast<Monero::PendingTransaction::Priority>(priority_raw);
624 + std::string _payment_id;
625 + Monero::PendingTransaction *transaction;
626 +
627 + if (payment_id != nullptr)
628 + {
629 + _payment_id = std::string(payment_id);
630 + }
631 +
632 + transaction = m_wallet->createTransactionMultDest(_addresses, _payment_id, _amounts,
633 + std::string(asset_type), std::string(asset_type), m_wallet->defaultMixin(), priority, subaddr_account,{});
634 +
635 + int status = transaction->status();
636 +
637 + if (status == Monero::PendingTransaction::Status::Status_Error || status == Monero::PendingTransaction::Status::Status_Critical)
638 + {
639 + error = Utf8Box(strdup(transaction->errorString().c_str()));
640 + return false;
641 + }
642 +
643 + if (m_listener != nullptr) {
644 + m_listener->m_new_transaction = true;
645 + }
646 +
647 + pendingTransaction = PendingTransactionRaw(transaction);
648 + return true;
649 + }
650 +
651 + bool transaction_commit(PendingTransactionRaw *transaction, Utf8Box &error)
652 + {
653 + bool committed = transaction->transaction->commit();
654 +
655 + if (!committed)
656 + {
657 + error = Utf8Box(strdup(transaction->transaction->errorString().c_str()));
658 + } else if (m_listener != nullptr) {
659 + m_listener->m_new_transaction = true;
660 + }
661 +
662 + return committed;
663 + }
664 +
665 + uint64_t get_node_height_or_update(uint64_t base_eight)
666 + {
667 + if (m_cached_syncing_blockchain_height < base_eight) {
668 + m_cached_syncing_blockchain_height = base_eight;
669 + }
670 +
671 + return m_cached_syncing_blockchain_height;
672 + }
673 +
674 + uint64_t get_syncing_height()
675 + {
676 + if (m_listener == nullptr) {
677 + return 0;
678 + }
679 +
680 + uint64_t height = m_listener->height();
681 +
682 + if (height <= 1) {
683 + return 0;
684 + }
685 +
686 + if (height != m_last_known_wallet_height)
687 + {
688 + m_last_known_wallet_height = height;
689 + }
690 +
691 + return height;
692 + }
693 +
694 + uint64_t is_needed_to_refresh()
695 + {
696 + if (m_listener == nullptr) {
697 + return false;
698 + }
699 +
700 + bool should_refresh = m_listener->isNeedToRefresh();
701 +
702 + if (should_refresh) {
703 + m_listener->resetNeedToRefresh();
704 + }
705 +
706 + return should_refresh;
707 + }
708 +
709 + uint8_t is_new_transaction_exist()
710 + {
711 + if (m_listener == nullptr) {
712 + return false;
713 + }
714 +
715 + bool is_new_transaction_exist = m_listener->isNewTransactionExist();
716 +
717 + if (is_new_transaction_exist)
718 + {
719 + m_listener->resetIsNewTransactionExist();
720 + }
721 +
722 + return is_new_transaction_exist;
723 + }
724 +
725 + void set_listener()
726 + {
727 + m_last_known_wallet_height = 0;
728 +
729 + if (m_listener != nullptr)
730 + {
731 + free(m_listener);
732 + }
733 +
734 + m_listener = new MoneroWalletListener();
735 + get_current_wallet()->setListener(m_listener);
736 + }
737 +
738 + int64_t *subaddrress_get_all()
739 + {
740 + std::vector<Monero::SubaddressRow *> _subaddresses = m_subaddress->getAll();
741 + size_t size = _subaddresses.size();
742 + int64_t *subaddresses = (int64_t *)malloc(size * sizeof(int64_t));
743 +
744 + for (int i = 0; i < size; i++)
745 + {
746 + Monero::SubaddressRow *row = _subaddresses[i];
747 + SubaddressRow *_row = new SubaddressRow(row->getRowId(), strdup(row->getAddress().c_str()), strdup(row->getLabel().c_str()));
748 + subaddresses[i] = reinterpret_cast<int64_t>(_row);
749 + }
750 +
751 + return subaddresses;
752 + }
753 +
754 + int32_t subaddrress_size()
755 + {
756 + std::vector<Monero::SubaddressRow *> _subaddresses = m_subaddress->getAll();
757 + return _subaddresses.size();
758 + }
759 +
760 + void subaddress_add_row(uint32_t accountIndex, char *label)
761 + {
762 + m_subaddress->addRow(accountIndex, std::string(label));
763 + }
764 +
765 + void subaddress_set_label(uint32_t accountIndex, uint32_t addressIndex, char *label)
766 + {
767 + m_subaddress->setLabel(accountIndex, addressIndex, std::string(label));
768 + }
769 +
770 + void subaddress_refresh(uint32_t accountIndex)
771 + {
772 + m_subaddress->refresh(accountIndex);
773 + }
774 +
775 + int32_t account_size()
776 + {
777 + std::vector<Monero::SubaddressAccountRow *> _accocunts = m_account->getAll();
778 + return _accocunts.size();
779 + }
780 +
781 + int64_t *account_get_all()
782 + {
783 + std::vector<Monero::SubaddressAccountRow *> _accocunts = m_account->getAll();
784 + size_t size = _accocunts.size();
785 + int64_t *accocunts = (int64_t *)malloc(size * sizeof(int64_t));
786 +
787 + for (int i = 0; i < size; i++)
788 + {
789 + Monero::SubaddressAccountRow *row = _accocunts[i];
790 + AccountRow *_row = new AccountRow(row->getRowId(), strdup(row->getLabel().c_str()));
791 + accocunts[i] = reinterpret_cast<int64_t>(_row);
792 + }
793 +
794 + return accocunts;
795 + }
796 +
797 + void account_add_row(char *label)
798 + {
799 + m_account->addRow(std::string(label));
800 + }
801 +
802 + void account_set_label_row(uint32_t account_index, char *label)
803 + {
804 + m_account->setLabel(account_index, label);
805 + }
806 +
807 + void account_refresh()
808 + {
809 + m_account->refresh();
810 + }
811 +
812 + int64_t *transactions_get_all()
813 + {
814 + std::vector<Monero::TransactionInfo *> transactions = m_transaction_history->getAll();
815 + size_t size = transactions.size();
816 + int64_t *transactionAddresses = (int64_t *)malloc(size * sizeof(int64_t));
817 +
818 + for (int i = 0; i < size; i++)
819 + {
820 + Monero::TransactionInfo *row = transactions[i];
821 + TransactionInfoRow *tx = new TransactionInfoRow(row);
822 + transactionAddresses[i] = reinterpret_cast<int64_t>(tx);
823 + }
824 +
825 + return transactionAddresses;
826 + }
827 +
828 + void transactions_refresh()
829 + {
830 + m_transaction_history->refresh();
831 + }
832 +
833 + int64_t transactions_count()
834 + {
835 + return m_transaction_history->count();
836 + }
837 +
838 + int LedgerExchange(
839 + unsigned char *command,
840 + unsigned int cmd_len,
841 + unsigned char *response,
842 + unsigned int max_resp_len)
843 + {
844 + return -1;
845 + }
846 +
847 + int LedgerFind(char *buffer, size_t len)
848 + {
849 + return -1;
850 + }
851 +
852 + void on_startup()
853 + {
854 + Monero::Utils::onStartup();
855 + Monero::WalletManagerFactory::setLogLevel(4);
856 + }
857 +
858 + void rescan_blockchain()
859 + {
860 + m_wallet->rescanBlockchainAsync();
861 + }
862 +
863 + char * get_tx_key(char * txId)
864 + {
865 + return strdup(m_wallet->getTxKey(std::string(txId)).c_str());
866 + }
867 +
868 + int32_t asset_types_size()
869 + {
870 + return Monero::Assets::list().size();
871 + }
872 +
873 + char **asset_types()
874 + {
875 + size_t size = Monero::Assets::list().size();
876 + std::vector<std::string> assetList = Monero::Assets::list();
877 + char **assetTypesPts;
878 + assetTypesPts = (char **) malloc( size * sizeof(char*));
879 +
880 + for (int i = 0; i < size; i++)
881 + {
882 +
883 + std::string asset = assetList[i];
884 + //assetTypes[i] = (char *)malloc( 5 * sizeof(char));
885 + assetTypesPts[i] = strdup(asset.c_str());
886 + }
887 +
888 + return assetTypesPts;
889 + }
890 +
891 + std::map<std::string, uint64_t> rates;
892 +
893 + void update_rate()
894 + {
895 + rates = get_current_wallet()->oracleRates();
896 + }
897 +
898 + int64_t *get_rate()
899 + {
900 + size_t size = rates.size();
901 + int64_t *havenRates = (int64_t *)malloc(size * sizeof(int64_t));
902 + int i = 0;
903 +
904 + for (auto const& rate : rates)
905 + {
906 + char *assetType = strdup(rate.first.c_str());
907 + HavenRate *havenRate = new HavenRate(assetType, rate.second);
908 + havenRates[i] = reinterpret_cast<int64_t>(havenRate);
909 + i++;
910 + }
911 +
912 + return havenRates;
913 + }
914 +
915 + int32_t size_of_rate()
916 + {
917 + return static_cast<int32_t>(rates.size());
918 + }
919 +
920 +#ifdef __cplusplus
921 +}
922 +#endif
cw_haven/ios/cw_haven.podspec new
+50
@@ -0,0 +1,50 @@
1 +#
2 +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
3 +# Run `pod lib lint cw_haven.podspec` to validate before publishing.
4 +#
5 +Pod::Spec.new do |s|
6 + s.name = 'cw_haven'
7 + s.version = '0.0.1'
8 + s.summary = 'Cake Wallet Haven'
9 + s.description = 'Cake Wallet wrapper over Haven project'
10 + s.homepage = 'http://cakewallet.com'
11 + s.license = { :file => '../LICENSE' }
12 + s.author = { 'Cake Wallet' => 'support@cakewallet.com' }
13 + s.source = { :path => '.' }
14 + s.source_files = 'Classes/**/*'
15 + s.public_header_files = 'Classes/**/*.h, Classes/*.h, ../shared_external/ios/libs/monero/include/src/**/*.h, ../shared_external/ios/libs/monero/include/contrib/**/*.h, ../shared_external/ios/libs/monero/include/../shared_external/ios/**/*.h'
16 + s.dependency 'Flutter'
17 + s.dependency 'cw_shared_external'
18 + s.platform = :ios, '10.0'
19 + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS' => 'arm64', 'ENABLE_BITCODE' => 'NO' }
20 + s.swift_version = '5.0'
21 + s.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/Classes/*.h" }
22 +
23 + s.subspec 'OpenSSL' do |openssl|
24 + openssl.preserve_paths = '../../../../../cw_shared_external/ios/External/ios/include/**/*.h'
25 + openssl.vendored_libraries = '../../../../../cw_shared_external/ios/External/ios/lib/libcrypto.a', '../../../../../cw_shared_external/ios/External/ios/lib/libssl.a'
26 + openssl.libraries = 'ssl', 'crypto'
27 + openssl.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
28 + end
29 +
30 + s.subspec 'Sodium' do |sodium|
31 + sodium.preserve_paths = '../../../../../cw_shared_external/ios/External/ios/include/**/*.h'
32 + sodium.vendored_libraries = '../../../../../cw_shared_external/ios/External/ios/lib/libsodium.a'
33 + sodium.libraries = 'sodium'
34 + sodium.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
35 + end
36 +
37 + s.subspec 'Boost' do |boost|
38 + boost.preserve_paths = '../../../../../cw_shared_external/ios/External/ios/include/**/*.h',
39 + boost.vendored_libraries = '../../../../../cw_shared_external/ios/External/ios/lib/libboost.a',
40 + boost.libraries = 'boost'
41 + boost.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
42 + end
43 +
44 + s.subspec 'Haven' do |haven|
45 + haven.preserve_paths = 'External/ios/include/**/*.h'
46 + haven.vendored_libraries = 'External/ios/lib/libhaven.a'
47 + haven.libraries = 'haven'
48 + haven.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include" }
49 + end
50 +end
cw_haven/lib/api/account_list.dart new
+83
@@ -0,0 +1,83 @@
1 +import 'dart:ffi';
2 +import 'package:ffi/ffi.dart';
3 +import 'package:cw_haven/api/signatures.dart';
4 +import 'package:cw_haven/api/types.dart';
5 +import 'package:cw_haven/api/haven_api.dart';
6 +import 'package:cw_haven/api/structs/account_row.dart';
7 +import 'package:flutter/foundation.dart';
8 +import 'package:cw_haven/api/wallet.dart';
9 +
10 +final accountSizeNative = havenApi
11 + .lookup<NativeFunction<account_size>>('account_size')
12 + .asFunction<SubaddressSize>();
13 +
14 +final accountRefreshNative = havenApi
15 + .lookup<NativeFunction<account_refresh>>('account_refresh')
16 + .asFunction<AccountRefresh>();
17 +
18 +final accountGetAllNative = havenApi
19 + .lookup<NativeFunction<account_get_all>>('account_get_all')
20 + .asFunction<AccountGetAll>();
21 +
22 +final accountAddNewNative = havenApi
23 + .lookup<NativeFunction<account_add_new>>('account_add_row')
24 + .asFunction<AccountAddNew>();
25 +
26 +final accountSetLabelNative = havenApi
27 + .lookup<NativeFunction<account_set_label>>('account_set_label_row')
28 + .asFunction<AccountSetLabel>();
29 +
30 +bool isUpdating = false;
31 +
32 +void refreshAccounts() {
33 + try {
34 + isUpdating = true;
35 + accountRefreshNative();
36 + isUpdating = false;
37 + } catch (e) {
38 + isUpdating = false;
39 + rethrow;
40 + }
41 +}
42 +
43 +List<AccountRow> getAllAccount() {
44 + final size = accountSizeNative();
45 + final accountAddressesPointer = accountGetAllNative();
46 + final accountAddresses = accountAddressesPointer.asTypedList(size);
47 +
48 + return accountAddresses
49 + .map((addr) => Pointer<AccountRow>.fromAddress(addr).ref)
50 + .toList();
51 +}
52 +
53 +void addAccountSync({String label}) {
54 + final labelPointer = Utf8.toUtf8(label);
55 + accountAddNewNative(labelPointer);
56 + free(labelPointer);
57 +}
58 +
59 +void setLabelForAccountSync({int accountIndex, String label}) {
60 + final labelPointer = Utf8.toUtf8(label);
61 + accountSetLabelNative(accountIndex, labelPointer);
62 + free(labelPointer);
63 +}
64 +
65 +void _addAccount(String label) => addAccountSync(label: label);
66 +
67 +void _setLabelForAccount(Map<String, dynamic> args) {
68 + final label = args['label'] as String;
69 + final accountIndex = args['accountIndex'] as int;
70 +
71 + setLabelForAccountSync(label: label, accountIndex: accountIndex);
72 +}
73 +
74 +Future<void> addAccount({String label}) async {
75 + await compute(_addAccount, label);
76 + await store();
77 +}
78 +
79 +Future<void> setLabelForAccount({int accountIndex, String label}) async {
80 + await compute(
81 + _setLabelForAccount, {'accountIndex': accountIndex, 'label': label});
82 + await store();
83 +}
\ No newline at end of file
cw_haven/lib/api/asset_types.dart new
+23
@@ -0,0 +1,23 @@
1 +import 'dart:ffi';
2 +import 'package:cw_haven/api/convert_utf8_to_string.dart';
3 +import 'package:cw_haven/api/signatures.dart';
4 +import 'package:cw_haven/api/types.dart';
5 +import 'package:cw_haven/api/haven_api.dart';
6 +import 'package:ffi/ffi.dart';
7 +
8 +final assetTypesSizeNative = havenApi
9 + .lookup<NativeFunction<account_size>>('asset_types_size')
10 + .asFunction<SubaddressSize>();
11 +
12 +final getAssetTypesNative = havenApi
13 + .lookup<NativeFunction<asset_types>>('asset_types')
14 + .asFunction<AssetTypes>();
15 +
16 +List<String> getAssetTypes() {
17 + List<String> assetTypes = [];
18 + Pointer<Pointer<Utf8>> assetTypePointers = getAssetTypesNative();
19 + Pointer<Utf8> assetpointer = assetTypePointers.elementAt(0)[0];
20 + String asset = convertUTF8ToString(pointer: assetpointer);
21 +
22 + return assetTypes;
23 +}
cw_haven/lib/api/balance_list.dart new
+58
@@ -0,0 +1,58 @@
1 +import 'dart:ffi';
2 +import 'package:cw_haven/api/signatures.dart';
3 +import 'package:cw_haven/api/types.dart';
4 +import 'package:cw_haven/api/haven_api.dart';
5 +import 'package:cw_haven/api/structs/haven_balance_row.dart';
6 +import 'package:cw_haven/api/structs/haven_rate.dart';
7 +import 'asset_types.dart';
8 +
9 +List<HavenBalanceRow> getHavenFullBalance({int accountIndex = 0}) {
10 + final size = assetTypesSizeNative();
11 + final balanceAddressesPointer = getHavenFullBalanceNative(accountIndex);
12 + final balanceAddresses = balanceAddressesPointer.asTypedList(size);
13 +
14 + return balanceAddresses
15 + .map((addr) => Pointer<HavenBalanceRow>.fromAddress(addr).ref)
16 + .toList();
17 +}
18 +
19 +List<HavenBalanceRow> getHavenUnlockedBalance({int accountIndex = 0}) {
20 + final size = assetTypesSizeNative();
21 + final balanceAddressesPointer = getHavenUnlockedBalanceNative(accountIndex);
22 + final balanceAddresses = balanceAddressesPointer.asTypedList(size);
23 +
24 + return balanceAddresses
25 + .map((addr) => Pointer<HavenBalanceRow>.fromAddress(addr).ref)
26 + .toList();
27 +}
28 +
29 +List<HavenRate> getRate() {
30 + updateRateNative();
31 + final size = sizeOfRateNative();
32 + final ratePointer = getRateNative();
33 + final rate = ratePointer.asTypedList(size);
34 +
35 + return rate
36 + .map((addr) => Pointer<HavenRate>.fromAddress(addr).ref)
37 + .toList();
38 +}
39 +
40 +final getHavenFullBalanceNative = havenApi
41 + .lookup<NativeFunction<get_full_balance>>('get_full_balance')
42 + .asFunction<GetHavenFullBalance>();
43 +
44 +final getHavenUnlockedBalanceNative = havenApi
45 + .lookup<NativeFunction<get_unlocked_balance>>('get_unlocked_balance')
46 + .asFunction<GetHavenUnlockedBalance>();
47 +
48 +final getRateNative = havenApi
49 + .lookup<NativeFunction<get_rate>>('get_rate')
50 + .asFunction<GetRate>();
51 +
52 +final sizeOfRateNative = havenApi
53 + .lookup<NativeFunction<size_of_rate>>('size_of_rate')
54 + .asFunction<SizeOfRate>();
55 +
56 +final updateRateNative = havenApi
57 + .lookup<NativeFunction<update_rate>>('update_rate')
58 + .asFunction<UpdateRate>();
\ No newline at end of file
cw_haven/lib/api/convert_utf8_to_string.dart new
+8
@@ -0,0 +1,8 @@
1 +import 'dart:ffi';
2 +import 'package:ffi/ffi.dart';
3 +
4 +String convertUTF8ToString({Pointer<Utf8> pointer}) {
5 + final str = Utf8.fromUtf8(pointer);
6 + free(pointer);
7 + return str;
8 +}
\ No newline at end of file
cw_haven/lib/api/cw_haven.dart new
+14
@@ -0,0 +1,14 @@
1 +
2 +import 'dart:async';
3 +
4 +import 'package:flutter/services.dart';
5 +
6 +class CwHaven {
7 + static const MethodChannel _channel =
8 + const MethodChannel('cw_haven');
9 +
10 + static Future<String> get platformVersion async {
11 + final String version = await _channel.invokeMethod('getPlatformVersion');
12 + return version;
13 + }
14 +}
cw_haven/lib/api/exceptions/connection_to_node_exception.dart new
+5
@@ -0,0 +1,5 @@
1 +class ConnectionToNodeException implements Exception {
2 + ConnectionToNodeException({this.message});
3 +
4 + final String message;
5 +}
\ No newline at end of file
cw_haven/lib/api/exceptions/creation_transaction_exception.dart new
+8
@@ -0,0 +1,8 @@
1 +class CreationTransactionException implements Exception {
2 + CreationTransactionException({this.message});
3 +
4 + final String message;
5 +
6 + @override
7 + String toString() => message;
8 +}
\ No newline at end of file
cw_haven/lib/api/exceptions/setup_wallet_exception.dart new
+5
@@ -0,0 +1,5 @@
1 +class SetupWalletException implements Exception {
2 + SetupWalletException({this.message});
3 +
4 + final String message;
5 +}
\ No newline at end of file
cw_haven/lib/api/exceptions/wallet_creation_exception.dart new
+8
@@ -0,0 +1,8 @@
1 +class WalletCreationException implements Exception {
2 + WalletCreationException({this.message});
3 +
4 + final String message;
5 +
6 + @override
7 + String toString() => message;
8 +}
\ No newline at end of file
cw_haven/lib/api/exceptions/wallet_opening_exception.dart new
+8
@@ -0,0 +1,8 @@
1 +class WalletOpeningException implements Exception {
2 + WalletOpeningException({this.message});
3 +
4 + final String message;
5 +
6 + @override
7 + String toString() => message;
8 +}
\ No newline at end of file
cw_haven/lib/api/exceptions/wallet_restore_from_keys_exception.dart new
+5
@@ -0,0 +1,5 @@
1 +class WalletRestoreFromKeysException implements Exception {
2 + WalletRestoreFromKeysException({this.message});
3 +
4 + final String message;
5 +}
\ No newline at end of file
cw_haven/lib/api/exceptions/wallet_restore_from_seed_exception.dart new
+5
@@ -0,0 +1,5 @@
1 +class WalletRestoreFromSeedException implements Exception {
2 + WalletRestoreFromSeedException({this.message});
3 +
4 + final String message;
5 +}
\ No newline at end of file
cw_haven/lib/api/haven_api.dart new
+6
@@ -0,0 +1,6 @@
1 +import 'dart:ffi';
2 +import 'dart:io';
3 +
4 +final DynamicLibrary havenApi = Platform.isAndroid
5 + ? DynamicLibrary.open("libcw_haven.so")
6 + : DynamicLibrary.open("cw_haven.framework/cw_haven");
\ No newline at end of file
cw_haven/lib/api/monero_output.dart new
+8
@@ -0,0 +1,8 @@
1 +import 'package:flutter/foundation.dart';
2 +
3 +class MoneroOutput {
4 + MoneroOutput({@required this.address, @required this.amount});
5 +
6 + final String address;
7 + final String amount;
8 +}
\ No newline at end of file
cw_haven/lib/api/signatures.dart new
+138
@@ -0,0 +1,138 @@
1 +import 'dart:ffi';
2 +import 'package:cw_haven/api/structs/pending_transaction.dart';
3 +import 'package:cw_haven/api/structs/ut8_box.dart';
4 +import 'package:ffi/ffi.dart';
5 +
6 +typedef create_wallet = Int8 Function(
7 + Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Pointer<Utf8>);
8 +
9 +typedef restore_wallet_from_seed = Int8 Function(
10 + Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Int64, Pointer<Utf8>);
11 +
12 +typedef restore_wallet_from_keys = Int8 Function(Pointer<Utf8>, Pointer<Utf8>,
13 + Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Int64, Pointer<Utf8>);
14 +
15 +typedef is_wallet_exist = Int8 Function(Pointer<Utf8>);
16 +
17 +typedef load_wallet = Int8 Function(Pointer<Utf8>, Pointer<Utf8>, Int8);
18 +
19 +typedef error_string = Pointer<Utf8> Function();
20 +
21 +typedef get_filename = Pointer<Utf8> Function();
22 +
23 +typedef get_seed = Pointer<Utf8> Function();
24 +
25 +typedef get_address = Pointer<Utf8> Function(Int32, Int32);
26 +
27 +typedef get_full_balance = Pointer<Int64> Function(Int32);
28 +
29 +typedef get_unlocked_balance = Pointer<Int64> Function(Int32);
30 +
31 +typedef get_full_balanace = Int64 Function(Int32);
32 +
33 +typedef get_unlocked_balanace = Int64 Function(Int32);
34 +
35 +typedef get_current_height = Int64 Function();
36 +
37 +typedef get_node_height = Int64 Function();
38 +
39 +typedef is_connected = Int8 Function();
40 +
41 +typedef setup_node = Int8 Function(
42 + Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int8, Int8, Pointer<Utf8>);
43 +
44 +typedef start_refresh = Void Function();
45 +
46 +typedef connect_to_node = Int8 Function();
47 +
48 +typedef set_refresh_from_block_height = Void Function(Int64);
49 +
50 +typedef set_recovering_from_seed = Void Function(Int8);
51 +
52 +typedef store_c = Void Function(Pointer<Utf8>);
53 +
54 +typedef set_listener = Void Function();
55 +
56 +typedef get_syncing_height = Int64 Function();
57 +
58 +typedef is_needed_to_refresh = Int8 Function();
59 +
60 +typedef is_new_transaction_exist = Int8 Function();
61 +
62 +typedef subaddrress_size = Int32 Function();
63 +
64 +typedef subaddrress_refresh = Void Function(Int32);
65 +
66 +typedef subaddress_get_all = Pointer<Int64> Function();
67 +
68 +typedef subaddress_add_new = Void Function(
69 + Int32 accountIndex, Pointer<Utf8> label);
70 +
71 +typedef subaddress_set_label = Void Function(
72 + Int32 accountIndex, Int32 addressIndex, Pointer<Utf8> label);
73 +
74 +typedef account_size = Int32 Function();
75 +
76 +typedef account_refresh = Void Function();
77 +
78 +typedef account_get_all = Pointer<Int64> Function();
79 +
80 +typedef account_add_new = Void Function(Pointer<Utf8> label);
81 +
82 +typedef account_set_label = Void Function(
83 + Int32 accountIndex, Pointer<Utf8> label);
84 +
85 +typedef transactions_refresh = Void Function();
86 +
87 +typedef get_tx_key = Pointer<Utf8> Function(Pointer<Utf8> txId);
88 +
89 +typedef transactions_count = Int64 Function();
90 +
91 +typedef transactions_get_all = Pointer<Int64> Function();
92 +
93 +typedef transaction_create = Int8 Function(
94 + Pointer<Utf8> address,
95 + Pointer<Utf8> assetType,
96 + Pointer<Utf8> paymentId,
97 + Pointer<Utf8> amount,
98 + Int8 priorityRaw,
99 + Int32 subaddrAccount,
100 + Pointer<Utf8Box> error,
101 + Pointer<PendingTransactionRaw> pendingTransaction);
102 +
103 +typedef transaction_create_mult_dest = Int8 Function(
104 + Pointer<Pointer<Utf8>> addresses,
105 + Pointer<Utf8> assetType,
106 + Pointer<Utf8> paymentId,
107 + Pointer<Pointer<Utf8>> amounts,
108 + Int32 size,
109 + Int8 priorityRaw,
110 + Int32 subaddrAccount,
111 + Pointer<Utf8Box> error,
112 + Pointer<PendingTransactionRaw> pendingTransaction);
113 +
114 +typedef transaction_commit = Int8 Function(Pointer<PendingTransactionRaw>, Pointer<Utf8Box>);
115 +
116 +typedef secret_view_key = Pointer<Utf8> Function();
117 +
118 +typedef public_view_key = Pointer<Utf8> Function();
119 +
120 +typedef secret_spend_key = Pointer<Utf8> Function();
121 +
122 +typedef public_spend_key = Pointer<Utf8> Function();
123 +
124 +typedef close_current_wallet = Void Function();
125 +
126 +typedef on_startup = Void Function();
127 +
128 +typedef rescan_blockchain = Void Function();
129 +
130 +typedef asset_types = Pointer<Pointer<Utf8>> Function();
131 +
132 +typedef asset_types_size = Int32 Function();
133 +
134 +typedef get_rate = Pointer<Int64> Function();
135 +
136 +typedef size_of_rate = Int32 Function();
137 +
138 +typedef update_rate = Void Function();
\ No newline at end of file
cw_haven/lib/api/structs/account_row.dart new
+11
@@ -0,0 +1,11 @@
1 +import 'dart:ffi';
2 +import 'package:ffi/ffi.dart';
3 +
4 +class AccountRow extends Struct {
5 + @Int64()
6 + int id;
7 + Pointer<Utf8> label;
8 +
9 + String getLabel() => Utf8.fromUtf8(label);
10 + int getId() => id;
11 +}
cw_haven/lib/api/structs/haven_balance_row.dart new
+11
@@ -0,0 +1,11 @@
1 +import 'dart:ffi';
2 +import 'package:ffi/ffi.dart';
3 +
4 +class HavenBalanceRow extends Struct {
5 + @Int64()
6 + int amount;
7 + Pointer<Utf8> assetType;
8 +
9 + int getAmount() => amount;
10 + String getAssetType() => Utf8.fromUtf8(assetType);
11 +}
cw_haven/lib/api/structs/haven_rate.dart new
+11
@@ -0,0 +1,11 @@
1 +import 'dart:ffi';
2 +import 'package:ffi/ffi.dart';
3 +
4 +class HavenRate extends Struct {
5 + @Int64()
6 + int rate;
7 + Pointer<Utf8> assetType;
8 +
9 + int getRate() => rate;
10 + String getAssetType() => Utf8.fromUtf8(assetType);
11 +}
cw_haven/lib/api/structs/pending_transaction.dart new
+23
@@ -0,0 +1,23 @@
1 +import 'dart:ffi';
2 +import 'package:ffi/ffi.dart';
3 +
4 +class PendingTransactionRaw extends Struct {
5 + @Int64()
6 + int amount;
7 +
8 + @Int64()
9 + int fee;
10 +
11 + Pointer<Utf8> hash;
12 +
13 + String getHash() => Utf8.fromUtf8(hash);
14 +}
15 +
16 +class PendingTransactionDescription {
17 + PendingTransactionDescription({this.amount, this.fee, this.hash, this.pointerAddress});
18 +
19 + final int amount;
20 + final int fee;
21 + final String hash;
22 + final int pointerAddress;
23 +}
\ No newline at end of file
cw_haven/lib/api/structs/subaddress_row.dart new
+13
@@ -0,0 +1,13 @@
1 +import 'dart:ffi';
2 +import 'package:ffi/ffi.dart';
3 +
4 +class SubaddressRow extends Struct {
5 + @Int64()
6 + int id;
7 + Pointer<Utf8> address;
8 + Pointer<Utf8> label;
9 +
10 + String getLabel() => Utf8.fromUtf8(label);
11 + String getAddress() => Utf8.fromUtf8(address);
12 + int getId() => id;
13 +}
\ No newline at end of file
cw_haven/lib/api/structs/transaction_info_row.dart new
+44
@@ -0,0 +1,44 @@
1 +import 'dart:ffi';
2 +import 'package:ffi/ffi.dart';
3 +
4 +class TransactionInfoRow extends Struct {
5 + @Uint64()
6 + int amount;
7 +
8 + @Uint64()
9 + int fee;
10 +
11 + @Uint64()
12 + int blockHeight;
13 +
14 + @Uint64()
15 + int confirmations;
16 +
17 + @Uint32()
18 + int subaddrAccount;
19 +
20 + @Int8()
21 + int direction;
22 +
23 + @Int8()
24 + int isPending;
25 +
26 + @Uint32()
27 + int subaddrIndex;
28 +
29 + Pointer<Utf8> hash;
30 +
31 + Pointer<Utf8> paymentId;
32 +
33 + Pointer<Utf8> assetType;
34 +
35 + @Int64()
36 + int datetime;
37 +
38 + int getDatetime() => datetime;
39 + int getAmount() => amount >= 0 ? amount : amount * -1;
40 + bool getIsPending() => isPending != 0;
41 + String getHash() => Utf8.fromUtf8(hash);
42 + String getPaymentId() => Utf8.fromUtf8(paymentId);
43 + String getAssetType() => Utf8.fromUtf8(assetType);
44 +}
cw_haven/lib/api/structs/ut8_box.dart new
+8
@@ -0,0 +1,8 @@
1 +import 'dart:ffi';
2 +import 'package:ffi/ffi.dart';
3 +
4 +class Utf8Box extends Struct {
5 + Pointer<Utf8> value;
6 +
7 + String getValue() => Utf8.fromUtf8(value);
8 +}
cw_haven/lib/api/subaddress_list.dart new
+97
@@ -0,0 +1,97 @@
1 +import 'dart:ffi';
2 +import 'package:ffi/ffi.dart';
3 +import 'package:flutter/foundation.dart';
4 +import 'package:cw_haven/api/signatures.dart';
5 +import 'package:cw_haven/api/types.dart';
6 +import 'package:cw_haven/api/haven_api.dart';
7 +import 'package:cw_haven/api/structs/subaddress_row.dart';
8 +import 'package:cw_haven/api/wallet.dart';
9 +
10 +final subaddressSizeNative = havenApi
11 + .lookup<NativeFunction<subaddrress_size>>('subaddrress_size')
12 + .asFunction<SubaddressSize>();
13 +
14 +final subaddressRefreshNative = havenApi
15 + .lookup<NativeFunction<subaddrress_refresh>>('subaddress_refresh')
16 + .asFunction<SubaddressRefresh>();
17 +
18 +final subaddrressGetAllNative = havenApi
19 + .lookup<NativeFunction<subaddress_get_all>>('subaddrress_get_all')
20 + .asFunction<SubaddressGetAll>();
21 +
22 +final subaddrressAddNewNative = havenApi
23 + .lookup<NativeFunction<subaddress_add_new>>('subaddress_add_row')
24 + .asFunction<SubaddressAddNew>();
25 +
26 +final subaddrressSetLabelNative = havenApi
27 + .lookup<NativeFunction<subaddress_set_label>>('subaddress_set_label')
28 + .asFunction<SubaddressSetLabel>();
29 +
30 +bool isUpdating = false;
31 +
32 +void refreshSubaddresses({@required int accountIndex}) {
33 + try {
34 + isUpdating = true;
35 + subaddressRefreshNative(accountIndex);
36 + isUpdating = false;
37 + } catch (e) {
38 + isUpdating = false;
39 + rethrow;
40 + }
41 +}
42 +
43 +List<SubaddressRow> getAllSubaddresses() {
44 + final size = subaddressSizeNative();
45 + final subaddressAddressesPointer = subaddrressGetAllNative();
46 + final subaddressAddresses = subaddressAddressesPointer.asTypedList(size);
47 +
48 + return subaddressAddresses
49 + .map((addr) => Pointer<SubaddressRow>.fromAddress(addr).ref)
50 + .toList();
51 +}
52 +
53 +void addSubaddressSync({int accountIndex, String label}) {
54 + final labelPointer = Utf8.toUtf8(label);
55 + subaddrressAddNewNative(accountIndex, labelPointer);
56 + free(labelPointer);
57 +}
58 +
59 +void setLabelForSubaddressSync(
60 + {int accountIndex, int addressIndex, String label}) {
61 + final labelPointer = Utf8.toUtf8(label);
62 +
63 + subaddrressSetLabelNative(accountIndex, addressIndex, labelPointer);
64 + free(labelPointer);
65 +}
66 +
67 +void _addSubaddress(Map<String, dynamic> args) {
68 + final label = args['label'] as String;
69 + final accountIndex = args['accountIndex'] as int;
70 +
71 + addSubaddressSync(accountIndex: accountIndex, label: label);
72 +}
73 +
74 +void _setLabelForSubaddress(Map<String, dynamic> args) {
75 + final label = args['label'] as String;
76 + final accountIndex = args['accountIndex'] as int;
77 + final addressIndex = args['addressIndex'] as int;
78 +
79 + setLabelForSubaddressSync(
80 + accountIndex: accountIndex, addressIndex: addressIndex, label: label);
81 +}
82 +
83 +Future addSubaddress({int accountIndex, String label}) async {
84 + await compute<Map<String, Object>, void>(
85 + _addSubaddress, {'accountIndex': accountIndex, 'label': label});
86 + await store();
87 +}
88 +
89 +Future setLabelForSubaddress(
90 + {int accountIndex, int addressIndex, String label}) async {
91 + await compute<Map<String, Object>, void>(_setLabelForSubaddress, {
92 + 'accountIndex': accountIndex,
93 + 'addressIndex': addressIndex,
94 + 'label': label
95 + });
96 + await store();
97 +}
cw_haven/lib/api/transaction_history.dart new
+246
@@ -0,0 +1,246 @@
1 +import 'dart:ffi';
2 +import 'package:cw_haven/api/convert_utf8_to_string.dart';
3 +import 'package:cw_haven/api/monero_output.dart';
4 +import 'package:cw_haven/api/structs/ut8_box.dart';
5 +import 'package:ffi/ffi.dart';
6 +import 'package:flutter/foundation.dart';
7 +import 'package:cw_haven/api/signatures.dart';
8 +import 'package:cw_haven/api/types.dart';
9 +import 'package:cw_haven/api/haven_api.dart';
10 +import 'package:cw_haven/api/structs/transaction_info_row.dart';
11 +import 'package:cw_haven/api/structs/pending_transaction.dart';
12 +import 'package:cw_haven/api/exceptions/creation_transaction_exception.dart';
13 +
14 +final transactionsRefreshNative = havenApi
15 + .lookup<NativeFunction<transactions_refresh>>('transactions_refresh')
16 + .asFunction<TransactionsRefresh>();
17 +
18 +final transactionsCountNative = havenApi
19 + .lookup<NativeFunction<transactions_count>>('transactions_count')
20 + .asFunction<TransactionsCount>();
21 +
22 +final transactionsGetAllNative = havenApi
23 + .lookup<NativeFunction<transactions_get_all>>('transactions_get_all')
24 + .asFunction<TransactionsGetAll>();
25 +
26 +final transactionCreateNative = havenApi
27 + .lookup<NativeFunction<transaction_create>>('transaction_create')
28 + .asFunction<TransactionCreate>();
29 +
30 +final transactionCreateMultDestNative = havenApi
31 + .lookup<NativeFunction<transaction_create_mult_dest>>('transaction_create_mult_dest')
32 + .asFunction<TransactionCreateMultDest>();
33 +
34 +final transactionCommitNative = havenApi
35 + .lookup<NativeFunction<transaction_commit>>('transaction_commit')
36 + .asFunction<TransactionCommit>();
37 +
38 +final getTxKeyNative = havenApi
39 + .lookup<NativeFunction<get_tx_key>>('get_tx_key')
40 + .asFunction<GetTxKey>();
41 +
42 +String getTxKey(String txId) {
43 + final txIdPointer = Utf8.toUtf8(txId);
44 + final keyPointer = getTxKeyNative(txIdPointer);
45 +
46 + free(txIdPointer);
47 +
48 + if (keyPointer != null) {
49 + return convertUTF8ToString(pointer: keyPointer);
50 + }
51 +
52 + return null;
53 +}
54 +
55 +void refreshTransactions() => transactionsRefreshNative();
56 +
57 +int countOfTransactions() => transactionsCountNative();
58 +
59 +List<TransactionInfoRow> getAllTransations() {
60 + final size = transactionsCountNative();
61 + final transactionsPointer = transactionsGetAllNative();
62 + final transactionsAddresses = transactionsPointer.asTypedList(size);
63 +
64 + return transactionsAddresses
65 + .map((addr) => Pointer<TransactionInfoRow>.fromAddress(addr).ref)
66 + .toList();
67 +}
68 +
69 +PendingTransactionDescription createTransactionSync(
70 + {String address,
71 + String assetType,
72 + String paymentId,
73 + String amount,
74 + int priorityRaw,
75 + int accountIndex = 0}) {
76 + final addressPointer = Utf8.toUtf8(address);
77 + final assetTypePointer = Utf8.toUtf8(assetType);
78 + final paymentIdPointer = Utf8.toUtf8(paymentId);
79 + final amountPointer = amount != null ? Utf8.toUtf8(amount) : nullptr;
80 + final errorMessagePointer = allocate<Utf8Box>();
81 + final pendingTransactionRawPointer = allocate<PendingTransactionRaw>();
82 + final created = transactionCreateNative(
83 + addressPointer,
84 + assetTypePointer,
85 + paymentIdPointer,
86 + amountPointer,
87 + priorityRaw,
88 + accountIndex,
89 + errorMessagePointer,
90 + pendingTransactionRawPointer) !=
91 + 0;
92 +
93 + free(addressPointer);
94 + free(assetTypePointer);
95 + free(paymentIdPointer);
96 +
97 + if (amountPointer != nullptr) {
98 + free(amountPointer);
99 + }
100 +
101 + if (!created) {
102 + final message = errorMessagePointer.ref.getValue();
103 + free(errorMessagePointer);
104 + throw CreationTransactionException(message: message);
105 + }
106 +
107 + return PendingTransactionDescription(
108 + amount: pendingTransactionRawPointer.ref.amount,
109 + fee: pendingTransactionRawPointer.ref.fee,
110 + hash: pendingTransactionRawPointer.ref.getHash(),
111 + pointerAddress: pendingTransactionRawPointer.address);
112 +}
113 +
114 +PendingTransactionDescription createTransactionMultDestSync(
115 + {List<MoneroOutput> outputs,
116 + String assetType,
117 + String paymentId,
118 + int priorityRaw,
119 + int accountIndex = 0}) {
120 + final int size = outputs.length;
121 + final List<Pointer<Utf8>> addressesPointers = outputs.map((output) =>
122 + Utf8.toUtf8(output.address)).toList();
123 + final Pointer<Pointer<Utf8>> addressesPointerPointer = allocate(count: size);
124 + final List<Pointer<Utf8>> amountsPointers = outputs.map((output) =>
125 + Utf8.toUtf8(output.amount)).toList();
126 + final Pointer<Pointer<Utf8>> amountsPointerPointer = allocate(count: size);
127 +
128 + for (int i = 0; i < size; i++) {
129 + addressesPointerPointer[i] = addressesPointers[i];
130 + amountsPointerPointer[i] = amountsPointers[i];
131 + }
132 +
133 + final assetTypePointer = Utf8.toUtf8(assetType);
134 + final paymentIdPointer = Utf8.toUtf8(paymentId);
135 + final errorMessagePointer = allocate<Utf8Box>();
136 + final pendingTransactionRawPointer = allocate<PendingTransactionRaw>();
137 + final created = transactionCreateMultDestNative(
138 + addressesPointerPointer,
139 + assetTypePointer,
140 + paymentIdPointer,
141 + amountsPointerPointer,
142 + size,
143 + priorityRaw,
144 + accountIndex,
145 + errorMessagePointer,
146 + pendingTransactionRawPointer) !=
147 + 0;
148 +
149 + free(addressesPointerPointer);
150 + free(assetTypePointer);
151 + free(amountsPointerPointer);
152 +
153 + addressesPointers.forEach((element) => free(element));
154 + amountsPointers.forEach((element) => free(element));
155 +
156 + free(paymentIdPointer);
157 +
158 + if (!created) {
159 + final message = errorMessagePointer.ref.getValue();
160 + free(errorMessagePointer);
161 + throw CreationTransactionException(message: message);
162 + }
163 +
164 + return PendingTransactionDescription(
165 + amount: pendingTransactionRawPointer.ref.amount,
166 + fee: pendingTransactionRawPointer.ref.fee,
167 + hash: pendingTransactionRawPointer.ref.getHash(),
168 + pointerAddress: pendingTransactionRawPointer.address);
169 +}
170 +
171 +void commitTransactionFromPointerAddress({int address}) => commitTransaction(
172 + transactionPointer: Pointer<PendingTransactionRaw>.fromAddress(address));
173 +
174 +void commitTransaction({Pointer<PendingTransactionRaw> transactionPointer}) {
175 + final errorMessagePointer = allocate<Utf8Box>();
176 + final isCommited =
177 + transactionCommitNative(transactionPointer, errorMessagePointer) != 0;
178 +
179 + if (!isCommited) {
180 + final message = errorMessagePointer.ref.getValue();
181 + free(errorMessagePointer);
182 + throw CreationTransactionException(message: message);
183 + }
184 +}
185 +
186 +PendingTransactionDescription _createTransactionSync(Map args) {
187 + final address = args['address'] as String;
188 + final assetType = args['assetType'] as String;
189 + final paymentId = args['paymentId'] as String;
190 + final amount = args['amount'] as String;
191 + final priorityRaw = args['priorityRaw'] as int;
192 + final accountIndex = args['accountIndex'] as int;
193 +
194 + return createTransactionSync(
195 + address: address,
196 + assetType: assetType,
197 + paymentId: paymentId,
198 + amount: amount,
199 + priorityRaw: priorityRaw,
200 + accountIndex: accountIndex);
201 +}
202 +
203 +PendingTransactionDescription _createTransactionMultDestSync(Map args) {
204 + final outputs = args['outputs'] as List<MoneroOutput>;
205 + final assetType = args['assetType'] as String;
206 + final paymentId = args['paymentId'] as String;
207 + final priorityRaw = args['priorityRaw'] as int;
208 + final accountIndex = args['accountIndex'] as int;
209 +
210 + return createTransactionMultDestSync(
211 + outputs: outputs,
212 + assetType: assetType,
213 + paymentId: paymentId,
214 + priorityRaw: priorityRaw,
215 + accountIndex: accountIndex);
216 +}
217 +
218 +Future<PendingTransactionDescription> createTransaction(
219 + {String address,
220 + String assetType,
221 + String paymentId = '',
222 + String amount,
223 + int priorityRaw,
224 + int accountIndex = 0}) =>
225 + compute(_createTransactionSync, {
226 + 'address': address,
227 + 'assetType': assetType,
228 + 'paymentId': paymentId,
229 + 'amount': amount,
230 + 'priorityRaw': priorityRaw,
231 + 'accountIndex': accountIndex
232 + });
233 +
234 +Future<PendingTransactionDescription> createTransactionMultDest(
235 + {List<MoneroOutput> outputs,
236 + String assetType,
237 + String paymentId = '',
238 + int priorityRaw,
239 + int accountIndex = 0}) =>
240 + compute(_createTransactionMultDestSync, {
241 + 'outputs': outputs,
242 + 'assetType': assetType,
243 + 'paymentId': paymentId,
244 + 'priorityRaw': priorityRaw,
245 + 'accountIndex': accountIndex
246 + });
cw_haven/lib/api/types.dart new
+136
@@ -0,0 +1,136 @@
1 +import 'dart:ffi';
2 +import 'package:cw_haven/api/structs/pending_transaction.dart';
3 +import 'package:cw_haven/api/structs/ut8_box.dart';
4 +import 'package:ffi/ffi.dart';
5 +
6 +typedef CreateWallet = int Function(
7 + Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, int, Pointer<Utf8>);
8 +
9 +typedef RestoreWalletFromSeed = int Function(
10 + Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, int, int, Pointer<Utf8>);
11 +
12 +typedef RestoreWalletFromKeys = int Function(Pointer<Utf8>, Pointer<Utf8>,
13 + Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, int, int, Pointer<Utf8>);
14 +
15 +typedef IsWalletExist = int Function(Pointer<Utf8>);
16 +
17 +typedef LoadWallet = int Function(Pointer<Utf8>, Pointer<Utf8>, int);
18 +
19 +typedef ErrorString = Pointer<Utf8> Function();
20 +
21 +typedef GetFilename = Pointer<Utf8> Function();
22 +
23 +typedef GetSeed = Pointer<Utf8> Function();
24 +
25 +typedef GetAddress = Pointer<Utf8> Function(int, int);
26 +
27 +typedef GetHavenFullBalance = Pointer<Int64> Function(int);
28 +
29 +typedef GetHavenUnlockedBalance = Pointer<Int64> Function(int);
30 +
31 +typedef GetFullBalance = int Function(int);
32 +
33 +typedef GetUnlockedBalance = int Function(int);
34 +
35 +typedef GetCurrentHeight = int Function();
36 +
37 +typedef GetNodeHeight = int Function();
38 +
39 +typedef IsConnected = int Function();
40 +
41 +typedef SetupNode = int Function(
42 + Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, int, int, Pointer<Utf8>);
43 +
44 +typedef StartRefresh = void Function();
45 +
46 +typedef ConnectToNode = int Function();
47 +
48 +typedef SetRefreshFromBlockHeight = void Function(int);
49 +
50 +typedef SetRecoveringFromSeed = void Function(int);
51 +
52 +typedef Store = void Function(Pointer<Utf8>);
53 +
54 +typedef SetListener = void Function();
55 +
56 +typedef GetSyncingHeight = int Function();
57 +
58 +typedef IsNeededToRefresh = int Function();
59 +
60 +typedef IsNewTransactionExist = int Function();
61 +
62 +typedef SubaddressSize = int Function();
63 +
64 +typedef SubaddressRefresh = void Function(int);
65 +
66 +typedef SubaddressGetAll = Pointer<Int64> Function();
67 +
68 +typedef SubaddressAddNew = void Function(int accountIndex, Pointer<Utf8> label);
69 +
70 +typedef SubaddressSetLabel = void Function(
71 + int accountIndex, int addressIndex, Pointer<Utf8> label);
72 +
73 +typedef AccountSize = int Function();
74 +
75 +typedef AccountRefresh = void Function();
76 +
77 +typedef AccountGetAll = Pointer<Int64> Function();
78 +
79 +typedef AccountAddNew = void Function(Pointer<Utf8> label);
80 +
81 +typedef AccountSetLabel = void Function(int accountIndex, Pointer<Utf8> label);
82 +
83 +typedef TransactionsRefresh = void Function();
84 +
85 +typedef GetTxKey = Pointer<Utf8> Function(Pointer<Utf8> txId);
86 +
87 +typedef TransactionsCount = int Function();
88 +
89 +typedef TransactionsGetAll = Pointer<Int64> Function();
90 +
91 +typedef TransactionCreate = int Function(
92 + Pointer<Utf8> address,
93 + Pointer<Utf8> assetType,
94 + Pointer<Utf8> paymentId,
95 + Pointer<Utf8> amount,
96 + int priorityRaw,
97 + int subaddrAccount,
98 + Pointer<Utf8Box> error,
99 + Pointer<PendingTransactionRaw> pendingTransaction);
100 +
101 +typedef TransactionCreateMultDest = int Function(
102 + Pointer<Pointer<Utf8>> addresses,
103 + Pointer<Utf8> assetType,
104 + Pointer<Utf8> paymentId,
105 + Pointer<Pointer<Utf8>> amounts,
106 + int size,
107 + int priorityRaw,
108 + int subaddrAccount,
109 + Pointer<Utf8Box> error,
110 + Pointer<PendingTransactionRaw> pendingTransaction);
111 +
112 +typedef TransactionCommit = int Function(Pointer<PendingTransactionRaw>, Pointer<Utf8Box>);
113 +
114 +typedef SecretViewKey = Pointer<Utf8> Function();
115 +
116 +typedef PublicViewKey = Pointer<Utf8> Function();
117 +
118 +typedef SecretSpendKey = Pointer<Utf8> Function();
119 +
120 +typedef PublicSpendKey = Pointer<Utf8> Function();
121 +
122 +typedef CloseCurrentWallet = void Function();
123 +
124 +typedef OnStartup = void Function();
125 +
126 +typedef RescanBlockchainAsync = void Function();
127 +
128 +typedef AssetTypes = Pointer<Pointer<Utf8>> Function();
129 +
130 +typedef AssetTypesSize = int Function();
131 +
132 +typedef GetRate = Pointer<Int64> Function();
133 +
134 +typedef SizeOfRate = int Function();
135 +
136 +typedef UpdateRate = void Function();
\ No newline at end of file
cw_haven/lib/api/wallet.dart new
+329
@@ -0,0 +1,329 @@
1 +import 'dart:async';
2 +import 'dart:ffi';
3 +import 'package:ffi/ffi.dart';
4 +import 'package:cw_haven/api/convert_utf8_to_string.dart';
5 +import 'package:cw_haven/api/signatures.dart';
6 +import 'package:cw_haven/api/types.dart';
7 +import 'package:cw_haven/api/haven_api.dart';
8 +import 'package:cw_haven/api/exceptions/setup_wallet_exception.dart';
9 +import 'package:flutter/foundation.dart';
10 +import 'package:flutter/services.dart';
11 +
12 +int _boolToInt(bool value) => value ? 1 : 0;
13 +
14 +final getFileNameNative = havenApi
15 + .lookup<NativeFunction<get_filename>>('get_filename')
16 + .asFunction<GetFilename>();
17 +
18 +final getSeedNative =
19 + havenApi.lookup<NativeFunction<get_seed>>('seed').asFunction<GetSeed>();
20 +
21 +final getAddressNative = havenApi
22 + .lookup<NativeFunction<get_address>>('get_address')
23 + .asFunction<GetAddress>();
24 +
25 +final getFullBalanceNative = havenApi
26 + .lookup<NativeFunction<get_full_balanace>>('get_full_balance')
27 + .asFunction<GetFullBalance>();
28 +
29 +final getUnlockedBalanceNative = havenApi
30 + .lookup<NativeFunction<get_unlocked_balanace>>('get_unlocked_balance')
31 + .asFunction<GetUnlockedBalance>();
32 +
33 +final getCurrentHeightNative = havenApi
34 + .lookup<NativeFunction<get_current_height>>('get_current_height')
35 + .asFunction<GetCurrentHeight>();
36 +
37 +final getNodeHeightNative = havenApi
38 + .lookup<NativeFunction<get_node_height>>('get_node_height')
39 + .asFunction<GetNodeHeight>();
40 +
41 +final isConnectedNative = havenApi
42 + .lookup<NativeFunction<is_connected>>('is_connected')
43 + .asFunction<IsConnected>();
44 +
45 +final setupNodeNative = havenApi
46 + .lookup<NativeFunction<setup_node>>('setup_node')
47 + .asFunction<SetupNode>();
48 +
49 +final startRefreshNative = havenApi
50 + .lookup<NativeFunction<start_refresh>>('start_refresh')
51 + .asFunction<StartRefresh>();
52 +
53 +final connecToNodeNative = havenApi
54 + .lookup<NativeFunction<connect_to_node>>('connect_to_node')
55 + .asFunction<ConnectToNode>();
56 +
57 +final setRefreshFromBlockHeightNative = havenApi
58 + .lookup<NativeFunction<set_refresh_from_block_height>>(
59 + 'set_refresh_from_block_height')
60 + .asFunction<SetRefreshFromBlockHeight>();
61 +
62 +final setRecoveringFromSeedNative = havenApi
63 + .lookup<NativeFunction<set_recovering_from_seed>>(
64 + 'set_recovering_from_seed')
65 + .asFunction<SetRecoveringFromSeed>();
66 +
67 +final storeNative =
68 + havenApi.lookup<NativeFunction<store_c>>('store').asFunction<Store>();
69 +
70 +final setListenerNative = havenApi
71 + .lookup<NativeFunction<set_listener>>('set_listener')
72 + .asFunction<SetListener>();
73 +
74 +final getSyncingHeightNative = havenApi
75 + .lookup<NativeFunction<get_syncing_height>>('get_syncing_height')
76 + .asFunction<GetSyncingHeight>();
77 +
78 +final isNeededToRefreshNative = havenApi
79 + .lookup<NativeFunction<is_needed_to_refresh>>('is_needed_to_refresh')
80 + .asFunction<IsNeededToRefresh>();
81 +
82 +final isNewTransactionExistNative = havenApi
83 + .lookup<NativeFunction<is_new_transaction_exist>>(
84 + 'is_new_transaction_exist')
85 + .asFunction<IsNewTransactionExist>();
86 +
87 +final getSecretViewKeyNative = havenApi
88 + .lookup<NativeFunction<secret_view_key>>('secret_view_key')
89 + .asFunction<SecretViewKey>();
90 +
91 +final getPublicViewKeyNative = havenApi
92 + .lookup<NativeFunction<public_view_key>>('public_view_key')
93 + .asFunction<PublicViewKey>();
94 +
95 +final getSecretSpendKeyNative = havenApi
96 + .lookup<NativeFunction<secret_spend_key>>('secret_spend_key')
97 + .asFunction<SecretSpendKey>();
98 +
99 +final getPublicSpendKeyNative = havenApi
100 + .lookup<NativeFunction<secret_view_key>>('public_spend_key')
101 + .asFunction<PublicSpendKey>();
102 +
103 +final closeCurrentWalletNative = havenApi
104 + .lookup<NativeFunction<close_current_wallet>>('close_current_wallet')
105 + .asFunction<CloseCurrentWallet>();
106 +
107 +final onStartupNative = havenApi
108 + .lookup<NativeFunction<on_startup>>('on_startup')
109 + .asFunction<OnStartup>();
110 +
111 +final rescanBlockchainAsyncNative = havenApi
112 + .lookup<NativeFunction<rescan_blockchain>>('rescan_blockchain')
113 + .asFunction<RescanBlockchainAsync>();
114 +
115 +int getSyncingHeight() => getSyncingHeightNative();
116 +
117 +bool isNeededToRefresh() => isNeededToRefreshNative() != 0;
118 +
119 +bool isNewTransactionExist() => isNewTransactionExistNative() != 0;
120 +
121 +String getFilename() => convertUTF8ToString(pointer: getFileNameNative());
122 +
123 +String getSeed() => convertUTF8ToString(pointer: getSeedNative());
124 +
125 +String getAddress({int accountIndex = 0, int addressIndex = 0}) =>
126 + convertUTF8ToString(pointer: getAddressNative(accountIndex, addressIndex));
127 +
128 +int getFullBalance({int accountIndex = 0}) =>
129 + getFullBalanceNative(accountIndex);
130 +
131 +int getUnlockedBalance({int accountIndex = 0}) =>
132 + getUnlockedBalanceNative(accountIndex);
133 +
134 +int getCurrentHeight() => getCurrentHeightNative();
135 +
136 +int getNodeHeightSync() => getNodeHeightNative();
137 +
138 +bool isConnectedSync() => isConnectedNative() != 0;
139 +
140 +bool setupNodeSync(
141 + {String address,
142 + String login,
143 + String password,
144 + bool useSSL = false,
145 + bool isLightWallet = false}) {
146 + final addressPointer = Utf8.toUtf8(address);
147 + Pointer<Utf8> loginPointer;
148 + Pointer<Utf8> passwordPointer;
149 +
150 + if (login != null) {
151 + loginPointer = Utf8.toUtf8(login);
152 + }
153 +
154 + if (password != null) {
155 + passwordPointer = Utf8.toUtf8(password);
156 + }
157 +
158 + final errorMessagePointer = allocate<Utf8>();
159 + final isSetupNode = setupNodeNative(
160 + addressPointer,
161 + loginPointer,
162 + passwordPointer,
163 + _boolToInt(useSSL),
164 + _boolToInt(isLightWallet),
165 + errorMessagePointer) !=
166 + 0;
167 +
168 + free(addressPointer);
169 + free(loginPointer);
170 + free(passwordPointer);
171 +
172 + if (!isSetupNode) {
173 + throw SetupWalletException(
174 + message: convertUTF8ToString(pointer: errorMessagePointer));
175 + }
176 +
177 + return isSetupNode;
178 +}
179 +
180 +void startRefreshSync() => startRefreshNative();
181 +
182 +Future<bool> connectToNode() async => connecToNodeNative() != 0;
183 +
184 +void setRefreshFromBlockHeight({int height}) =>
185 + setRefreshFromBlockHeightNative(height);
186 +
187 +void setRecoveringFromSeed({bool isRecovery}) =>
188 + setRecoveringFromSeedNative(_boolToInt(isRecovery));
189 +
190 +void storeSync() {
191 + final pathPointer = Utf8.toUtf8('');
192 + storeNative(pathPointer);
193 + free(pathPointer);
194 +}
195 +
196 +void closeCurrentWallet() => closeCurrentWalletNative();
197 +
198 +String getSecretViewKey() =>
199 + convertUTF8ToString(pointer: getSecretViewKeyNative());
200 +
201 +String getPublicViewKey() =>
202 + convertUTF8ToString(pointer: getPublicViewKeyNative());
203 +
204 +String getSecretSpendKey() =>
205 + convertUTF8ToString(pointer: getSecretSpendKeyNative());
206 +
207 +String getPublicSpendKey() =>
208 + convertUTF8ToString(pointer: getPublicSpendKeyNative());
209 +
210 +class SyncListener {
211 + SyncListener(this.onNewBlock, this.onNewTransaction) {
212 + _cachedBlockchainHeight = 0;
213 + _lastKnownBlockHeight = 0;
214 + _initialSyncHeight = 0;
215 + }
216 +
217 + void Function(int, int, double) onNewBlock;
218 + void Function() onNewTransaction;
219 +
220 + Timer _updateSyncInfoTimer;
221 + int _cachedBlockchainHeight;
222 + int _lastKnownBlockHeight;
223 + int _initialSyncHeight;
224 +
225 + Future<int> getNodeHeightOrUpdate(int baseHeight) async {
226 + if (_cachedBlockchainHeight < baseHeight || _cachedBlockchainHeight == 0) {
227 + _cachedBlockchainHeight = await getNodeHeight();
228 + }
229 +
230 + return _cachedBlockchainHeight;
231 + }
232 +
233 + void start() {
234 + _cachedBlockchainHeight = 0;
235 + _lastKnownBlockHeight = 0;
236 + _initialSyncHeight = 0;
237 + _updateSyncInfoTimer ??=
238 + Timer.periodic(Duration(milliseconds: 1200), (_) async {
239 + if (isNewTransactionExist()) {
240 + onNewTransaction?.call();
241 + }
242 +
243 + var syncHeight = getSyncingHeight();
244 +
245 + if (syncHeight <= 0) {
246 + syncHeight = getCurrentHeight();
247 + }
248 +
249 + if (_initialSyncHeight <= 0) {
250 + _initialSyncHeight = syncHeight;
251 + }
252 +
253 + final bchHeight = await getNodeHeightOrUpdate(syncHeight);
254 +
255 + if (_lastKnownBlockHeight == syncHeight || syncHeight == null) {
256 + return;
257 + }
258 +
259 + _lastKnownBlockHeight = syncHeight;
260 + final track = bchHeight - _initialSyncHeight;
261 + final diff = track - (bchHeight - syncHeight);
262 + final ptc = diff <= 0 ? 0.0 : diff / track;
263 + final left = bchHeight - syncHeight;
264 +
265 + if (syncHeight < 0 || left < 0) {
266 + return;
267 + }
268 +
269 + // 1. Actual new height; 2. Blocks left to finish; 3. Progress in percents;
270 + onNewBlock?.call(syncHeight, left, ptc);
271 + });
272 + }
273 +
274 + void stop() => _updateSyncInfoTimer?.cancel();
275 +}
276 +
277 +SyncListener setListeners(void Function(int, int, double) onNewBlock,
278 + void Function() onNewTransaction) {
279 + final listener = SyncListener(onNewBlock, onNewTransaction);
280 + setListenerNative();
281 + return listener;
282 +}
283 +
284 +void onStartup() => onStartupNative();
285 +
286 +void _storeSync(Object _) => storeSync();
287 +
288 +bool _setupNodeSync(Map args) {
289 + final address = args['address'] as String;
290 + final login = (args['login'] ?? '') as String;
291 + final password = (args['password'] ?? '') as String;
292 + final useSSL = args['useSSL'] as bool;
293 + final isLightWallet = args['isLightWallet'] as bool;
294 +
295 + return setupNodeSync(
296 + address: address,
297 + login: login,
298 + password: password,
299 + useSSL: useSSL,
300 + isLightWallet: isLightWallet);
301 +}
302 +
303 +bool _isConnected(Object _) => isConnectedSync();
304 +
305 +int _getNodeHeight(Object _) => getNodeHeightSync();
306 +
307 +void startRefresh() => startRefreshSync();
308 +
309 +Future setupNode(
310 + {String address,
311 + String login,
312 + String password,
313 + bool useSSL = false,
314 + bool isLightWallet = false}) =>
315 + compute<Map<String, Object>, void>(_setupNodeSync, {
316 + 'address': address,
317 + 'login': login,
318 + 'password': password,
319 + 'useSSL': useSSL,
320 + 'isLightWallet': isLightWallet
321 + });
322 +
323 +Future store() => compute<int, void>(_storeSync, 0);
324 +
325 +Future<bool> isConnected() => compute(_isConnected, 0);
326 +
327 +Future<int> getNodeHeight() => compute(_getNodeHeight, 0);
328 +
329 +void rescanBlockchainAsync() => rescanBlockchainAsyncNative();
cw_haven/lib/api/wallet_manager.dart new
+248
@@ -0,0 +1,248 @@
1 +import 'dart:ffi';
2 +import 'package:ffi/ffi.dart';
3 +import 'package:flutter/foundation.dart';
4 +import 'package:cw_haven/api/convert_utf8_to_string.dart';
5 +import 'package:cw_haven/api/signatures.dart';
6 +import 'package:cw_haven/api/types.dart';
7 +import 'package:cw_haven/api/haven_api.dart';
8 +import 'package:cw_haven/api/wallet.dart';
9 +import 'package:cw_haven/api/exceptions/wallet_opening_exception.dart';
10 +import 'package:cw_haven/api/exceptions/wallet_creation_exception.dart';
11 +import 'package:cw_haven/api/exceptions/wallet_restore_from_keys_exception.dart';
12 +import 'package:cw_haven/api/exceptions/wallet_restore_from_seed_exception.dart';
13 +
14 +final createWalletNative = havenApi
15 + .lookup<NativeFunction<create_wallet>>('create_wallet')
16 + .asFunction<CreateWallet>();
17 +
18 +final restoreWalletFromSeedNative = havenApi
19 + .lookup<NativeFunction<restore_wallet_from_seed>>(
20 + 'restore_wallet_from_seed')
21 + .asFunction<RestoreWalletFromSeed>();
22 +
23 +final restoreWalletFromKeysNative = havenApi
24 + .lookup<NativeFunction<restore_wallet_from_keys>>(
25 + 'restore_wallet_from_keys')
26 + .asFunction<RestoreWalletFromKeys>();
27 +
28 +final isWalletExistNative = havenApi
29 + .lookup<NativeFunction<is_wallet_exist>>('is_wallet_exist')
30 + .asFunction<IsWalletExist>();
31 +
32 +final loadWalletNative = havenApi
33 + .lookup<NativeFunction<load_wallet>>('load_wallet')
34 + .asFunction<LoadWallet>();
35 +
36 +final errorStringNative = havenApi
37 + .lookup<NativeFunction<error_string>>('error_string')
38 + .asFunction<ErrorString>();
39 +
40 +void createWalletSync(
41 + {String path, String password, String language, int nettype = 0}) {
42 + final pathPointer = Utf8.toUtf8(path);
43 + final passwordPointer = Utf8.toUtf8(password);
44 + final languagePointer = Utf8.toUtf8(language);
45 + final errorMessagePointer = allocate<Utf8>();
46 + final isWalletCreated = createWalletNative(pathPointer, passwordPointer,
47 + languagePointer, nettype, errorMessagePointer) !=
48 + 0;
49 +
50 + free(pathPointer);
51 + free(passwordPointer);
52 + free(languagePointer);
53 +
54 + if (!isWalletCreated) {
55 + throw WalletCreationException(
56 + message: convertUTF8ToString(pointer: errorMessagePointer));
57 + }
58 +
59 + // setupNodeSync(address: "node.moneroworld.com:18089");
60 +}
61 +
62 +bool isWalletExistSync({String path}) {
63 + final pathPointer = Utf8.toUtf8(path);
64 + final isExist = isWalletExistNative(pathPointer) != 0;
65 +
66 + free(pathPointer);
67 +
68 + return isExist;
69 +}
70 +
71 +void restoreWalletFromSeedSync(
72 + {String path,
73 + String password,
74 + String seed,
75 + int nettype = 0,
76 + int restoreHeight = 0}) {
77 + final pathPointer = Utf8.toUtf8(path);
78 + final passwordPointer = Utf8.toUtf8(password);
79 + final seedPointer = Utf8.toUtf8(seed);
80 + final errorMessagePointer = allocate<Utf8>();
81 + final isWalletRestored = restoreWalletFromSeedNative(
82 + pathPointer,
83 + passwordPointer,
84 + seedPointer,
85 + nettype,
86 + restoreHeight,
87 + errorMessagePointer) !=
88 + 0;
89 +
90 + free(pathPointer);
91 + free(passwordPointer);
92 + free(seedPointer);
93 +
94 + if (!isWalletRestored) {
95 + throw WalletRestoreFromSeedException(
96 + message: convertUTF8ToString(pointer: errorMessagePointer));
97 + }
98 +}
99 +
100 +void restoreWalletFromKeysSync(
101 + {String path,
102 + String password,
103 + String language,
104 + String address,
105 + String viewKey,
106 + String spendKey,
107 + int nettype = 0,
108 + int restoreHeight = 0}) {
109 + final pathPointer = Utf8.toUtf8(path);
110 + final passwordPointer = Utf8.toUtf8(password);
111 + final languagePointer = Utf8.toUtf8(language);
112 + final addressPointer = Utf8.toUtf8(address);
113 + final viewKeyPointer = Utf8.toUtf8(viewKey);
114 + final spendKeyPointer = Utf8.toUtf8(spendKey);
115 + final errorMessagePointer = allocate<Utf8>();
116 + final isWalletRestored = restoreWalletFromKeysNative(
117 + pathPointer,
118 + passwordPointer,
119 + languagePointer,
120 + addressPointer,
121 + viewKeyPointer,
122 + spendKeyPointer,
123 + nettype,
124 + restoreHeight,
125 + errorMessagePointer) !=
126 + 0;
127 +
128 + free(pathPointer);
129 + free(passwordPointer);
130 + free(languagePointer);
131 + free(addressPointer);
132 + free(viewKeyPointer);
133 + free(spendKeyPointer);
134 +
135 + if (!isWalletRestored) {
136 + throw WalletRestoreFromKeysException(
137 + message: convertUTF8ToString(pointer: errorMessagePointer));
138 + }
139 +}
140 +
141 +void loadWallet({String path, String password, int nettype = 0}) {
142 + final pathPointer = Utf8.toUtf8(path);
143 + final passwordPointer = Utf8.toUtf8(password);
144 + final loaded = loadWalletNative(pathPointer, passwordPointer, nettype) != 0;
145 + free(pathPointer);
146 + free(passwordPointer);
147 +
148 + if (!loaded) {
149 + throw WalletOpeningException(
150 + message: convertUTF8ToString(pointer: errorStringNative()));
151 + }
152 +}
153 +
154 +void _createWallet(Map<String, dynamic> args) {
155 + final path = args['path'] as String;
156 + final password = args['password'] as String;
157 + final language = args['language'] as String;
158 +
159 + createWalletSync(path: path, password: password, language: language);
160 +}
161 +
162 +void _restoreFromSeed(Map<String, dynamic> args) {
163 + final path = args['path'] as String;
164 + final password = args['password'] as String;
165 + final seed = args['seed'] as String;
166 + final restoreHeight = args['restoreHeight'] as int;
167 +
168 + restoreWalletFromSeedSync(
169 + path: path, password: password, seed: seed, restoreHeight: restoreHeight);
170 +}
171 +
172 +void _restoreFromKeys(Map<String, dynamic> args) {
173 + final path = args['path'] as String;
174 + final password = args['password'] as String;
175 + final language = args['language'] as String;
176 + final restoreHeight = args['restoreHeight'] as int;
177 + final address = args['address'] as String;
178 + final viewKey = args['viewKey'] as String;
179 + final spendKey = args['spendKey'] as String;
180 +
181 + restoreWalletFromKeysSync(
182 + path: path,
183 + password: password,
184 + language: language,
185 + restoreHeight: restoreHeight,
186 + address: address,
187 + viewKey: viewKey,
188 + spendKey: spendKey);
189 +}
190 +
191 +Future<void> _openWallet(Map<String, String> args) async =>
192 + loadWallet(path: args['path'], password: args['password']);
193 +
194 +bool _isWalletExist(String path) => isWalletExistSync(path: path);
195 +
196 +void openWallet({String path, String password, int nettype = 0}) async =>
197 + loadWallet(path: path, password: password, nettype: nettype);
198 +
199 +Future<void> openWalletAsync(Map<String, String> args) async =>
200 + compute(_openWallet, args);
201 +
202 +Future<void> createWallet(
203 + {String path,
204 + String password,
205 + String language,
206 + int nettype = 0}) async =>
207 + compute(_createWallet, {
208 + 'path': path,
209 + 'password': password,
210 + 'language': language,
211 + 'nettype': nettype
212 + });
213 +
214 +Future restoreFromSeed(
215 + {String path,
216 + String password,
217 + String seed,
218 + int nettype = 0,
219 + int restoreHeight = 0}) async =>
220 + compute<Map<String, Object>, void>(_restoreFromSeed, {
221 + 'path': path,
222 + 'password': password,
223 + 'seed': seed,
224 + 'nettype': nettype,
225 + 'restoreHeight': restoreHeight
226 + });
227 +
228 +Future restoreFromKeys(
229 + {String path,
230 + String password,
231 + String language,
232 + String address,
233 + String viewKey,
234 + String spendKey,
235 + int nettype = 0,
236 + int restoreHeight = 0}) async =>
237 + compute<Map<String, Object>, void>(_restoreFromKeys, {
238 + 'path': path,
239 + 'password': password,
240 + 'language': language,
241 + 'address': address,
242 + 'viewKey': viewKey,
243 + 'spendKey': spendKey,
244 + 'nettype': nettype,
245 + 'restoreHeight': restoreHeight
246 + });
247 +
248 +Future<bool> isWalletExist({String path}) => compute(_isWalletExist, path);
cw_haven/lib/haven_account_list.dart new
+84
@@ -0,0 +1,84 @@
1 +import 'package:mobx/mobx.dart';
2 +import 'package:cw_core/account.dart';
3 +import 'package:cw_core/account_list.dart';
4 +import 'package:cw_haven/api/account_list.dart' as account_list;
5 +
6 +part 'haven_account_list.g.dart';
7 +
8 +class HavenAccountList = HavenAccountListBase with _$HavenAccountList;
9 +
10 +abstract class HavenAccountListBase extends AccountList<Account> with Store {
11 + HavenAccountListBase()
12 + : accounts = ObservableList<Account>(),
13 + _isRefreshing = false,
14 + _isUpdating = false {
15 + refresh();
16 + }
17 +
18 + @override
19 + @observable
20 + ObservableList<Account> accounts;
21 + bool _isRefreshing;
22 + bool _isUpdating;
23 +
24 + @override
25 + void update() async {
26 + if (_isUpdating) {
27 + return;
28 + }
29 +
30 + try {
31 + _isUpdating = true;
32 + refresh();
33 + final accounts = getAll();
34 +
35 + if (accounts.isNotEmpty) {
36 + this.accounts.clear();
37 + this.accounts.addAll(accounts);
38 + }
39 +
40 + _isUpdating = false;
41 + } catch (e) {
42 + _isUpdating = false;
43 + rethrow;
44 + }
45 + }
46 +
47 + @override
48 + List<Account> getAll() => account_list
49 + .getAllAccount()
50 + .map((accountRow) => Account(
51 + id: accountRow.getId(),
52 + label: accountRow.getLabel()))
53 + .toList();
54 +
55 + @override
56 + Future addAccount({String label}) async {
57 + await account_list.addAccount(label: label);
58 + update();
59 + }
60 +
61 + @override
62 + Future setLabelAccount({int accountIndex, String label}) async {
63 + await account_list.setLabelForAccount(
64 + accountIndex: accountIndex, label: label);
65 + update();
66 + }
67 +
68 + @override
69 + void refresh() {
70 + if (_isRefreshing) {
71 + return;
72 + }
73 +
74 + try {
75 + _isRefreshing = true;
76 + account_list.refreshAccounts();
77 + _isRefreshing = false;
78 + } catch (e) {
79 + _isRefreshing = false;
80 + print(e);
81 + rethrow;
82 + }
83 + }
84 +}
cw_haven/lib/haven_balance.dart new
+34
@@ -0,0 +1,34 @@
1 +import 'package:cw_core/crypto_currency.dart';
2 +import 'package:cw_core/monero_balance.dart';
3 +import 'package:cw_haven/api/balance_list.dart';
4 +import 'package:cw_haven/api/structs/haven_balance_row.dart';
5 +
6 +const inactiveBalances = [
7 + CryptoCurrency.xcad,
8 + CryptoCurrency.xjpy,
9 + CryptoCurrency.xnok,
10 + CryptoCurrency.xnzd];
11 +
12 +Map<CryptoCurrency, MoneroBalance> getHavenBalance({int accountIndex}) {
13 + final fullBalances = getHavenFullBalance(accountIndex: accountIndex);
14 + final unlockedBalances = getHavenUnlockedBalance(accountIndex: accountIndex);
15 + final havenBalances = <CryptoCurrency, MoneroBalance>{};
16 + final balancesLength = fullBalances.length;
17 +
18 + for (int i = 0; i < balancesLength; i++) {
19 + final assetType = fullBalances[i].getAssetType();
20 + final fullBalance = fullBalances[i].getAmount();
21 + final unlockedBalance = unlockedBalances[i].getAmount();
22 + final moneroBalance = MoneroBalance(
23 + fullBalance: fullBalance, unlockedBalance: unlockedBalance);
24 + final currency = CryptoCurrency.fromString(assetType);
25 +
26 + if (inactiveBalances.indexOf(currency) >= 0) {
27 + continue;
28 + }
29 +
30 + havenBalances[currency] = moneroBalance;
31 + }
32 +
33 + return havenBalances;
34 +}
\ No newline at end of file
cw_haven/lib/haven_subaddress_list.dart new
+87
@@ -0,0 +1,87 @@
1 +import 'package:cw_haven/api/structs/subaddress_row.dart';
2 +import 'package:flutter/services.dart';
3 +import 'package:mobx/mobx.dart';
4 +import 'package:cw_haven/api/subaddress_list.dart' as subaddress_list;
5 +import 'package:cw_core/subaddress.dart';
6 +
7 +part 'haven_subaddress_list.g.dart';
8 +
9 +class HavenSubaddressList = HavenSubaddressListBase
10 + with _$HavenSubaddressList;
11 +
12 +abstract class HavenSubaddressListBase with Store {
13 + HavenSubaddressListBase() {
14 + _isRefreshing = false;
15 + _isUpdating = false;
16 + subaddresses = ObservableList<Subaddress>();
17 + }
18 +
19 + @observable
20 + ObservableList<Subaddress> subaddresses;
21 +
22 + bool _isRefreshing;
23 + bool _isUpdating;
24 +
25 + void update({int accountIndex}) {
26 + if (_isUpdating) {
27 + return;
28 + }
29 +
30 + try {
31 + _isUpdating = true;
32 + refresh(accountIndex: accountIndex);
33 + subaddresses.clear();
34 + subaddresses.addAll(getAll());
35 + _isUpdating = false;
36 + } catch (e) {
37 + _isUpdating = false;
38 + rethrow;
39 + }
40 + }
41 +
42 + List<Subaddress> getAll() {
43 + var subaddresses = subaddress_list.getAllSubaddresses();
44 +
45 + if (subaddresses.length > 2) {
46 + final primary = subaddresses.first;
47 + final rest = subaddresses.sublist(1).reversed;
48 + subaddresses = [primary] + rest.toList();
49 + }
50 +
51 + return subaddresses
52 + .map((subaddressRow) => Subaddress(
53 + id: subaddressRow.getId(),
54 + address: subaddressRow.getAddress(),
55 + label: subaddressRow.getLabel()))
56 + .toList();
57 + }
58 +
59 + Future addSubaddress({int accountIndex, String label}) async {
60 + await subaddress_list.addSubaddress(
61 + accountIndex: accountIndex, label: label);
62 + update(accountIndex: accountIndex);
63 + }
64 +
65 + Future setLabelSubaddress(
66 + {int accountIndex, int addressIndex, String label}) async {
67 + await subaddress_list.setLabelForSubaddress(
68 + accountIndex: accountIndex, addressIndex: addressIndex, label: label);
69 + update(accountIndex: accountIndex);
70 + }
71 +
72 + void refresh({int accountIndex}) {
73 + if (_isRefreshing) {
74 + return;
75 + }
76 +
77 + try {
78 + _isRefreshing = true;
79 + subaddress_list.refreshSubaddresses(accountIndex: accountIndex);
80 + _isRefreshing = false;
81 + } on PlatformException catch (e) {
82 + _isRefreshing = false;
83 + print(e);
84 + rethrow;
85 + }
86 + }
87 +}
cw_haven/lib/haven_transaction_creation_credentials.dart new
+10
@@ -0,0 +1,10 @@
1 +import 'package:cw_core/monero_transaction_priority.dart';
2 +import 'package:cw_core/output_info.dart';
3 +
4 +class HavenTransactionCreationCredentials {
5 + HavenTransactionCreationCredentials({this.outputs, this.priority, this.assetType});
6 +
7 + final List<OutputInfo> outputs;
8 + final MoneroTransactionPriority priority;
9 + final String assetType;
10 +}
cw_haven/lib/haven_transaction_creation_exception.dart new
+8
@@ -0,0 +1,8 @@
1 +class HavenTransactionCreationException implements Exception {
2 + HavenTransactionCreationException(this.message);
3 +
4 + final String message;
5 +
6 + @override
7 + String toString() => message;
8 +}
\ No newline at end of file
cw_haven/lib/haven_transaction_history.dart new
+27
@@ -0,0 +1,27 @@
1 +import 'dart:core';
2 +import 'package:mobx/mobx.dart';
3 +import 'package:cw_core/transaction_history.dart';
4 +import 'package:cw_haven/haven_transaction_info.dart';
5 +
6 +part 'haven_transaction_history.g.dart';
7 +
8 +class HavenTransactionHistory = HavenTransactionHistoryBase
9 + with _$HavenTransactionHistory;
10 +
11 +abstract class HavenTransactionHistoryBase
12 + extends TransactionHistoryBase<HavenTransactionInfo> with Store {
13 + HavenTransactionHistoryBase() {
14 + transactions = ObservableMap<String, HavenTransactionInfo>();
15 + }
16 +
17 + @override
18 + Future<void> save() async {}
19 +
20 + @override
21 + void addOne(HavenTransactionInfo transaction) =>
22 + transactions[transaction.id] = transaction;
23 +
24 + @override
25 + void addMany(Map<String, HavenTransactionInfo> transactions) =>
26 + this.transactions.addAll(transactions);
27 +}
cw_haven/lib/haven_transaction_info.dart new
+70
@@ -0,0 +1,70 @@
1 +import 'package:cw_core/transaction_info.dart';
2 +import 'package:cw_core/monero_amount_format.dart';
3 +import 'package:cw_haven/api/structs/transaction_info_row.dart';
4 +import 'package:cw_core/parseBoolFromString.dart';
5 +import 'package:cw_core/transaction_direction.dart';
6 +import 'package:cw_core/format_amount.dart';
7 +import 'package:cw_haven/api/transaction_history.dart';
8 +
9 +class HavenTransactionInfo extends TransactionInfo {
10 + HavenTransactionInfo(this.id, this.height, this.direction, this.date,
11 + this.isPending, this.amount, this.accountIndex, this.addressIndex, this.fee);
12 +
13 + HavenTransactionInfo.fromMap(Map map)
14 + : id = (map['hash'] ?? '') as String,
15 + height = (map['height'] ?? 0) as int,
16 + direction =
17 + parseTransactionDirectionFromNumber(map['direction'] as String) ??
18 + TransactionDirection.incoming,
19 + date = DateTime.fromMillisecondsSinceEpoch(
20 + (int.parse(map['timestamp'] as String) ?? 0) * 1000),
21 + isPending = parseBoolFromString(map['isPending'] as String),
22 + amount = map['amount'] as int,
23 + accountIndex = int.parse(map['accountIndex'] as String),
24 + addressIndex = map['addressIndex'] as int,
25 + key = getTxKey((map['hash'] ?? '') as String),
26 + fee = map['fee'] as int ?? 0;
27 +
28 + HavenTransactionInfo.fromRow(TransactionInfoRow row)
29 + : id = row.getHash(),
30 + height = row.blockHeight,
31 + direction = parseTransactionDirectionFromInt(row.direction) ??
32 + TransactionDirection.incoming,
33 + date = DateTime.fromMillisecondsSinceEpoch(row.getDatetime() * 1000),
34 + isPending = row.isPending != 0,
35 + amount = row.getAmount(),
36 + accountIndex = row.subaddrAccount,
37 + addressIndex = row.subaddrIndex,
38 + key = null, //getTxKey(row.getHash()),
39 + fee = row.fee,
40 + assetType = row.getAssetType();
41 +
42 + final String id;
43 + final int height;
44 + final TransactionDirection direction;
45 + final DateTime date;
46 + final int accountIndex;
47 + final bool isPending;
48 + final int amount;
49 + final int fee;
50 + final int addressIndex;
51 + String recipientAddress;
52 + String key;
53 + String assetType;
54 +
55 + String _fiatAmount;
56 +
57 + @override
58 + String amountFormatted() =>
59 + '${formatAmount(moneroAmountToString(amount: amount))} $assetType';
60 +
61 + @override
62 + String fiatAmount() => _fiatAmount ?? '';
63 +
64 + @override
65 + void changeFiatAmount(String amount) => _fiatAmount = formatAmount(amount);
66 +
67 + @override
68 + String feeFormatted() =>
69 + '${formatAmount(moneroAmountToString(amount: fee))} $assetType';
70 +}
cw_haven/lib/haven_wallet.dart new
+388
@@ -0,0 +1,388 @@
1 +import 'dart:async';
2 +import 'package:cw_core/crypto_currency.dart';
3 +import 'package:cw_core/transaction_priority.dart';
4 +import 'package:cw_haven/haven_transaction_creation_credentials.dart';
5 +import 'package:cw_core/monero_amount_format.dart';
6 +import 'package:cw_haven/haven_transaction_creation_exception.dart';
7 +import 'package:cw_haven/haven_transaction_info.dart';
8 +import 'package:cw_haven/haven_wallet_addresses.dart';
9 +import 'package:cw_core/monero_wallet_utils.dart';
10 +import 'package:cw_haven/api/structs/pending_transaction.dart';
11 +import 'package:flutter/foundation.dart';
12 +import 'package:mobx/mobx.dart';
13 +import 'package:cw_haven/api/transaction_history.dart'
14 + as haven_transaction_history;
15 +//import 'package:cw_haven/wallet.dart';
16 +import 'package:cw_haven/api/wallet.dart' as haven_wallet;
17 +import 'package:cw_haven/api/transaction_history.dart' as transaction_history;
18 +import 'package:cw_haven/api/monero_output.dart';
19 +import 'package:cw_haven/pending_haven_transaction.dart';
20 +import 'package:cw_core/monero_wallet_keys.dart';
21 +import 'package:cw_core/monero_balance.dart';
22 +import 'package:cw_haven/haven_transaction_history.dart';
23 +import 'package:cw_core/account.dart';
24 +import 'package:cw_core/pending_transaction.dart';
25 +import 'package:cw_core/wallet_base.dart';
26 +import 'package:cw_core/sync_status.dart';
27 +import 'package:cw_core/wallet_info.dart';
28 +import 'package:cw_core/node.dart';
29 +import 'package:cw_core/monero_transaction_priority.dart';
30 +import 'package:cw_haven/haven_balance.dart';
31 +
32 +part 'haven_wallet.g.dart';
33 +
34 +const moneroBlockSize = 1000;
35 +
36 +class HavenWallet = HavenWalletBase with _$HavenWallet;
37 +
38 +abstract class HavenWalletBase extends WalletBase<MoneroBalance,
39 + HavenTransactionHistory, HavenTransactionInfo> with Store {
40 + HavenWalletBase({WalletInfo walletInfo})
41 + : super(walletInfo) {
42 + transactionHistory = HavenTransactionHistory();
43 + balance = ObservableMap.of(getHavenBalance(accountIndex: 0));
44 + _isTransactionUpdating = false;
45 + _hasSyncAfterStartup = false;
46 + walletAddresses = HavenWalletAddresses(walletInfo);
47 + _onAccountChangeReaction = reaction((_) => walletAddresses.account,
48 + (Account account) {
49 + balance.addAll(getHavenBalance(accountIndex: account.id));
50 + walletAddresses.updateSubaddressList(accountIndex: account.id);
51 + });
52 + }
53 +
54 + static const int _autoSaveInterval = 30;
55 +
56 + @override
57 + HavenWalletAddresses walletAddresses;
58 +
59 + @override
60 + @observable
61 + SyncStatus syncStatus;
62 +
63 + @override
64 + @observable
65 + ObservableMap<CryptoCurrency, MoneroBalance> balance;
66 +
67 + @override
68 + String get seed => haven_wallet.getSeed();
69 +
70 + @override
71 + MoneroWalletKeys get keys => MoneroWalletKeys(
72 + privateSpendKey: haven_wallet.getSecretSpendKey(),
73 + privateViewKey: haven_wallet.getSecretViewKey(),
74 + publicSpendKey: haven_wallet.getPublicSpendKey(),
75 + publicViewKey: haven_wallet.getPublicViewKey());
76 +
77 + haven_wallet.SyncListener _listener;
78 + ReactionDisposer _onAccountChangeReaction;
79 + bool _isTransactionUpdating;
80 + bool _hasSyncAfterStartup;
81 + Timer _autoSaveTimer;
82 +
83 + Future<void> init() async {
84 + await walletAddresses.init();
85 + balance.addAll(getHavenBalance(accountIndex: walletAddresses.account.id ?? 0));
86 + _setListeners();
87 + await updateTransactions();
88 +
89 + if (walletInfo.isRecovery) {
90 + haven_wallet.setRecoveringFromSeed(isRecovery: walletInfo.isRecovery);
91 +
92 + if (haven_wallet.getCurrentHeight() <= 1) {
93 + haven_wallet.setRefreshFromBlockHeight(
94 + height: walletInfo.restoreHeight);
95 + }
96 + }
97 +
98 + _autoSaveTimer = Timer.periodic(
99 + Duration(seconds: _autoSaveInterval),
100 + (_) async => await save());
101 + }
102 +
103 + @override
104 + void close() {
105 + _listener?.stop();
106 + _onAccountChangeReaction?.reaction?.dispose();
107 + _autoSaveTimer?.cancel();
108 + }
109 +
110 + @override
111 + Future<void> connectToNode({@required Node node}) async {
112 + try {
113 + syncStatus = ConnectingSyncStatus();
114 + await haven_wallet.setupNode(
115 + address: node.uriRaw,
116 + login: node.login,
117 + password: node.password,
118 + useSSL: node.useSSL,
119 + isLightWallet: false); // FIXME: hardcoded value
120 + syncStatus = ConnectedSyncStatus();
121 + } catch (e) {
122 + syncStatus = FailedSyncStatus();
123 + print(e);
124 + }
125 + }
126 +
127 + @override
128 + Future<void> startSync() async {
129 + try {
130 + _setInitialHeight();
131 + } catch (_) {}
132 +
133 + try {
134 + syncStatus = StartingSyncStatus();
135 + haven_wallet.startRefresh();
136 + _setListeners();
137 + _listener?.start();
138 + } catch (e) {
139 + syncStatus = FailedSyncStatus();
140 + print(e);
141 + rethrow;
142 + }
143 + }
144 +
145 + @override
146 + Future<PendingTransaction> createTransaction(Object credentials) async {
147 + final _credentials = credentials as HavenTransactionCreationCredentials;
148 + final outputs = _credentials.outputs;
149 + final hasMultiDestination = outputs.length > 1;
150 + final assetType = CryptoCurrency.fromString(_credentials.assetType.toLowerCase());
151 + final balances = getHavenBalance(accountIndex: walletAddresses.account.id);
152 + final unlockedBalance = balances[assetType].unlockedBalance;
153 +
154 + PendingTransactionDescription pendingTransactionDescription;
155 +
156 + if (!(syncStatus is SyncedSyncStatus)) {
157 + throw HavenTransactionCreationException('The wallet is not synced.');
158 + }
159 +
160 + if (hasMultiDestination) {
161 + if (outputs.any((item) => item.sendAll
162 + || item.formattedCryptoAmount <= 0)) {
163 + throw HavenTransactionCreationException('Wrong balance. Not enough XMR on your balance.');
164 + }
165 +
166 + final int totalAmount = outputs.fold(0, (acc, value) =>
167 + acc + value.formattedCryptoAmount);
168 +
169 + if (unlockedBalance < totalAmount) {
170 + throw HavenTransactionCreationException('Wrong balance. Not enough XMR on your balance.');
171 + }
172 +
173 + final moneroOutputs = outputs.map((output) =>
174 + MoneroOutput(
175 + address: output.address,
176 + amount: output.cryptoAmount.replaceAll(',', '.')))
177 + .toList();
178 +
179 + pendingTransactionDescription =
180 + await transaction_history.createTransactionMultDest(
181 + outputs: moneroOutputs,
182 + priorityRaw: _credentials.priority.serialize(),
183 + accountIndex: walletAddresses.account.id);
184 + } else {
185 + final output = outputs.first;
186 + final address = output.address;
187 + final amount = output.sendAll
188 + ? null
189 + : output.cryptoAmount.replaceAll(',', '.');
190 + final formattedAmount = output.sendAll
191 + ? null
192 + : output.formattedCryptoAmount;
193 +
194 + if ((formattedAmount != null && unlockedBalance < formattedAmount) ||
195 + (formattedAmount == null && unlockedBalance <= 0)) {
196 + final formattedBalance = moneroAmountToString(amount: unlockedBalance);
197 +
198 + throw HavenTransactionCreationException(
199 + 'Incorrect unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.');
200 + }
201 +
202 + pendingTransactionDescription =
203 + await transaction_history.createTransaction(
204 + address: address,
205 + assetType: _credentials.assetType,
206 + amount: amount,
207 + priorityRaw: _credentials.priority.serialize(),
208 + accountIndex: walletAddresses.account.id);
209 + }
210 +
211 + return PendingHavenTransaction(pendingTransactionDescription, assetType);
212 + }
213 +
214 + @override
215 + int calculateEstimatedFee(TransactionPriority priority, int amount) {
216 + // FIXME: hardcoded value;
217 +
218 + if (priority is MoneroTransactionPriority) {
219 + switch (priority) {
220 + case MoneroTransactionPriority.slow:
221 + return 24590000;
222 + case MoneroTransactionPriority.regular:
223 + return 123050000;
224 + case MoneroTransactionPriority.medium:
225 + return 245029999;
226 + case MoneroTransactionPriority.fast:
227 + return 614530000;
228 + case MoneroTransactionPriority.fastest:
229 + return 26021600000;
230 + }
231 + }
232 +
233 + return 0;
234 + }
235 +
236 + @override
237 + Future<void> save() async {
238 + await walletAddresses.updateAddressesInBox();
239 + await backupWalletFiles(name);
240 + await haven_wallet.store();
241 + }
242 +
243 + Future<int> getNodeHeight() async => haven_wallet.getNodeHeight();
244 +
245 + Future<bool> isConnected() async => haven_wallet.isConnected();
246 +
247 + Future<void> setAsRecovered() async {
248 + walletInfo.isRecovery = false;
249 + await walletInfo.save();
250 + }
251 +
252 + @override
253 + Future<void> rescan({int height}) async {
254 + walletInfo.restoreHeight = height;
255 + walletInfo.isRecovery = true;
256 + haven_wallet.setRefreshFromBlockHeight(height: height);
257 + haven_wallet.rescanBlockchainAsync();
258 + await startSync();
259 + _askForUpdateBalance();
260 + walletAddresses.accountList.update();
261 + await _askForUpdateTransactionHistory();
262 + await save();
263 + await walletInfo.save();
264 + }
265 +
266 + String getTransactionAddress(int accountIndex, int addressIndex) =>
267 + haven_wallet.getAddress(
268 + accountIndex: accountIndex,
269 + addressIndex: addressIndex);
270 +
271 + @override
272 + Future<Map<String, HavenTransactionInfo>> fetchTransactions() async {
273 + haven_transaction_history.refreshTransactions();
274 + return _getAllTransactions(null).fold<Map<String, HavenTransactionInfo>>(
275 + <String, HavenTransactionInfo>{},
276 + (Map<String, HavenTransactionInfo> acc, HavenTransactionInfo tx) {
277 + acc[tx.id] = tx;
278 + return acc;
279 + });
280 + }
281 +
282 + Future<void> updateTransactions() async {
283 + try {
284 + if (_isTransactionUpdating) {
285 + return;
286 + }
287 +
288 + _isTransactionUpdating = true;
289 + final transactions = await fetchTransactions();
290 + transactionHistory.addMany(transactions);
291 + await transactionHistory.save();
292 + _isTransactionUpdating = false;
293 + } catch (e) {
294 + print(e);
295 + _isTransactionUpdating = false;
296 + }
297 + }
298 +
299 + List<HavenTransactionInfo> _getAllTransactions(dynamic _) => haven_transaction_history
300 + .getAllTransations()
301 + .map((row) => HavenTransactionInfo.fromRow(row))
302 + .toList();
303 +
304 + void _setListeners() {
305 + _listener?.stop();
306 + _listener = haven_wallet.setListeners(_onNewBlock, _onNewTransaction);
307 + }
308 +
309 + void _setInitialHeight() {
310 + if (walletInfo.isRecovery) {
311 + return;
312 + }
313 +
314 + final currentHeight = haven_wallet.getCurrentHeight();
315 +
316 + if (currentHeight <= 1) {
317 + final height = _getHeightByDate(walletInfo.date);
318 + haven_wallet.setRecoveringFromSeed(isRecovery: true);
319 + haven_wallet.setRefreshFromBlockHeight(height: height);
320 + }
321 + }
322 +
323 + int _getHeightDistance(DateTime date) {
324 + final distance =
325 + DateTime.now().millisecondsSinceEpoch - date.millisecondsSinceEpoch;
326 + final daysTmp = (distance / 86400).round();
327 + final days = daysTmp < 1 ? 1 : daysTmp;
328 +
329 + return days * 1000;
330 + }
331 +
332 + int _getHeightByDate(DateTime date) {
333 + final nodeHeight = haven_wallet.getNodeHeightSync();
334 + final heightDistance = _getHeightDistance(date);
335 +
336 + if (nodeHeight <= 0) {
337 + return 0;
338 + }
339 +
340 + return nodeHeight - heightDistance;
341 + }
342 +
343 + void _askForUpdateBalance() =>
344 + balance.addAll(getHavenBalance(accountIndex: walletAddresses.account.id));
345 +
346 + Future<void> _askForUpdateTransactionHistory() async =>
347 + await updateTransactions();
348 +
349 + void _onNewBlock(int height, int blocksLeft, double ptc) async {
350 + try {
351 + if (walletInfo.isRecovery) {
352 + await _askForUpdateTransactionHistory();
353 + _askForUpdateBalance();
354 + walletAddresses.accountList.update();
355 + }
356 +
357 + if (blocksLeft < 1000) {
358 + await _askForUpdateTransactionHistory();
359 + _askForUpdateBalance();
360 + walletAddresses.accountList.update();
361 + syncStatus = SyncedSyncStatus();
362 +
363 + if (!_hasSyncAfterStartup) {
364 + _hasSyncAfterStartup = true;
365 + await save();
366 + }
367 +
368 + if (walletInfo.isRecovery) {
369 + await setAsRecovered();
370 + }
371 + } else {
372 + syncStatus = SyncingSyncStatus(blocksLeft, ptc);
373 + }
374 + } catch (e) {
375 + print(e.toString());
376 + }
377 + }
378 +
379 + void _onNewTransaction() async {
380 + try {
381 + await _askForUpdateTransactionHistory();
382 + _askForUpdateBalance();
383 + await Future<void>.delayed(Duration(seconds: 1));
384 + } catch (e) {
385 + print(e.toString());
386 + }
387 + }
388 +}
cw_haven/lib/haven_wallet_addresses.dart new
+86
@@ -0,0 +1,86 @@
1 +import 'package:cw_core/wallet_addresses_with_account.dart';
2 +import 'package:cw_core/wallet_info.dart';
3 +import 'package:cw_core/account.dart';
4 +import 'package:cw_haven/haven_account_list.dart';
5 +import 'package:cw_haven/haven_subaddress_list.dart';
6 +import 'package:cw_core/subaddress.dart';
7 +import 'package:mobx/mobx.dart';
8 +
9 +part 'haven_wallet_addresses.g.dart';
10 +
11 +class HavenWalletAddresses = HavenWalletAddressesBase
12 + with _$HavenWalletAddresses;
13 +
14 +abstract class HavenWalletAddressesBase extends WalletAddressesWithAccount<Account> with Store {
15 + HavenWalletAddressesBase(WalletInfo walletInfo) : super(walletInfo) {
16 + accountList = HavenAccountList();
17 + subaddressList = HavenSubaddressList();
18 + }
19 +
20 + @override
21 + @observable
22 + String address;
23 +
24 + @override
25 + @observable
26 + Account account;
27 +
28 + @observable
29 + Subaddress subaddress;
30 +
31 + HavenSubaddressList subaddressList;
32 +
33 + HavenAccountList accountList;
34 +
35 + @override
36 + Future<void> init() async {
37 + accountList.update();
38 + account = accountList.accounts.first;
39 + updateSubaddressList(accountIndex: account.id ?? 0);
40 + await updateAddressesInBox();
41 + }
42 +
43 + @override
44 + Future<void> updateAddressesInBox() async {
45 + try {
46 + final _subaddressList = HavenSubaddressList();
47 +
48 + addressesMap.clear();
49 +
50 + accountList.accounts.forEach((account) {
51 + _subaddressList.update(accountIndex: account.id);
52 + _subaddressList.subaddresses.forEach((subaddress) {
53 + addressesMap[subaddress.address] = subaddress.label;
54 + });
55 + });
56 +
57 + await saveAddressesInBox();
58 + } catch (e) {
59 + print(e.toString());
60 + }
61 + }
62 +
63 + bool validate() {
64 + accountList.update();
65 + final accountListLength = accountList.accounts?.length ?? 0;
66 +
67 + if (accountListLength <= 0) {
68 + return false;
69 + }
70 +
71 + subaddressList.update(accountIndex: accountList.accounts.first.id);
72 + final subaddressListLength = subaddressList.subaddresses?.length ?? 0;
73 +
74 + if (subaddressListLength <= 0) {
75 + return false;
76 + }
77 +
78 + return true;
79 + }
80 +
81 + void updateSubaddressList({int accountIndex}) {
82 + subaddressList.update(accountIndex: accountIndex);
83 + subaddress = subaddressList.subaddresses.first;
84 + address = subaddress.address;
85 + }
86 +}
\ No newline at end of file
cw_haven/lib/haven_wallet_service.dart new
+228
@@ -0,0 +1,228 @@
1 +import 'dart:io';
2 +import 'package:cw_core/wallet_base.dart';
3 +import 'package:cw_core/monero_wallet_utils.dart';
4 +import 'package:hive/hive.dart';
5 +import 'package:cw_haven/api/wallet_manager.dart' as haven_wallet_manager;
6 +import 'package:cw_haven/api/wallet.dart' as haven_wallet;
7 +import 'package:cw_haven/api/exceptions/wallet_opening_exception.dart';
8 +import 'package:cw_haven/haven_wallet.dart';
9 +import 'package:cw_core/wallet_credentials.dart';
10 +import 'package:cw_core/wallet_service.dart';
11 +import 'package:cw_core/pathForWallet.dart';
12 +import 'package:cw_core/wallet_info.dart';
13 +import 'package:cw_core/wallet_type.dart';
14 +
15 +class HavenNewWalletCredentials extends WalletCredentials {
16 + HavenNewWalletCredentials({String name, String password, this.language})
17 + : super(name: name, password: password);
18 +
19 + final String language;
20 +}
21 +
22 +class HavenRestoreWalletFromSeedCredentials extends WalletCredentials {
23 + HavenRestoreWalletFromSeedCredentials(
24 + {String name, String password, int height, this.mnemonic})
25 + : super(name: name, password: password, height: height);
26 +
27 + final String mnemonic;
28 +}
29 +
30 +class HavenWalletLoadingException implements Exception {
31 + @override
32 + String toString() => 'Failure to load the wallet.';
33 +}
34 +
35 +class HavenRestoreWalletFromKeysCredentials extends WalletCredentials {
36 + HavenRestoreWalletFromKeysCredentials(
37 + {String name,
38 + String password,
39 + this.language,
40 + this.address,
41 + this.viewKey,
42 + this.spendKey,
43 + int height})
44 + : super(name: name, password: password, height: height);
45 +
46 + final String language;
47 + final String address;
48 + final String viewKey;
49 + final String spendKey;
50 +}
51 +
52 +class HavenWalletService extends WalletService<
53 + HavenNewWalletCredentials,
54 + HavenRestoreWalletFromSeedCredentials,
55 + HavenRestoreWalletFromKeysCredentials> {
56 + HavenWalletService(this.walletInfoSource);
57 +
58 + final Box<WalletInfo> walletInfoSource;
59 +
60 + static bool walletFilesExist(String path) =>
61 + !File(path).existsSync() && !File('$path.keys').existsSync();
62 +
63 + @override
64 + WalletType getType() => WalletType.haven;
65 +
66 + @override
67 + Future<HavenWallet> create(HavenNewWalletCredentials credentials) async {
68 + try {
69 + final path = await pathForWallet(name: credentials.name, type: getType());
70 + await haven_wallet_manager.createWallet(
71 + path: path,
72 + password: credentials.password,
73 + language: credentials.language);
74 + final wallet = HavenWallet(walletInfo: credentials.walletInfo);
75 + await wallet.init();
76 + return wallet;
77 + } catch (e) {
78 + // TODO: Implement Exception for wallet list service.
79 + print('HavenWalletsManager Error: ${e.toString()}');
80 + rethrow;
81 + }
82 + }
83 +
84 + @override
85 + Future<bool> isWalletExit(String name) async {
86 + try {
87 + final path = await pathForWallet(name: name, type: getType());
88 + return haven_wallet_manager.isWalletExist(path: path);
89 + } catch (e) {
90 + // TODO: Implement Exception for wallet list service.
91 + print('HavenWalletsManager Error: $e');
92 + rethrow;
93 + }
94 + }
95 +
96 + @override
97 + Future<HavenWallet> openWallet(String name, String password) async {
98 + try {
99 + final path = await pathForWallet(name: name, type: getType());
100 +
101 + if (walletFilesExist(path)) {
102 + await repairOldAndroidWallet(name);
103 + }
104 +
105 + await haven_wallet_manager
106 + .openWalletAsync({'path': path, 'password': password});
107 + final walletInfo = walletInfoSource.values.firstWhere(
108 + (info) => info.id == WalletBase.idFor(name, getType()),
109 + orElse: () => null);
110 + final wallet = HavenWallet(walletInfo: walletInfo);
111 + final isValid = wallet.walletAddresses.validate();
112 +
113 + if (!isValid) {
114 + await restoreOrResetWalletFiles(name);
115 + wallet.close();
116 + return openWallet(name, password);
117 + }
118 +
119 + await wallet.init();
120 +
121 + return wallet;
122 + } catch (e) {
123 + // TODO: Implement Exception for wallet list service.
124 +
125 + if ((e.toString().contains('bad_alloc') ||
126 + (e is WalletOpeningException &&
127 + (e.message == 'std::bad_alloc' ||
128 + e.message.contains('bad_alloc')))) ||
129 + (e.toString().contains('does not correspond') ||
130 + (e is WalletOpeningException &&
131 + e.message.contains('does not correspond')))) {
132 + await restoreOrResetWalletFiles(name);
133 + return openWallet(name, password);
134 + }
135 +
136 + rethrow;
137 + }
138 + }
139 +
140 + @override
141 + Future<void> remove(String wallet) async {
142 + final path = await pathForWalletDir(name: wallet, type: getType());
143 + final file = Directory(path);
144 + final isExist = file.existsSync();
145 +
146 + if (isExist) {
147 + await file.delete(recursive: true);
148 + }
149 + }
150 +
151 + @override
152 + Future<HavenWallet> restoreFromKeys(
153 + HavenRestoreWalletFromKeysCredentials credentials) async {
154 + try {
155 + final path = await pathForWallet(name: credentials.name, type: getType());
156 + await haven_wallet_manager.restoreFromKeys(
157 + path: path,
158 + password: credentials.password,
159 + language: credentials.language,
160 + restoreHeight: credentials.height,
161 + address: credentials.address,
162 + viewKey: credentials.viewKey,
163 + spendKey: credentials.spendKey);
164 + final wallet = HavenWallet(walletInfo: credentials.walletInfo);
165 + await wallet.init();
166 +
167 + return wallet;
168 + } catch (e) {
169 + // TODO: Implement Exception for wallet list service.
170 + print('HavenWalletsManager Error: $e');
171 + rethrow;
172 + }
173 + }
174 +
175 + @override
176 + Future<HavenWallet> restoreFromSeed(
177 + HavenRestoreWalletFromSeedCredentials credentials) async {
178 + try {
179 + final path = await pathForWallet(name: credentials.name, type: getType());
180 + await haven_wallet_manager.restoreFromSeed(
181 + path: path,
182 + password: credentials.password,
183 + seed: credentials.mnemonic,
184 + restoreHeight: credentials.height);
185 + final wallet = HavenWallet(walletInfo: credentials.walletInfo);
186 + await wallet.init();
187 +
188 + return wallet;
189 + } catch (e) {
190 + // TODO: Implement Exception for wallet list service.
191 + print('HavenWalletsManager Error: $e');
192 + rethrow;
193 + }
194 + }
195 +
196 + Future<void> repairOldAndroidWallet(String name) async {
197 + try {
198 + if (!Platform.isAndroid) {
199 + return;
200 + }
201 +
202 + final oldAndroidWalletDirPath =
203 + await outdatedAndroidPathForWalletDir(name: name);
204 + final dir = Directory(oldAndroidWalletDirPath);
205 +
206 + if (!dir.existsSync()) {
207 + return;
208 + }
209 +
210 + final newWalletDirPath =
211 + await pathForWalletDir(name: name, type: getType());
212 +
213 + dir.listSync().forEach((f) {
214 + final file = File(f.path);
215 + final name = f.path.split('/').last;
216 + final newPath = newWalletDirPath + '/$name';
217 + final newFile = File(newPath);
218 +
219 + if (!newFile.existsSync()) {
220 + newFile.createSync();
221 + }
222 + newFile.writeAsBytesSync(file.readAsBytesSync());
223 + });
224 + } catch (e) {
225 + print(e.toString());
226 + }
227 + }
228 +}
cw_haven/lib/mnemonics/chinese_simplified.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class ChineseSimplifiedMnemonics {
2 + static const words = [
3 + "的",
4 + "一",
5 + "是",
6 + "在",
7 + "不",
8 + "了",
9 + "有",
10 + "和",
11 + "人",
12 + "这",
13 + "中",
14 + "大",
15 + "为",
16 + "上",
17 + "个",
18 + "国",
19 + "我",
20 + "以",
21 + "要",
22 + "他",
23 + "时",
24 + "来",
25 + "用",
26 + "们",
27 + "生",
28 + "到",
29 + "作",
30 + "地",
31 + "于",
32 + "出",
33 + "就",
34 + "分",
35 + "对",
36 + "成",
37 + "会",
38 + "可",
39 + "主",
40 + "发",
41 + "年",
42 + "动",
43 + "同",
44 + "工",
45 + "也",
46 + "能",
47 + "下",
48 + "过",
49 + "子",
50 + "说",
51 + "产",
52 + "种",
53 + "面",
54 + "而",
55 + "方",
56 + "后",
57 + "多",
58 + "定",
59 + "行",
60 + "学",
61 + "法",
62 + "所",
63 + "民",
64 + "得",
65 + "经",
66 + "十",
67 + "三",
68 + "之",
69 + "进",
70 + "着",
71 + "等",
72 + "部",
73 + "度",
74 + "家",
75 + "电",
76 + "力",
77 + "里",
78 + "如",
79 + "水",
80 + "化",
81 + "高",
82 + "自",
83 + "二",
84 + "理",
85 + "起",
86 + "小",
87 + "物",
88 + "现",
89 + "实",
90 + "加",
91 + "量",
92 + "都",
93 + "两",
94 + "体",
95 + "制",
96 + "机",
97 + "当",
98 + "使",
99 + "点",
100 + "从",
101 + "业",
102 + "本",
103 + "去",
104 + "把",
105 + "性",
106 + "好",
107 + "应",
108 + "开",
109 + "它",
110 + "合",
111 + "还",
112 + "因",
113 + "由",
114 + "其",
115 + "些",
116 + "然",
117 + "前",
118 + "外",
119 + "天",
120 + "政",
121 + "四",
122 + "日",
123 + "那",
124 + "社",
125 + "义",
126 + "事",
127 + "平",
128 + "形",
129 + "相",
130 + "全",
131 + "表",
132 + "间",
133 + "样",
134 + "与",
135 + "关",
136 + "各",
137 + "重",
138 + "新",
139 + "线",
140 + "内",
141 + "数",
142 + "正",
143 + "心",
144 + "反",
145 + "你",
146 + "明",
147 + "看",
148 + "原",
149 + "又",
150 + "么",
151 + "利",
152 + "比",
153 + "或",
154 + "但",
155 + "质",
156 + "气",
157 + "第",
158 + "向",
159 + "道",
160 + "命",
161 + "此",
162 + "变",
163 + "条",
164 + "只",
165 + "没",
166 + "结",
167 + "解",
168 + "问",
169 + "意",
170 + "建",
171 + "月",
172 + "公",
173 + "无",
174 + "系",
175 + "军",
176 + "很",
177 + "情",
178 + "者",
179 + "最",
180 + "立",
181 + "代",
182 + "想",
183 + "已",
184 + "通",
185 + "并",
186 + "提",
187 + "直",
188 + "题",
189 + "党",
190 + "程",
191 + "展",
192 + "五",
193 + "果",
194 + "料",
195 + "象",
196 + "员",
197 + "革",
198 + "位",
199 + "入",
200 + "常",
201 + "文",
202 + "总",
203 + "次",
204 + "品",
205 + "式",
206 + "活",
207 + "设",
208 + "及",
209 + "管",
210 + "特",
211 + "件",
212 + "长",
213 + "求",
214 + "老",
215 + "头",
216 + "基",
217 + "资",
218 + "边",
219 + "流",
220 + "路",
221 + "级",
222 + "少",
223 + "图",
224 + "山",
225 + "统",
226 + "接",
227 + "知",
228 + "较",
229 + "将",
230 + "组",
231 + "见",
232 + "计",
233 + "别",
234 + "她",
235 + "手",
236 + "角",
237 + "期",
238 + "根",
239 + "论",
240 + "运",
241 + "农",
242 + "指",
243 + "几",
244 + "九",
245 + "区",
246 + "强",
247 + "放",
248 + "决",
249 + "西",
250 + "被",
251 + "干",
252 + "做",
253 + "必",
254 + "战",
255 + "先",
256 + "回",
257 + "则",
258 + "任",
259 + "取",
260 + "据",
261 + "处",
262 + "队",
263 + "南",
264 + "给",
265 + "色",
266 + "光",
267 + "门",
268 + "即",
269 + "保",
270 + "治",
271 + "北",
272 + "造",
273 + "百",
274 + "规",
275 + "热",
276 + "领",
277 + "七",
278 + "海",
279 + "口",
280 + "东",
281 + "导",
282 + "器",
283 + "压",
284 + "志",
285 + "世",
286 + "金",
287 + "增",
288 + "争",
289 + "济",
290 + "阶",
291 + "油",
292 + "思",
293 + "术",
294 + "极",
295 + "交",
296 + "受",
297 + "联",
298 + "什",
299 + "认",
300 + "六",
301 + "共",
302 + "权",
303 + "收",
304 + "证",
305 + "改",
306 + "清",
307 + "美",
308 + "再",
309 + "采",
310 + "转",
311 + "更",
312 + "单",
313 + "风",
314 + "切",
315 + "打",
316 + "白",
317 + "教",
318 + "速",
319 + "花",
320 + "带",
321 + "安",
322 + "场",
323 + "身",
324 + "车",
325 + "例",
326 + "真",
327 + "务",
328 + "具",
329 + "万",
330 + "每",
331 + "目",
332 + "至",
333 + "达",
334 + "走",
335 + "积",
336 + "示",
337 + "议",
338 + "声",
339 + "报",
340 + "斗",
341 + "完",
342 + "类",
343 + "八",
344 + "离",
345 + "华",
346 + "名",
347 + "确",
348 + "才",
349 + "科",
350 + "张",
351 + "信",
352 + "马",
353 + "节",
354 + "话",
355 + "米",
356 + "整",
357 + "空",
358 + "元",
359 + "况",
360 + "今",
361 + "集",
362 + "温",
363 + "传",
364 + "土",
365 + "许",
366 + "步",
367 + "群",
368 + "广",
369 + "石",
370 + "记",
371 + "需",
372 + "段",
373 + "研",
374 + "界",
375 + "拉",
376 + "林",
377 + "律",
378 + "叫",
379 + "且",
380 + "究",
381 + "观",
382 + "越",
383 + "织",
384 + "装",
385 + "影",
386 + "算",
387 + "低",
388 + "持",
389 + "音",
390 + "众",
391 + "书",
392 + "布",
393 + "复",
394 + "容",
395 + "儿",
396 + "须",
397 + "际",
398 + "商",
399 + "非",
400 + "验",
401 + "连",
402 + "断",
403 + "深",
404 + "难",
405 + "近",
406 + "矿",
407 + "千",
408 + "周",
409 + "委",
410 + "素",
411 + "技",
412 + "备",
413 + "半",
414 + "办",
415 + "青",
416 + "省",
417 + "列",
418 + "习",
419 + "响",
420 + "约",
421 + "支",
422 + "般",
423 + "史",
424 + "感",
425 + "劳",
426 + "便",
427 + "团",
428 + "往",
429 + "酸",
430 + "历",
431 + "市",
432 + "克",
433 + "何",
434 + "除",
435 + "消",
436 + "构",
437 + "府",
438 + "称",
439 + "太",
440 + "准",
441 + "精",
442 + "值",
443 + "号",
444 + "率",
445 + "族",
446 + "维",
447 + "划",
448 + "选",
449 + "标",
450 + "写",
451 + "存",
452 + "候",
453 + "毛",
454 + "亲",
455 + "快",
456 + "效",
457 + "斯",
458 + "院",
459 + "查",
460 + "江",
461 + "型",
462 + "眼",
463 + "王",
464 + "按",
465 + "格",
466 + "养",
467 + "易",
468 + "置",
469 + "派",
470 + "层",
471 + "片",
472 + "始",
473 + "却",
474 + "专",
475 + "状",
476 + "育",
477 + "厂",
478 + "京",
479 + "识",
480 + "适",
481 + "属",
482 + "圆",
483 + "包",
484 + "火",
485 + "住",
486 + "调",
487 + "满",
488 + "县",
489 + "局",
490 + "照",
491 + "参",
492 + "红",
493 + "细",
494 + "引",
495 + "听",
496 + "该",
497 + "铁",
498 + "价",
499 + "严",
500 + "首",
501 + "底",
502 + "液",
503 + "官",
504 + "德",
505 + "随",
506 + "病",
507 + "苏",
508 + "失",
509 + "尔",
510 + "死",
511 + "讲",
512 + "配",
513 + "女",
514 + "黄",
515 + "推",
516 + "显",
517 + "谈",
518 + "罪",
519 + "神",
520 + "艺",
521 + "呢",
522 + "席",
523 + "含",
524 + "企",
525 + "望",
526 + "密",
527 + "批",
528 + "营",
529 + "项",
530 + "防",
531 + "举",
532 + "球",
533 + "英",
534 + "氧",
535 + "势",
536 + "告",
537 + "李",
538 + "台",
539 + "落",
540 + "木",
541 + "帮",
542 + "轮",
543 + "破",
544 + "亚",
545 + "师",
546 + "围",
547 + "注",
548 + "远",
549 + "字",
550 + "材",
551 + "排",
552 + "供",
553 + "河",
554 + "态",
555 + "封",
556 + "另",
557 + "施",
558 + "减",
559 + "树",
560 + "溶",
561 + "怎",
562 + "止",
563 + "案",
564 + "言",
565 + "士",
566 + "均",
567 + "武",
568 + "固",
569 + "叶",
570 + "鱼",
571 + "波",
572 + "视",
573 + "仅",
574 + "费",
575 + "紧",
576 + "爱",
577 + "左",
578 + "章",
579 + "早",
580 + "朝",
581 + "害",
582 + "续",
583 + "轻",
584 + "服",
585 + "试",
586 + "食",
587 + "充",
588 + "兵",
589 + "源",
590 + "判",
591 + "护",
592 + "司",
593 + "足",
594 + "某",
595 + "练",
596 + "差",
597 + "致",
598 + "板",
599 + "田",
600 + "降",
601 + "黑",
602 + "犯",
603 + "负",
604 + "击",
605 + "范",
606 + "继",
607 + "兴",
608 + "似",
609 + "余",
610 + "坚",
611 + "曲",
612 + "输",
613 + "修",
614 + "故",
615 + "城",
616 + "夫",
617 + "够",
618 + "送",
619 + "笔",
620 + "船",
621 + "占",
622 + "右",
623 + "财",
624 + "吃",
625 + "富",
626 + "春",
627 + "职",
628 + "觉",
629 + "汉",
630 + "画",
631 + "功",
632 + "巴",
633 + "跟",
634 + "虽",
635 + "杂",
636 + "飞",
637 + "检",
638 + "吸",
639 + "助",
640 + "升",
641 + "阳",
642 + "互",
643 + "初",
644 + "创",
645 + "抗",
646 + "考",
647 + "投",
648 + "坏",
649 + "策",
650 + "古",
651 + "径",
652 + "换",
653 + "未",
654 + "跑",
655 + "留",
656 + "钢",
657 + "曾",
658 + "端",
659 + "责",
660 + "站",
661 + "简",
662 + "述",
663 + "钱",
664 + "副",
665 + "尽",
666 + "帝",
667 + "射",
668 + "草",
669 + "冲",
670 + "承",
671 + "独",
672 + "令",
673 + "限",
674 + "阿",
675 + "宣",
676 + "环",
677 + "双",
678 + "请",
679 + "超",
680 + "微",
681 + "让",
682 + "控",
683 + "州",
684 + "良",
685 + "轴",
686 + "找",
687 + "否",
688 + "纪",
689 + "益",
690 + "依",
691 + "优",
692 + "顶",
693 + "础",
694 + "载",
695 + "倒",
696 + "房",
697 + "突",
698 + "坐",
699 + "粉",
700 + "敌",
701 + "略",
702 + "客",
703 + "袁",
704 + "冷",
705 + "胜",
706 + "绝",
707 + "析",
708 + "块",
709 + "剂",
710 + "测",
711 + "丝",
712 + "协",
713 + "诉",
714 + "念",
715 + "陈",
716 + "仍",
717 + "罗",
718 + "盐",
719 + "友",
720 + "洋",
721 + "错",
722 + "苦",
723 + "夜",
724 + "刑",
725 + "移",
726 + "频",
727 + "逐",
728 + "靠",
729 + "混",
730 + "母",
731 + "短",
732 + "皮",
733 + "终",
734 + "聚",
735 + "汽",
736 + "村",
737 + "云",
738 + "哪",
739 + "既",
740 + "距",
741 + "卫",
742 + "停",
743 + "烈",
744 + "央",
745 + "察",
746 + "烧",
747 + "迅",
748 + "境",
749 + "若",
750 + "印",
751 + "洲",
752 + "刻",
753 + "括",
754 + "激",
755 + "孔",
756 + "搞",
757 + "甚",
758 + "室",
759 + "待",
760 + "核",
761 + "校",
762 + "散",
763 + "侵",
764 + "吧",
765 + "甲",
766 + "游",
767 + "久",
768 + "菜",
769 + "味",
770 + "旧",
771 + "模",
772 + "湖",
773 + "货",
774 + "损",
775 + "预",
776 + "阻",
777 + "毫",
778 + "普",
779 + "稳",
780 + "乙",
781 + "妈",
782 + "植",
783 + "息",
784 + "扩",
785 + "银",
786 + "语",
787 + "挥",
788 + "酒",
789 + "守",
790 + "拿",
791 + "序",
792 + "纸",
793 + "医",
794 + "缺",
795 + "雨",
796 + "吗",
797 + "针",
798 + "刘",
799 + "啊",
800 + "急",
801 + "唱",
802 + "误",
803 + "训",
804 + "愿",
805 + "审",
806 + "附",
807 + "获",
808 + "茶",
809 + "鲜",
810 + "粮",
811 + "斤",
812 + "孩",
813 + "脱",
814 + "硫",
815 + "肥",
816 + "善",
817 + "龙",
818 + "演",
819 + "父",
820 + "渐",
821 + "血",
822 + "欢",
823 + "械",
824 + "掌",
825 + "歌",
826 + "沙",
827 + "刚",
828 + "攻",
829 + "谓",
830 + "盾",
831 + "讨",
832 + "晚",
833 + "粒",
834 + "乱",
835 + "燃",
836 + "矛",
837 + "乎",
838 + "杀",
839 + "药",
840 + "宁",
841 + "鲁",
842 + "贵",
843 + "钟",
844 + "煤",
845 + "读",
846 + "班",
847 + "伯",
848 + "香",
849 + "介",
850 + "迫",
851 + "句",
852 + "丰",
853 + "培",
854 + "握",
855 + "兰",
856 + "担",
857 + "弦",
858 + "蛋",
859 + "沉",
860 + "假",
861 + "穿",
862 + "执",
863 + "答",
864 + "乐",
865 + "谁",
866 + "顺",
867 + "烟",
868 + "缩",
869 + "征",
870 + "脸",
871 + "喜",
872 + "松",
873 + "脚",
874 + "困",
875 + "异",
876 + "免",
877 + "背",
878 + "星",
879 + "福",
880 + "买",
881 + "染",
882 + "井",
883 + "概",
884 + "慢",
885 + "怕",
886 + "磁",
887 + "倍",
888 + "祖",
889 + "皇",
890 + "促",
891 + "静",
892 + "补",
893 + "评",
894 + "翻",
895 + "肉",
896 + "践",
897 + "尼",
898 + "衣",
899 + "宽",
900 + "扬",
901 + "棉",
902 + "希",
903 + "伤",
904 + "操",
905 + "垂",
906 + "秋",
907 + "宜",
908 + "氢",
909 + "套",
910 + "督",
911 + "振",
912 + "架",
913 + "亮",
914 + "末",
915 + "宪",
916 + "庆",
917 + "编",
918 + "牛",
919 + "触",
920 + "映",
921 + "雷",
922 + "销",
923 + "诗",
924 + "座",
925 + "居",
926 + "抓",
927 + "裂",
928 + "胞",
929 + "呼",
930 + "娘",
931 + "景",
932 + "威",
933 + "绿",
934 + "晶",
935 + "厚",
936 + "盟",
937 + "衡",
938 + "鸡",
939 + "孙",
940 + "延",
941 + "危",
942 + "胶",
943 + "屋",
944 + "乡",
945 + "临",
946 + "陆",
947 + "顾",
948 + "掉",
949 + "呀",
950 + "灯",
951 + "岁",
952 + "措",
953 + "束",
954 + "耐",
955 + "剧",
956 + "玉",
957 + "赵",
958 + "跳",
959 + "哥",
960 + "季",
961 + "课",
962 + "凯",
963 + "胡",
964 + "额",
965 + "款",
966 + "绍",
967 + "卷",
968 + "齐",
969 + "伟",
970 + "蒸",
971 + "殖",
972 + "永",
973 + "宗",
974 + "苗",
975 + "川",
976 + "炉",
977 + "岩",
978 + "弱",
979 + "零",
980 + "杨",
981 + "奏",
982 + "沿",
983 + "露",
984 + "杆",
985 + "探",
986 + "滑",
987 + "镇",
988 + "饭",
989 + "浓",
990 + "航",
991 + "怀",
992 + "赶",
993 + "库",
994 + "夺",
995 + "伊",
996 + "灵",
997 + "税",
998 + "途",
999 + "灭",
1000 + "赛",
1001 + "归",
1002 + "召",
1003 + "鼓",
1004 + "播",
1005 + "盘",
1006 + "裁",
1007 + "险",
1008 + "康",
1009 + "唯",
1010 + "录",
1011 + "菌",
1012 + "纯",
1013 + "借",
1014 + "糖",
1015 + "盖",
1016 + "横",
1017 + "符",
1018 + "私",
1019 + "努",
1020 + "堂",
1021 + "域",
1022 + "枪",
1023 + "润",
1024 + "幅",
1025 + "哈",
1026 + "竟",
1027 + "熟",
1028 + "虫",
1029 + "泽",
1030 + "脑",
1031 + "壤",
1032 + "碳",
1033 + "欧",
1034 + "遍",
1035 + "侧",
1036 + "寨",
1037 + "敢",
1038 + "彻",
1039 + "虑",
1040 + "斜",
1041 + "薄",
1042 + "庭",
1043 + "纳",
1044 + "弹",
1045 + "饲",
1046 + "伸",
1047 + "折",
1048 + "麦",
1049 + "湿",
1050 + "暗",
1051 + "荷",
1052 + "瓦",
1053 + "塞",
1054 + "床",
1055 + "筑",
1056 + "恶",
1057 + "户",
1058 + "访",
1059 + "塔",
1060 + "奇",
1061 + "透",
1062 + "梁",
1063 + "刀",
1064 + "旋",
1065 + "迹",
1066 + "卡",
1067 + "氯",
1068 + "遇",
1069 + "份",
1070 + "毒",
1071 + "泥",
1072 + "退",
1073 + "洗",
1074 + "摆",
1075 + "灰",
1076 + "彩",
1077 + "卖",
1078 + "耗",
1079 + "夏",
1080 + "择",
1081 + "忙",
1082 + "铜",
1083 + "献",
1084 + "硬",
1085 + "予",
1086 + "繁",
1087 + "圈",
1088 + "雪",
1089 + "函",
1090 + "亦",
1091 + "抽",
1092 + "篇",
1093 + "阵",
1094 + "阴",
1095 + "丁",
1096 + "尺",
1097 + "追",
1098 + "堆",
1099 + "雄",
1100 + "迎",
1101 + "泛",
1102 + "爸",
1103 + "楼",
1104 + "避",
1105 + "谋",
1106 + "吨",
1107 + "野",
1108 + "猪",
1109 + "旗",
1110 + "累",
1111 + "偏",
1112 + "典",
1113 + "馆",
1114 + "索",
1115 + "秦",
1116 + "脂",
1117 + "潮",
1118 + "爷",
1119 + "豆",
1120 + "忽",
1121 + "托",
1122 + "惊",
1123 + "塑",
1124 + "遗",
1125 + "愈",
1126 + "朱",
1127 + "替",
1128 + "纤",
1129 + "粗",
1130 + "倾",
1131 + "尚",
1132 + "痛",
1133 + "楚",
1134 + "谢",
1135 + "奋",
1136 + "购",
1137 + "磨",
1138 + "君",
1139 + "池",
1140 + "旁",
1141 + "碎",
1142 + "骨",
1143 + "监",
1144 + "捕",
1145 + "弟",
1146 + "暴",
1147 + "割",
1148 + "贯",
1149 + "殊",
1150 + "释",
1151 + "词",
1152 + "亡",
1153 + "壁",
1154 + "顿",
1155 + "宝",
1156 + "午",
1157 + "尘",
1158 + "闻",
1159 + "揭",
1160 + "炮",
1161 + "残",
1162 + "冬",
1163 + "桥",
1164 + "妇",
1165 + "警",
1166 + "综",
1167 + "招",
1168 + "吴",
1169 + "付",
1170 + "浮",
1171 + "遭",
1172 + "徐",
1173 + "您",
1174 + "摇",
1175 + "谷",
1176 + "赞",
1177 + "箱",
1178 + "隔",
1179 + "订",
1180 + "男",
1181 + "吹",
1182 + "园",
1183 + "纷",
1184 + "唐",
1185 + "败",
1186 + "宋",
1187 + "玻",
1188 + "巨",
1189 + "耕",
1190 + "坦",
1191 + "荣",
1192 + "闭",
1193 + "湾",
1194 + "键",
1195 + "凡",
1196 + "驻",
1197 + "锅",
1198 + "救",
1199 + "恩",
1200 + "剥",
1201 + "凝",
1202 + "碱",
1203 + "齿",
1204 + "截",
1205 + "炼",
1206 + "麻",
1207 + "纺",
1208 + "禁",
1209 + "废",
1210 + "盛",
1211 + "版",
1212 + "缓",
1213 + "净",
1214 + "睛",
1215 + "昌",
1216 + "婚",
1217 + "涉",
1218 + "筒",
1219 + "嘴",
1220 + "插",
1221 + "岸",
1222 + "朗",
1223 + "庄",
1224 + "街",
1225 + "藏",
1226 + "姑",
1227 + "贸",
1228 + "腐",
1229 + "奴",
1230 + "啦",
1231 + "惯",
1232 + "乘",
1233 + "伙",
1234 + "恢",
1235 + "匀",
1236 + "纱",
1237 + "扎",
1238 + "辩",
1239 + "耳",
1240 + "彪",
1241 + "臣",
1242 + "亿",
1243 + "璃",
1244 + "抵",
1245 + "脉",
1246 + "秀",
1247 + "萨",
1248 + "俄",
1249 + "网",
1250 + "舞",
1251 + "店",
1252 + "喷",
1253 + "纵",
1254 + "寸",
1255 + "汗",
1256 + "挂",
1257 + "洪",
1258 + "贺",
1259 + "闪",
1260 + "柬",
1261 + "爆",
1262 + "烯",
1263 + "津",
1264 + "稻",
1265 + "墙",
1266 + "软",
1267 + "勇",
1268 + "像",
1269 + "滚",
1270 + "厘",
1271 + "蒙",
1272 + "芳",
1273 + "肯",
1274 + "坡",
1275 + "柱",
1276 + "荡",
1277 + "腿",
1278 + "仪",
1279 + "旅",
1280 + "尾",
1281 + "轧",
1282 + "冰",
1283 + "贡",
1284 + "登",
1285 + "黎",
1286 + "削",
1287 + "钻",
1288 + "勒",
1289 + "逃",
1290 + "障",
1291 + "氨",
1292 + "郭",
1293 + "峰",
1294 + "币",
1295 + "港",
1296 + "伏",
1297 + "轨",
1298 + "亩",
1299 + "毕",
1300 + "擦",
1301 + "莫",
1302 + "刺",
1303 + "浪",
1304 + "秘",
1305 + "援",
1306 + "株",
1307 + "健",
1308 + "售",
1309 + "股",
1310 + "岛",
1311 + "甘",
1312 + "泡",
1313 + "睡",
1314 + "童",
1315 + "铸",
1316 + "汤",
1317 + "阀",
1318 + "休",
1319 + "汇",
1320 + "舍",
1321 + "牧",
1322 + "绕",
1323 + "炸",
1324 + "哲",
1325 + "磷",
1326 + "绩",
1327 + "朋",
1328 + "淡",
1329 + "尖",
1330 + "启",
1331 + "陷",
1332 + "柴",
1333 + "呈",
1334 + "徒",
1335 + "颜",
1336 + "泪",
1337 + "稍",
1338 + "忘",
1339 + "泵",
1340 + "蓝",
1341 + "拖",
1342 + "洞",
1343 + "授",
1344 + "镜",
1345 + "辛",
1346 + "壮",
1347 + "锋",
1348 + "贫",
1349 + "虚",
1350 + "弯",
1351 + "摩",
1352 + "泰",
1353 + "幼",
1354 + "廷",
1355 + "尊",
1356 + "窗",
1357 + "纲",
1358 + "弄",
1359 + "隶",
1360 + "疑",
1361 + "氏",
1362 + "宫",
1363 + "姐",
1364 + "震",
1365 + "瑞",
1366 + "怪",
1367 + "尤",
1368 + "琴",
1369 + "循",
1370 + "描",
1371 + "膜",
1372 + "违",
1373 + "夹",
1374 + "腰",
1375 + "缘",
1376 + "珠",
1377 + "穷",
1378 + "森",
1379 + "枝",
1380 + "竹",
1381 + "沟",
1382 + "催",
1383 + "绳",
1384 + "忆",
1385 + "邦",
1386 + "剩",
1387 + "幸",
1388 + "浆",
1389 + "栏",
1390 + "拥",
1391 + "牙",
1392 + "贮",
1393 + "礼",
1394 + "滤",
1395 + "钠",
1396 + "纹",
1397 + "罢",
1398 + "拍",
1399 + "咱",
1400 + "喊",
1401 + "袖",
1402 + "埃",
1403 + "勤",
1404 + "罚",
1405 + "焦",
1406 + "潜",
1407 + "伍",
1408 + "墨",
1409 + "欲",
1410 + "缝",
1411 + "姓",
1412 + "刊",
1413 + "饱",
1414 + "仿",
1415 + "奖",
1416 + "铝",
1417 + "鬼",
1418 + "丽",
1419 + "跨",
1420 + "默",
1421 + "挖",
1422 + "链",
1423 + "扫",
1424 + "喝",
1425 + "袋",
1426 + "炭",
1427 + "污",
1428 + "幕",
1429 + "诸",
1430 + "弧",
1431 + "励",
1432 + "梅",
1433 + "奶",
1434 + "洁",
1435 + "灾",
1436 + "舟",
1437 + "鉴",
1438 + "苯",
1439 + "讼",
1440 + "抱",
1441 + "毁",
1442 + "懂",
1443 + "寒",
1444 + "智",
1445 + "埔",
1446 + "寄",
1447 + "届",
1448 + "跃",
1449 + "渡",
1450 + "挑",
1451 + "丹",
1452 + "艰",
1453 + "贝",
1454 + "碰",
1455 + "拔",
1456 + "爹",
1457 + "戴",
1458 + "码",
1459 + "梦",
1460 + "芽",
1461 + "熔",
1462 + "赤",
1463 + "渔",
1464 + "哭",
1465 + "敬",
1466 + "颗",
1467 + "奔",
1468 + "铅",
1469 + "仲",
1470 + "虎",
1471 + "稀",
1472 + "妹",
1473 + "乏",
1474 + "珍",
1475 + "申",
1476 + "桌",
1477 + "遵",
1478 + "允",
1479 + "隆",
1480 + "螺",
1481 + "仓",
1482 + "魏",
1483 + "锐",
1484 + "晓",
1485 + "氮",
1486 + "兼",
1487 + "隐",
1488 + "碍",
1489 + "赫",
1490 + "拨",
1491 + "忠",
1492 + "肃",
1493 + "缸",
1494 + "牵",
1495 + "抢",
1496 + "博",
1497 + "巧",
1498 + "壳",
1499 + "兄",
1500 + "杜",
1501 + "讯",
1502 + "诚",
1503 + "碧",
1504 + "祥",
1505 + "柯",
1506 + "页",
1507 + "巡",
1508 + "矩",
1509 + "悲",
1510 + "灌",
1511 + "龄",
1512 + "伦",
1513 + "票",
1514 + "寻",
1515 + "桂",
1516 + "铺",
1517 + "圣",
1518 + "恐",
1519 + "恰",
1520 + "郑",
1521 + "趣",
1522 + "抬",
1523 + "荒",
1524 + "腾",
1525 + "贴",
1526 + "柔",
1527 + "滴",
1528 + "猛",
1529 + "阔",
1530 + "辆",
1531 + "妻",
1532 + "填",
1533 + "撤",
1534 + "储",
1535 + "签",
1536 + "闹",
1537 + "扰",
1538 + "紫",
1539 + "砂",
1540 + "递",
1541 + "戏",
1542 + "吊",
1543 + "陶",
1544 + "伐",
1545 + "喂",
1546 + "疗",
1547 + "瓶",
1548 + "婆",
1549 + "抚",
1550 + "臂",
1551 + "摸",
1552 + "忍",
1553 + "虾",
1554 + "蜡",
1555 + "邻",
1556 + "胸",
1557 + "巩",
1558 + "挤",
1559 + "偶",
1560 + "弃",
1561 + "槽",
1562 + "劲",
1563 + "乳",
1564 + "邓",
1565 + "吉",
1566 + "仁",
1567 + "烂",
1568 + "砖",
1569 + "租",
1570 + "乌",
1571 + "舰",
1572 + "伴",
1573 + "瓜",
1574 + "浅",
1575 + "丙",
1576 + "暂",
1577 + "燥",
1578 + "橡",
1579 + "柳",
1580 + "迷",
1581 + "暖",
1582 + "牌",
1583 + "秧",
1584 + "胆",
1585 + "详",
1586 + "簧",
1587 + "踏",
1588 + "瓷",
1589 + "谱",
1590 + "呆",
1591 + "宾",
1592 + "糊",
1593 + "洛",
1594 + "辉",
1595 + "愤",
1596 + "竞",
1597 + "隙",
1598 + "怒",
1599 + "粘",
1600 + "乃",
1601 + "绪",
1602 + "肩",
1603 + "籍",
1604 + "敏",
1605 + "涂",
1606 + "熙",
1607 + "皆",
1608 + "侦",
1609 + "悬",
1610 + "掘",
1611 + "享",
1612 + "纠",
1613 + "醒",
1614 + "狂",
1615 + "锁",
1616 + "淀",
1617 + "恨",
1618 + "牲",
1619 + "霸",
1620 + "爬",
1621 + "赏",
1622 + "逆",
1623 + "玩",
1624 + "陵",
1625 + "祝",
1626 + "秒",
1627 + "浙",
1628 + "貌"
1629 + ];
1630 +}
\ No newline at end of file
cw_haven/lib/mnemonics/dutch.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class DutchMnemonics {
2 + static const words = [
3 + "aalglad",
4 + "aalscholver",
5 + "aambeeld",
6 + "aangeef",
7 + "aanlandig",
8 + "aanvaard",
9 + "aanwakker",
10 + "aapmens",
11 + "aarten",
12 + "abdicatie",
13 + "abnormaal",
14 + "abrikoos",
15 + "accu",
16 + "acuut",
17 + "adjudant",
18 + "admiraal",
19 + "advies",
20 + "afbidding",
21 + "afdracht",
22 + "affaire",
23 + "affiche",
24 + "afgang",
25 + "afkick",
26 + "afknap",
27 + "aflees",
28 + "afmijner",
29 + "afname",
30 + "afpreekt",
31 + "afrader",
32 + "afspeel",
33 + "aftocht",
34 + "aftrek",
35 + "afzijdig",
36 + "ahornboom",
37 + "aktetas",
38 + "akzo",
39 + "alchemist",
40 + "alcohol",
41 + "aldaar",
42 + "alexander",
43 + "alfabet",
44 + "alfredo",
45 + "alice",
46 + "alikruik",
47 + "allrisk",
48 + "altsax",
49 + "alufolie",
50 + "alziend",
51 + "amai",
52 + "ambacht",
53 + "ambieer",
54 + "amina",
55 + "amnestie",
56 + "amok",
57 + "ampul",
58 + "amuzikaal",
59 + "angela",
60 + "aniek",
61 + "antje",
62 + "antwerpen",
63 + "anya",
64 + "aorta",
65 + "apache",
66 + "apekool",
67 + "appelaar",
68 + "arganolie",
69 + "argeloos",
70 + "armoede",
71 + "arrenslee",
72 + "artritis",
73 + "arubaan",
74 + "asbak",
75 + "ascii",
76 + "asgrauw",
77 + "asjes",
78 + "asml",
79 + "aspunt",
80 + "asurn",
81 + "asveld",
82 + "aterling",
83 + "atomair",
84 + "atrium",
85 + "atsma",
86 + "atypisch",
87 + "auping",
88 + "aura",
89 + "avifauna",
90 + "axiaal",
91 + "azoriaan",
92 + "azteek",
93 + "azuur",
94 + "bachelor",
95 + "badderen",
96 + "badhotel",
97 + "badmantel",
98 + "badsteden",
99 + "balie",
100 + "ballans",
101 + "balvers",
102 + "bamibal",
103 + "banneling",
104 + "barracuda",
105 + "basaal",
106 + "batelaan",
107 + "batje",
108 + "beambte",
109 + "bedlamp",
110 + "bedwelmd",
111 + "befaamd",
112 + "begierd",
113 + "begraaf",
114 + "behield",
115 + "beijaard",
116 + "bejaagd",
117 + "bekaaid",
118 + "beks",
119 + "bektas",
120 + "belaad",
121 + "belboei",
122 + "belderbos",
123 + "beloerd",
124 + "beluchten",
125 + "bemiddeld",
126 + "benadeeld",
127 + "benijd",
128 + "berechten",
129 + "beroemd",
130 + "besef",
131 + "besseling",
132 + "best",
133 + "betichten",
134 + "bevind",
135 + "bevochten",
136 + "bevraagd",
137 + "bewust",
138 + "bidplaats",
139 + "biefstuk",
140 + "biemans",
141 + "biezen",
142 + "bijbaan",
143 + "bijeenkom",
144 + "bijfiguur",
145 + "bijkaart",
146 + "bijlage",
147 + "bijpaard",
148 + "bijtgaar",
149 + "bijweg",
150 + "bimmel",
151 + "binck",
152 + "bint",
153 + "biobak",
154 + "biotisch",
155 + "biseks",
156 + "bistro",
157 + "bitter",
158 + "bitumen",
159 + "bizar",
160 + "blad",
161 + "bleken",
162 + "blender",
163 + "bleu",
164 + "blief",
165 + "blijven",
166 + "blozen",
167 + "bock",
168 + "boef",
169 + "boei",
170 + "boks",
171 + "bolder",
172 + "bolus",
173 + "bolvormig",
174 + "bomaanval",
175 + "bombarde",
176 + "bomma",
177 + "bomtapijt",
178 + "bookmaker",
179 + "boos",
180 + "borg",
181 + "bosbes",
182 + "boshuizen",
183 + "bosloop",
184 + "botanicus",
185 + "bougie",
186 + "bovag",
187 + "boxspring",
188 + "braad",
189 + "brasem",
190 + "brevet",
191 + "brigade",
192 + "brinckman",
193 + "bruid",
194 + "budget",
195 + "buffel",
196 + "buks",
197 + "bulgaar",
198 + "buma",
199 + "butaan",
200 + "butler",
201 + "buuf",
202 + "cactus",
203 + "cafeetje",
204 + "camcorder",
205 + "cannabis",
206 + "canyon",
207 + "capoeira",
208 + "capsule",
209 + "carkit",
210 + "casanova",
211 + "catalaan",
212 + "ceintuur",
213 + "celdeling",
214 + "celplasma",
215 + "cement",
216 + "censeren",
217 + "ceramisch",
218 + "cerberus",
219 + "cerebraal",
220 + "cesium",
221 + "cirkel",
222 + "citeer",
223 + "civiel",
224 + "claxon",
225 + "clenbuterol",
226 + "clicheren",
227 + "clijsen",
228 + "coalitie",
229 + "coassistentschap",
230 + "coaxiaal",
231 + "codetaal",
232 + "cofinanciering",
233 + "cognac",
234 + "coltrui",
235 + "comfort",
236 + "commandant",
237 + "condensaat",
238 + "confectie",
239 + "conifeer",
240 + "convector",
241 + "copier",
242 + "corfu",
243 + "correct",
244 + "coup",
245 + "couvert",
246 + "creatie",
247 + "credit",
248 + "crematie",
249 + "cricket",
250 + "croupier",
251 + "cruciaal",
252 + "cruijff",
253 + "cuisine",
254 + "culemborg",
255 + "culinair",
256 + "curve",
257 + "cyrano",
258 + "dactylus",
259 + "dading",
260 + "dagblind",
261 + "dagje",
262 + "daglicht",
263 + "dagprijs",
264 + "dagranden",
265 + "dakdekker",
266 + "dakpark",
267 + "dakterras",
268 + "dalgrond",
269 + "dambord",
270 + "damkat",
271 + "damlengte",
272 + "damman",
273 + "danenberg",
274 + "debbie",
275 + "decibel",
276 + "defect",
277 + "deformeer",
278 + "degelijk",
279 + "degradant",
280 + "dejonghe",
281 + "dekken",
282 + "deppen",
283 + "derek",
284 + "derf",
285 + "derhalve",
286 + "detineren",
287 + "devalueer",
288 + "diaken",
289 + "dicht",
290 + "dictaat",
291 + "dief",
292 + "digitaal",
293 + "dijbreuk",
294 + "dijkmans",
295 + "dimbaar",
296 + "dinsdag",
297 + "diode",
298 + "dirigeer",
299 + "disbalans",
300 + "dobermann",
301 + "doenbaar",
302 + "doerak",
303 + "dogma",
304 + "dokhaven",
305 + "dokwerker",
306 + "doling",
307 + "dolphijn",
308 + "dolven",
309 + "dombo",
310 + "dooraderd",
311 + "dopeling",
312 + "doping",
313 + "draderig",
314 + "drama",
315 + "drenkbak",
316 + "dreumes",
317 + "drol",
318 + "drug",
319 + "duaal",
320 + "dublin",
321 + "duplicaat",
322 + "durven",
323 + "dusdanig",
324 + "dutchbat",
325 + "dutje",
326 + "dutten",
327 + "duur",
328 + "duwwerk",
329 + "dwaal",
330 + "dweil",
331 + "dwing",
332 + "dyslexie",
333 + "ecostroom",
334 + "ecotaks",
335 + "educatie",
336 + "eeckhout",
337 + "eede",
338 + "eemland",
339 + "eencellig",
340 + "eeneiig",
341 + "eenruiter",
342 + "eenwinter",
343 + "eerenberg",
344 + "eerrover",
345 + "eersel",
346 + "eetmaal",
347 + "efteling",
348 + "egaal",
349 + "egtberts",
350 + "eickhoff",
351 + "eidooier",
352 + "eiland",
353 + "eind",
354 + "eisden",
355 + "ekster",
356 + "elburg",
357 + "elevatie",
358 + "elfkoppig",
359 + "elfrink",
360 + "elftal",
361 + "elimineer",
362 + "elleboog",
363 + "elma",
364 + "elodie",
365 + "elsa",
366 + "embleem",
367 + "embolie",
368 + "emoe",
369 + "emonds",
370 + "emplooi",
371 + "enduro",
372 + "enfin",
373 + "engageer",
374 + "entourage",
375 + "entstof",
376 + "epileer",
377 + "episch",
378 + "eppo",
379 + "erasmus",
380 + "erboven",
381 + "erebaan",
382 + "erelijst",
383 + "ereronden",
384 + "ereteken",
385 + "erfhuis",
386 + "erfwet",
387 + "erger",
388 + "erica",
389 + "ermitage",
390 + "erna",
391 + "ernie",
392 + "erts",
393 + "ertussen",
394 + "eruitzien",
395 + "ervaar",
396 + "erven",
397 + "erwt",
398 + "esbeek",
399 + "escort",
400 + "esdoorn",
401 + "essing",
402 + "etage",
403 + "eter",
404 + "ethanol",
405 + "ethicus",
406 + "etholoog",
407 + "eufonisch",
408 + "eurocent",
409 + "evacuatie",
410 + "exact",
411 + "examen",
412 + "executant",
413 + "exen",
414 + "exit",
415 + "exogeen",
416 + "exotherm",
417 + "expeditie",
418 + "expletief",
419 + "expres",
420 + "extase",
421 + "extinctie",
422 + "faal",
423 + "faam",
424 + "fabel",
425 + "facultair",
426 + "fakir",
427 + "fakkel",
428 + "faliekant",
429 + "fallisch",
430 + "famke",
431 + "fanclub",
432 + "fase",
433 + "fatsoen",
434 + "fauna",
435 + "federaal",
436 + "feedback",
437 + "feest",
438 + "feilbaar",
439 + "feitelijk",
440 + "felblauw",
441 + "figurante",
442 + "fiod",
443 + "fitheid",
444 + "fixeer",
445 + "flap",
446 + "fleece",
447 + "fleur",
448 + "flexibel",
449 + "flits",
450 + "flos",
451 + "flow",
452 + "fluweel",
453 + "foezelen",
454 + "fokkelman",
455 + "fokpaard",
456 + "fokvee",
457 + "folder",
458 + "follikel",
459 + "folmer",
460 + "folteraar",
461 + "fooi",
462 + "foolen",
463 + "forfait",
464 + "forint",
465 + "formule",
466 + "fornuis",
467 + "fosfaat",
468 + "foxtrot",
469 + "foyer",
470 + "fragiel",
471 + "frater",
472 + "freak",
473 + "freddie",
474 + "fregat",
475 + "freon",
476 + "frijnen",
477 + "fructose",
478 + "frunniken",
479 + "fuiven",
480 + "funshop",
481 + "furieus",
482 + "fysica",
483 + "gadget",
484 + "galder",
485 + "galei",
486 + "galg",
487 + "galvlieg",
488 + "galzuur",
489 + "ganesh",
490 + "gaswet",
491 + "gaza",
492 + "gazelle",
493 + "geaaid",
494 + "gebiecht",
495 + "gebufferd",
496 + "gedijd",
497 + "geef",
498 + "geflanst",
499 + "gefreesd",
500 + "gegaan",
501 + "gegijzeld",
502 + "gegniffel",
503 + "gegraaid",
504 + "gehikt",
505 + "gehobbeld",
506 + "gehucht",
507 + "geiser",
508 + "geiten",
509 + "gekaakt",
510 + "gekheid",
511 + "gekijf",
512 + "gekmakend",
513 + "gekocht",
514 + "gekskap",
515 + "gekte",
516 + "gelubberd",
517 + "gemiddeld",
518 + "geordend",
519 + "gepoederd",
520 + "gepuft",
521 + "gerda",
522 + "gerijpt",
523 + "geseald",
524 + "geshockt",
525 + "gesierd",
526 + "geslaagd",
527 + "gesnaaid",
528 + "getracht",
529 + "getwijfel",
530 + "geuit",
531 + "gevecht",
532 + "gevlagd",
533 + "gewicht",
534 + "gezaagd",
535 + "gezocht",
536 + "ghanees",
537 + "giebelen",
538 + "giechel",
539 + "giepmans",
540 + "gips",
541 + "giraal",
542 + "gistachtig",
543 + "gitaar",
544 + "glaasje",
545 + "gletsjer",
546 + "gleuf",
547 + "glibberen",
548 + "glijbaan",
549 + "gloren",
550 + "gluipen",
551 + "gluren",
552 + "gluur",
553 + "gnoe",
554 + "goddelijk",
555 + "godgans",
556 + "godschalk",
557 + "godzalig",
558 + "goeierd",
559 + "gogme",
560 + "goklustig",
561 + "gokwereld",
562 + "gonggrijp",
563 + "gonje",
564 + "goor",
565 + "grabbel",
566 + "graf",
567 + "graveer",
568 + "grif",
569 + "grolleman",
570 + "grom",
571 + "groosman",
572 + "grubben",
573 + "gruijs",
574 + "grut",
575 + "guacamole",
576 + "guido",
577 + "guppy",
578 + "haazen",
579 + "hachelijk",
580 + "haex",
581 + "haiku",
582 + "hakhout",
583 + "hakken",
584 + "hanegem",
585 + "hans",
586 + "hanteer",
587 + "harrie",
588 + "hazebroek",
589 + "hedonist",
590 + "heil",
591 + "heineken",
592 + "hekhuis",
593 + "hekman",
594 + "helbig",
595 + "helga",
596 + "helwegen",
597 + "hengelaar",
598 + "herkansen",
599 + "hermafrodiet",
600 + "hertaald",
601 + "hiaat",
602 + "hikspoors",
603 + "hitachi",
604 + "hitparade",
605 + "hobo",
606 + "hoeve",
607 + "holocaust",
608 + "hond",
609 + "honnepon",
610 + "hoogacht",
611 + "hotelbed",
612 + "hufter",
613 + "hugo",
614 + "huilbier",
615 + "hulk",
616 + "humus",
617 + "huwbaar",
618 + "huwelijk",
619 + "hype",
620 + "iconisch",
621 + "idema",
622 + "ideogram",
623 + "idolaat",
624 + "ietje",
625 + "ijker",
626 + "ijkheid",
627 + "ijklijn",
628 + "ijkmaat",
629 + "ijkwezen",
630 + "ijmuiden",
631 + "ijsbox",
632 + "ijsdag",
633 + "ijselijk",
634 + "ijskoud",
635 + "ilse",
636 + "immuun",
637 + "impliceer",
638 + "impuls",
639 + "inbijten",
640 + "inbuigen",
641 + "indijken",
642 + "induceer",
643 + "indy",
644 + "infecteer",
645 + "inhaak",
646 + "inkijk",
647 + "inluiden",
648 + "inmijnen",
649 + "inoefenen",
650 + "inpolder",
651 + "inrijden",
652 + "inslaan",
653 + "invitatie",
654 + "inwaaien",
655 + "ionisch",
656 + "isaac",
657 + "isolatie",
658 + "isotherm",
659 + "isra",
660 + "italiaan",
661 + "ivoor",
662 + "jacobs",
663 + "jakob",
664 + "jammen",
665 + "jampot",
666 + "jarig",
667 + "jehova",
668 + "jenever",
669 + "jezus",
670 + "joana",
671 + "jobdienst",
672 + "josua",
673 + "joule",
674 + "juich",
675 + "jurk",
676 + "juut",
677 + "kaas",
678 + "kabelaar",
679 + "kabinet",
680 + "kagenaar",
681 + "kajuit",
682 + "kalebas",
683 + "kalm",
684 + "kanjer",
685 + "kapucijn",
686 + "karregat",
687 + "kart",
688 + "katvanger",
689 + "katwijk",
690 + "kegelaar",
691 + "keiachtig",
692 + "keizer",
693 + "kenletter",
694 + "kerdijk",
695 + "keus",
696 + "kevlar",
697 + "kezen",
698 + "kickback",
699 + "kieviet",
700 + "kijken",
701 + "kikvors",
702 + "kilheid",
703 + "kilobit",
704 + "kilsdonk",
705 + "kipschnitzel",
706 + "kissebis",
707 + "klad",
708 + "klagelijk",
709 + "klak",
710 + "klapbaar",
711 + "klaver",
712 + "klene",
713 + "klets",
714 + "klijnhout",
715 + "klit",
716 + "klok",
717 + "klonen",
718 + "klotefilm",
719 + "kluif",
720 + "klumper",
721 + "klus",
722 + "knabbel",
723 + "knagen",
724 + "knaven",
725 + "kneedbaar",
726 + "knmi",
727 + "knul",
728 + "knus",
729 + "kokhals",
730 + "komiek",
731 + "komkommer",
732 + "kompaan",
733 + "komrij",
734 + "komvormig",
735 + "koning",
736 + "kopbal",
737 + "kopklep",
738 + "kopnagel",
739 + "koppejan",
740 + "koptekst",
741 + "kopwand",
742 + "koraal",
743 + "kosmisch",
744 + "kostbaar",
745 + "kram",
746 + "kraneveld",
747 + "kras",
748 + "kreling",
749 + "krengen",
750 + "kribbe",
751 + "krik",
752 + "kruid",
753 + "krulbol",
754 + "kuijper",
755 + "kuipbank",
756 + "kuit",
757 + "kuiven",
758 + "kutsmoes",
759 + "kuub",
760 + "kwak",
761 + "kwatong",
762 + "kwetsbaar",
763 + "kwezelaar",
764 + "kwijnen",
765 + "kwik",
766 + "kwinkslag",
767 + "kwitantie",
768 + "lading",
769 + "lakbeits",
770 + "lakken",
771 + "laklaag",
772 + "lakmoes",
773 + "lakwijk",
774 + "lamheid",
775 + "lamp",
776 + "lamsbout",
777 + "lapmiddel",
778 + "larve",
779 + "laser",
780 + "latijn",
781 + "latuw",
782 + "lawaai",
783 + "laxeerpil",
784 + "lebberen",
785 + "ledeboer",
786 + "leefbaar",
787 + "leeman",
788 + "lefdoekje",
789 + "lefhebber",
790 + "legboor",
791 + "legsel",
792 + "leguaan",
793 + "leiplaat",
794 + "lekdicht",
795 + "lekrijden",
796 + "leksteen",
797 + "lenen",
798 + "leraar",
799 + "lesbienne",
800 + "leugenaar",
801 + "leut",
802 + "lexicaal",
803 + "lezing",
804 + "lieten",
805 + "liggeld",
806 + "lijdzaam",
807 + "lijk",
808 + "lijmstang",
809 + "lijnschip",
810 + "likdoorn",
811 + "likken",
812 + "liksteen",
813 + "limburg",
814 + "link",
815 + "linoleum",
816 + "lipbloem",
817 + "lipman",
818 + "lispelen",
819 + "lissabon",
820 + "litanie",
821 + "liturgie",
822 + "lochem",
823 + "loempia",
824 + "loesje",
825 + "logheid",
826 + "lonen",
827 + "lonneke",
828 + "loom",
829 + "loos",
830 + "losbaar",
831 + "loslaten",
832 + "losplaats",
833 + "loting",
834 + "lotnummer",
835 + "lots",
836 + "louie",
837 + "lourdes",
838 + "louter",
839 + "lowbudget",
840 + "luijten",
841 + "luikenaar",
842 + "luilak",
843 + "luipaard",
844 + "luizenbos",
845 + "lulkoek",
846 + "lumen",
847 + "lunzen",
848 + "lurven",
849 + "lutjeboer",
850 + "luttel",
851 + "lutz",
852 + "luuk",
853 + "luwte",
854 + "luyendijk",
855 + "lyceum",
856 + "lynx",
857 + "maakbaar",
858 + "magdalena",
859 + "malheid",
860 + "manchet",
861 + "manfred",
862 + "manhaftig",
863 + "mank",
864 + "mantel",
865 + "marion",
866 + "marxist",
867 + "masmeijer",
868 + "massaal",
869 + "matsen",
870 + "matverf",
871 + "matze",
872 + "maude",
873 + "mayonaise",
874 + "mechanica",
875 + "meifeest",
876 + "melodie",
877 + "meppelink",
878 + "midvoor",
879 + "midweeks",
880 + "midzomer",
881 + "miezel",
882 + "mijnraad",
883 + "minus",
884 + "mirck",
885 + "mirte",
886 + "mispakken",
887 + "misraden",
888 + "miswassen",
889 + "mitella",
890 + "moker",
891 + "molecule",
892 + "mombakkes",
893 + "moonen",
894 + "mopperaar",
895 + "moraal",
896 + "morgana",
897 + "mormel",
898 + "mosselaar",
899 + "motregen",
900 + "mouw",
901 + "mufheid",
902 + "mutueel",
903 + "muzelman",
904 + "naaidoos",
905 + "naald",
906 + "nadeel",
907 + "nadruk",
908 + "nagy",
909 + "nahon",
910 + "naima",
911 + "nairobi",
912 + "napalm",
913 + "napels",
914 + "napijn",
915 + "napoleon",
916 + "narigheid",
917 + "narratief",
918 + "naseizoen",
919 + "nasibal",
920 + "navigatie",
921 + "nawijn",
922 + "negatief",
923 + "nekletsel",
924 + "nekwervel",
925 + "neolatijn",
926 + "neonataal",
927 + "neptunus",
928 + "nerd",
929 + "nest",
930 + "neuzelaar",
931 + "nihiliste",
932 + "nijenhuis",
933 + "nijging",
934 + "nijhoff",
935 + "nijl",
936 + "nijptang",
937 + "nippel",
938 + "nokkenas",
939 + "noordam",
940 + "noren",
941 + "normaal",
942 + "nottelman",
943 + "notulant",
944 + "nout",
945 + "nuance",
946 + "nuchter",
947 + "nudorp",
948 + "nulde",
949 + "nullijn",
950 + "nulmeting",
951 + "nunspeet",
952 + "nylon",
953 + "obelisk",
954 + "object",
955 + "oblie",
956 + "obsceen",
957 + "occlusie",
958 + "oceaan",
959 + "ochtend",
960 + "ockhuizen",
961 + "oerdom",
962 + "oergezond",
963 + "oerlaag",
964 + "oester",
965 + "okhuijsen",
966 + "olifant",
967 + "olijfboer",
968 + "omaans",
969 + "ombudsman",
970 + "omdat",
971 + "omdijken",
972 + "omdoen",
973 + "omgebouwd",
974 + "omkeer",
975 + "omkomen",
976 + "ommegaand",
977 + "ommuren",
978 + "omroep",
979 + "omruil",
980 + "omslaan",
981 + "omsmeden",
982 + "omvaar",
983 + "onaardig",
984 + "onedel",
985 + "onenig",
986 + "onheilig",
987 + "onrecht",
988 + "onroerend",
989 + "ontcijfer",
990 + "onthaal",
991 + "ontvallen",
992 + "ontzadeld",
993 + "onzacht",
994 + "onzin",
995 + "onzuiver",
996 + "oogappel",
997 + "ooibos",
998 + "ooievaar",
999 + "ooit",
1000 + "oorarts",
1001 + "oorhanger",
1002 + "oorijzer",
1003 + "oorklep",
1004 + "oorschelp",
1005 + "oorworm",
1006 + "oorzaak",
1007 + "opdagen",
1008 + "opdien",
1009 + "opdweilen",
1010 + "opel",
1011 + "opgebaard",
1012 + "opinie",
1013 + "opjutten",
1014 + "opkijken",
1015 + "opklaar",
1016 + "opkuisen",
1017 + "opkwam",
1018 + "opnaaien",
1019 + "opossum",
1020 + "opsieren",
1021 + "opsmeer",
1022 + "optreden",
1023 + "opvijzel",
1024 + "opvlammen",
1025 + "opwind",
1026 + "oraal",
1027 + "orchidee",
1028 + "orkest",
1029 + "ossuarium",
1030 + "ostendorf",
1031 + "oublie",
1032 + "oudachtig",
1033 + "oudbakken",
1034 + "oudnoors",
1035 + "oudshoorn",
1036 + "oudtante",
1037 + "oven",
1038 + "over",
1039 + "oxidant",
1040 + "pablo",
1041 + "pacht",
1042 + "paktafel",
1043 + "pakzadel",
1044 + "paljas",
1045 + "panharing",
1046 + "papfles",
1047 + "paprika",
1048 + "parochie",
1049 + "paus",
1050 + "pauze",
1051 + "paviljoen",
1052 + "peek",
1053 + "pegel",
1054 + "peigeren",
1055 + "pekela",
1056 + "pendant",
1057 + "penibel",
1058 + "pepmiddel",
1059 + "peptalk",
1060 + "periferie",
1061 + "perron",
1062 + "pessarium",
1063 + "peter",
1064 + "petfles",
1065 + "petgat",
1066 + "peuk",
1067 + "pfeifer",
1068 + "picknick",
1069 + "pief",
1070 + "pieneman",
1071 + "pijlkruid",
1072 + "pijnacker",
1073 + "pijpelink",
1074 + "pikdonker",
1075 + "pikeer",
1076 + "pilaar",
1077 + "pionier",
1078 + "pipet",
1079 + "piscine",
1080 + "pissebed",
1081 + "pitchen",
1082 + "pixel",
1083 + "plamuren",
1084 + "plan",
1085 + "plausibel",
1086 + "plegen",
1087 + "plempen",
1088 + "pleonasme",
1089 + "plezant",
1090 + "podoloog",
1091 + "pofmouw",
1092 + "pokdalig",
1093 + "ponywagen",
1094 + "popachtig",
1095 + "popidool",
1096 + "porren",
1097 + "positie",
1098 + "potten",
1099 + "pralen",
1100 + "prezen",
1101 + "prijzen",
1102 + "privaat",
1103 + "proef",
1104 + "prooi",
1105 + "prozawerk",
1106 + "pruik",
1107 + "prul",
1108 + "publiceer",
1109 + "puck",
1110 + "puilen",
1111 + "pukkelig",
1112 + "pulveren",
1113 + "pupil",
1114 + "puppy",
1115 + "purmerend",
1116 + "pustjens",
1117 + "putemmer",
1118 + "puzzelaar",
1119 + "queenie",
1120 + "quiche",
1121 + "raam",
1122 + "raar",
1123 + "raat",
1124 + "raes",
1125 + "ralf",
1126 + "rally",
1127 + "ramona",
1128 + "ramselaar",
1129 + "ranonkel",
1130 + "rapen",
1131 + "rapunzel",
1132 + "rarekiek",
1133 + "rarigheid",
1134 + "rattenhol",
1135 + "ravage",
1136 + "reactie",
1137 + "recreant",
1138 + "redacteur",
1139 + "redster",
1140 + "reewild",
1141 + "regie",
1142 + "reijnders",
1143 + "rein",
1144 + "replica",
1145 + "revanche",
1146 + "rigide",
1147 + "rijbaan",
1148 + "rijdansen",
1149 + "rijgen",
1150 + "rijkdom",
1151 + "rijles",
1152 + "rijnwijn",
1153 + "rijpma",
1154 + "rijstafel",
1155 + "rijtaak",
1156 + "rijzwepen",
1157 + "rioleer",
1158 + "ripdeal",
1159 + "riphagen",
1160 + "riskant",
1161 + "rits",
1162 + "rivaal",
1163 + "robbedoes",
1164 + "robot",
1165 + "rockact",
1166 + "rodijk",
1167 + "rogier",
1168 + "rohypnol",
1169 + "rollaag",
1170 + "rolpaal",
1171 + "roltafel",
1172 + "roof",
1173 + "roon",
1174 + "roppen",
1175 + "rosbief",
1176 + "rosharig",
1177 + "rosielle",
1178 + "rotan",
1179 + "rotleven",
1180 + "rotten",
1181 + "rotvaart",
1182 + "royaal",
1183 + "royeer",
1184 + "rubato",
1185 + "ruby",
1186 + "ruche",
1187 + "rudge",
1188 + "ruggetje",
1189 + "rugnummer",
1190 + "rugpijn",
1191 + "rugtitel",
1192 + "rugzak",
1193 + "ruilbaar",
1194 + "ruis",
1195 + "ruit",
1196 + "rukwind",
1197 + "rulijs",
1198 + "rumoeren",
1199 + "rumsdorp",
1200 + "rumtaart",
1201 + "runnen",
1202 + "russchen",
1203 + "ruwkruid",
1204 + "saboteer",
1205 + "saksisch",
1206 + "salade",
1207 + "salpeter",
1208 + "sambabal",
1209 + "samsam",
1210 + "satelliet",
1211 + "satineer",
1212 + "saus",
1213 + "scampi",
1214 + "scarabee",
1215 + "scenario",
1216 + "schobben",
1217 + "schubben",
1218 + "scout",
1219 + "secessie",
1220 + "secondair",
1221 + "seculair",
1222 + "sediment",
1223 + "seeland",
1224 + "settelen",
1225 + "setwinst",
1226 + "sheriff",
1227 + "shiatsu",
1228 + "siciliaan",
1229 + "sidderaal",
1230 + "sigma",
1231 + "sijben",
1232 + "silvana",
1233 + "simkaart",
1234 + "sinds",
1235 + "situatie",
1236 + "sjaak",
1237 + "sjardijn",
1238 + "sjezen",
1239 + "sjor",
1240 + "skinhead",
1241 + "skylab",
1242 + "slamixen",
1243 + "sleijpen",
1244 + "slijkerig",
1245 + "slordig",
1246 + "slowaak",
1247 + "sluieren",
1248 + "smadelijk",
1249 + "smiecht",
1250 + "smoel",
1251 + "smos",
1252 + "smukken",
1253 + "snackcar",
1254 + "snavel",
1255 + "sneaker",
1256 + "sneu",
1257 + "snijdbaar",
1258 + "snit",
1259 + "snorder",
1260 + "soapbox",
1261 + "soetekouw",
1262 + "soigneren",
1263 + "sojaboon",
1264 + "solo",
1265 + "solvabel",
1266 + "somber",
1267 + "sommatie",
1268 + "soort",
1269 + "soppen",
1270 + "sopraan",
1271 + "soundbar",
1272 + "spanen",
1273 + "spawater",
1274 + "spijgat",
1275 + "spinaal",
1276 + "spionage",
1277 + "spiraal",
1278 + "spleet",
1279 + "splijt",
1280 + "spoed",
1281 + "sporen",
1282 + "spul",
1283 + "spuug",
1284 + "spuw",
1285 + "stalen",
1286 + "standaard",
1287 + "star",
1288 + "stefan",
1289 + "stencil",
1290 + "stijf",
1291 + "stil",
1292 + "stip",
1293 + "stopdas",
1294 + "stoten",
1295 + "stoven",
1296 + "straat",
1297 + "strobbe",
1298 + "strubbel",
1299 + "stucadoor",
1300 + "stuif",
1301 + "stukadoor",
1302 + "subhoofd",
1303 + "subregent",
1304 + "sudoku",
1305 + "sukade",
1306 + "sulfaat",
1307 + "surinaams",
1308 + "suus",
1309 + "syfilis",
1310 + "symboliek",
1311 + "sympathie",
1312 + "synagoge",
1313 + "synchroon",
1314 + "synergie",
1315 + "systeem",
1316 + "taanderij",
1317 + "tabak",
1318 + "tachtig",
1319 + "tackelen",
1320 + "taiwanees",
1321 + "talman",
1322 + "tamheid",
1323 + "tangaslip",
1324 + "taps",
1325 + "tarkan",
1326 + "tarwe",
1327 + "tasman",
1328 + "tatjana",
1329 + "taxameter",
1330 + "teil",
1331 + "teisman",
1332 + "telbaar",
1333 + "telco",
1334 + "telganger",
1335 + "telstar",
1336 + "tenant",
1337 + "tepel",
1338 + "terzet",
1339 + "testament",
1340 + "ticket",
1341 + "tiesinga",
1342 + "tijdelijk",
1343 + "tika",
1344 + "tiksel",
1345 + "tilleman",
1346 + "timbaal",
1347 + "tinsteen",
1348 + "tiplijn",
1349 + "tippelaar",
1350 + "tjirpen",
1351 + "toezeggen",
1352 + "tolbaas",
1353 + "tolgeld",
1354 + "tolhek",
1355 + "tolo",
1356 + "tolpoort",
1357 + "toltarief",
1358 + "tolvrij",
1359 + "tomaat",
1360 + "tondeuse",
1361 + "toog",
1362 + "tooi",
1363 + "toonbaar",
1364 + "toos",
1365 + "topclub",
1366 + "toppen",
1367 + "toptalent",
1368 + "topvrouw",
1369 + "toque",
1370 + "torment",
1371 + "tornado",
1372 + "tosti",
1373 + "totdat",
1374 + "toucheer",
1375 + "toulouse",
1376 + "tournedos",
1377 + "tout",
1378 + "trabant",
1379 + "tragedie",
1380 + "trailer",
1381 + "traject",
1382 + "traktaat",
1383 + "trauma",
1384 + "tray",
1385 + "trechter",
1386 + "tred",
1387 + "tref",
1388 + "treur",
1389 + "troebel",
1390 + "tros",
1391 + "trucage",
1392 + "truffel",
1393 + "tsaar",
1394 + "tucht",
1395 + "tuenter",
1396 + "tuitelig",
1397 + "tukje",
1398 + "tuktuk",
1399 + "tulp",
1400 + "tuma",
1401 + "tureluurs",
1402 + "twijfel",
1403 + "twitteren",
1404 + "tyfoon",
1405 + "typograaf",
1406 + "ugandees",
1407 + "uiachtig",
1408 + "uier",
1409 + "uisnipper",
1410 + "ultiem",
1411 + "unitair",
1412 + "uranium",
1413 + "urbaan",
1414 + "urendag",
1415 + "ursula",
1416 + "uurcirkel",
1417 + "uurglas",
1418 + "uzelf",
1419 + "vaat",
1420 + "vakantie",
1421 + "vakleraar",
1422 + "valbijl",
1423 + "valpartij",
1424 + "valreep",
1425 + "valuatie",
1426 + "vanmiddag",
1427 + "vanonder",
1428 + "varaan",
1429 + "varken",
1430 + "vaten",
1431 + "veenbes",
1432 + "veeteler",
1433 + "velgrem",
1434 + "vellekoop",
1435 + "velvet",
1436 + "veneberg",
1437 + "venlo",
1438 + "vent",
1439 + "venusberg",
1440 + "venw",
1441 + "veredeld",
1442 + "verf",
1443 + "verhaaf",
1444 + "vermaak",
1445 + "vernaaid",
1446 + "verraad",
1447 + "vers",
1448 + "veruit",
1449 + "verzaagd",
1450 + "vetachtig",
1451 + "vetlok",
1452 + "vetmesten",
1453 + "veto",
1454 + "vetrek",
1455 + "vetstaart",
1456 + "vetten",
1457 + "veurink",
1458 + "viaduct",
1459 + "vibrafoon",
1460 + "vicariaat",
1461 + "vieux",
1462 + "vieveen",
1463 + "vijfvoud",
1464 + "villa",
1465 + "vilt",
1466 + "vimmetje",
1467 + "vindbaar",
1468 + "vips",
1469 + "virtueel",
1470 + "visdieven",
1471 + "visee",
1472 + "visie",
1473 + "vlaag",
1474 + "vleugel",
1475 + "vmbo",
1476 + "vocht",
1477 + "voesenek",
1478 + "voicemail",
1479 + "voip",
1480 + "volg",
1481 + "vork",
1482 + "vorselaar",
1483 + "voyeur",
1484 + "vracht",
1485 + "vrekkig",
1486 + "vreten",
1487 + "vrije",
1488 + "vrozen",
1489 + "vrucht",
1490 + "vucht",
1491 + "vugt",
1492 + "vulkaan",
1493 + "vulmiddel",
1494 + "vulva",
1495 + "vuren",
1496 + "waas",
1497 + "wacht",
1498 + "wadvogel",
1499 + "wafel",
1500 + "waffel",
1501 + "walhalla",
1502 + "walnoot",
1503 + "walraven",
1504 + "wals",
1505 + "walvis",
1506 + "wandaad",
1507 + "wanen",
1508 + "wanmolen",
1509 + "want",
1510 + "warklomp",
1511 + "warm",
1512 + "wasachtig",
1513 + "wasteil",
1514 + "watt",
1515 + "webhandel",
1516 + "weblog",
1517 + "webpagina",
1518 + "webzine",
1519 + "wedereis",
1520 + "wedstrijd",
1521 + "weeda",
1522 + "weert",
1523 + "wegmaaien",
1524 + "wegscheer",
1525 + "wekelijks",
1526 + "wekken",
1527 + "wekroep",
1528 + "wektoon",
1529 + "weldaad",
1530 + "welwater",
1531 + "wendbaar",
1532 + "wenkbrauw",
1533 + "wens",
1534 + "wentelaar",
1535 + "wervel",
1536 + "wesseling",
1537 + "wetboek",
1538 + "wetmatig",
1539 + "whirlpool",
1540 + "wijbrands",
1541 + "wijdbeens",
1542 + "wijk",
1543 + "wijnbes",
1544 + "wijting",
1545 + "wild",
1546 + "wimpelen",
1547 + "wingebied",
1548 + "winplaats",
1549 + "winter",
1550 + "winzucht",
1551 + "wipstaart",
1552 + "wisgerhof",
1553 + "withaar",
1554 + "witmaker",
1555 + "wokkel",
1556 + "wolf",
1557 + "wonenden",
1558 + "woning",
1559 + "worden",
1560 + "worp",
1561 + "wortel",
1562 + "wrat",
1563 + "wrijf",
1564 + "wringen",
1565 + "yoghurt",
1566 + "ypsilon",
1567 + "zaaijer",
1568 + "zaak",
1569 + "zacharias",
1570 + "zakelijk",
1571 + "zakkam",
1572 + "zakwater",
1573 + "zalf",
1574 + "zalig",
1575 + "zaniken",
1576 + "zebracode",
1577 + "zeeblauw",
1578 + "zeef",
1579 + "zeegaand",
1580 + "zeeuw",
1581 + "zege",
1582 + "zegje",
1583 + "zeil",
1584 + "zesbaans",
1585 + "zesenhalf",
1586 + "zeskantig",
1587 + "zesmaal",
1588 + "zetbaas",
1589 + "zetpil",
1590 + "zeulen",
1591 + "ziezo",
1592 + "zigzag",
1593 + "zijaltaar",
1594 + "zijbeuk",
1595 + "zijlijn",
1596 + "zijmuur",
1597 + "zijn",
1598 + "zijwaarts",
1599 + "zijzelf",
1600 + "zilt",
1601 + "zimmerman",
1602 + "zinledig",
1603 + "zinnelijk",
1604 + "zionist",
1605 + "zitdag",
1606 + "zitruimte",
1607 + "zitzak",
1608 + "zoal",
1609 + "zodoende",
1610 + "zoekbots",
1611 + "zoem",
1612 + "zoiets",
1613 + "zojuist",
1614 + "zondaar",
1615 + "zotskap",
1616 + "zottebol",
1617 + "zucht",
1618 + "zuivel",
1619 + "zulk",
1620 + "zult",
1621 + "zuster",
1622 + "zuur",
1623 + "zweedijk",
1624 + "zwendel",
1625 + "zwepen",
1626 + "zwiep",
1627 + "zwijmel",
1628 + "zworen"
1629 + ];
1630 +}
\ No newline at end of file
cw_haven/lib/mnemonics/english.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class EnglishMnemonics {
2 + static const words = [
3 + "abbey",
4 + "abducts",
5 + "ability",
6 + "ablaze",
7 + "abnormal",
8 + "abort",
9 + "abrasive",
10 + "absorb",
11 + "abyss",
12 + "academy",
13 + "aces",
14 + "aching",
15 + "acidic",
16 + "acoustic",
17 + "acquire",
18 + "across",
19 + "actress",
20 + "acumen",
21 + "adapt",
22 + "addicted",
23 + "adept",
24 + "adhesive",
25 + "adjust",
26 + "adopt",
27 + "adrenalin",
28 + "adult",
29 + "adventure",
30 + "aerial",
31 + "afar",
32 + "affair",
33 + "afield",
34 + "afloat",
35 + "afoot",
36 + "afraid",
37 + "after",
38 + "against",
39 + "agenda",
40 + "aggravate",
41 + "agile",
42 + "aglow",
43 + "agnostic",
44 + "agony",
45 + "agreed",
46 + "ahead",
47 + "aided",
48 + "ailments",
49 + "aimless",
50 + "airport",
51 + "aisle",
52 + "ajar",
53 + "akin",
54 + "alarms",
55 + "album",
56 + "alchemy",
57 + "alerts",
58 + "algebra",
59 + "alkaline",
60 + "alley",
61 + "almost",
62 + "aloof",
63 + "alpine",
64 + "already",
65 + "also",
66 + "altitude",
67 + "alumni",
68 + "always",
69 + "amaze",
70 + "ambush",
71 + "amended",
72 + "amidst",
73 + "ammo",
74 + "amnesty",
75 + "among",
76 + "amply",
77 + "amused",
78 + "anchor",
79 + "android",
80 + "anecdote",
81 + "angled",
82 + "ankle",
83 + "annoyed",
84 + "answers",
85 + "antics",
86 + "anvil",
87 + "anxiety",
88 + "anybody",
89 + "apart",
90 + "apex",
91 + "aphid",
92 + "aplomb",
93 + "apology",
94 + "apply",
95 + "apricot",
96 + "aptitude",
97 + "aquarium",
98 + "arbitrary",
99 + "archer",
100 + "ardent",
101 + "arena",
102 + "argue",
103 + "arises",
104 + "army",
105 + "around",
106 + "arrow",
107 + "arsenic",
108 + "artistic",
109 + "ascend",
110 + "ashtray",
111 + "aside",
112 + "asked",
113 + "asleep",
114 + "aspire",
115 + "assorted",
116 + "asylum",
117 + "athlete",
118 + "atlas",
119 + "atom",
120 + "atrium",
121 + "attire",
122 + "auburn",
123 + "auctions",
124 + "audio",
125 + "august",
126 + "aunt",
127 + "austere",
128 + "autumn",
129 + "avatar",
130 + "avidly",
131 + "avoid",
132 + "awakened",
133 + "awesome",
134 + "awful",
135 + "awkward",
136 + "awning",
137 + "awoken",
138 + "axes",
139 + "axis",
140 + "axle",
141 + "aztec",
142 + "azure",
143 + "baby",
144 + "bacon",
145 + "badge",
146 + "baffles",
147 + "bagpipe",
148 + "bailed",
149 + "bakery",
150 + "balding",
151 + "bamboo",
152 + "banjo",
153 + "baptism",
154 + "basin",
155 + "batch",
156 + "bawled",
157 + "bays",
158 + "because",
159 + "beer",
160 + "befit",
161 + "begun",
162 + "behind",
163 + "being",
164 + "below",
165 + "bemused",
166 + "benches",
167 + "berries",
168 + "bested",
169 + "betting",
170 + "bevel",
171 + "beware",
172 + "beyond",
173 + "bias",
174 + "bicycle",
175 + "bids",
176 + "bifocals",
177 + "biggest",
178 + "bikini",
179 + "bimonthly",
180 + "binocular",
181 + "biology",
182 + "biplane",
183 + "birth",
184 + "biscuit",
185 + "bite",
186 + "biweekly",
187 + "blender",
188 + "blip",
189 + "bluntly",
190 + "boat",
191 + "bobsled",
192 + "bodies",
193 + "bogeys",
194 + "boil",
195 + "boldly",
196 + "bomb",
197 + "border",
198 + "boss",
199 + "both",
200 + "bounced",
201 + "bovine",
202 + "bowling",
203 + "boxes",
204 + "boyfriend",
205 + "broken",
206 + "brunt",
207 + "bubble",
208 + "buckets",
209 + "budget",
210 + "buffet",
211 + "bugs",
212 + "building",
213 + "bulb",
214 + "bumper",
215 + "bunch",
216 + "business",
217 + "butter",
218 + "buying",
219 + "buzzer",
220 + "bygones",
221 + "byline",
222 + "bypass",
223 + "cabin",
224 + "cactus",
225 + "cadets",
226 + "cafe",
227 + "cage",
228 + "cajun",
229 + "cake",
230 + "calamity",
231 + "camp",
232 + "candy",
233 + "casket",
234 + "catch",
235 + "cause",
236 + "cavernous",
237 + "cease",
238 + "cedar",
239 + "ceiling",
240 + "cell",
241 + "cement",
242 + "cent",
243 + "certain",
244 + "chlorine",
245 + "chrome",
246 + "cider",
247 + "cigar",
248 + "cinema",
249 + "circle",
250 + "cistern",
251 + "citadel",
252 + "civilian",
253 + "claim",
254 + "click",
255 + "clue",
256 + "coal",
257 + "cobra",
258 + "cocoa",
259 + "code",
260 + "coexist",
261 + "coffee",
262 + "cogs",
263 + "cohesive",
264 + "coils",
265 + "colony",
266 + "comb",
267 + "cool",
268 + "copy",
269 + "corrode",
270 + "costume",
271 + "cottage",
272 + "cousin",
273 + "cowl",
274 + "criminal",
275 + "cube",
276 + "cucumber",
277 + "cuddled",
278 + "cuffs",
279 + "cuisine",
280 + "cunning",
281 + "cupcake",
282 + "custom",
283 + "cycling",
284 + "cylinder",
285 + "cynical",
286 + "dabbing",
287 + "dads",
288 + "daft",
289 + "dagger",
290 + "daily",
291 + "damp",
292 + "dangerous",
293 + "dapper",
294 + "darted",
295 + "dash",
296 + "dating",
297 + "dauntless",
298 + "dawn",
299 + "daytime",
300 + "dazed",
301 + "debut",
302 + "decay",
303 + "dedicated",
304 + "deepest",
305 + "deftly",
306 + "degrees",
307 + "dehydrate",
308 + "deity",
309 + "dejected",
310 + "delayed",
311 + "demonstrate",
312 + "dented",
313 + "deodorant",
314 + "depth",
315 + "desk",
316 + "devoid",
317 + "dewdrop",
318 + "dexterity",
319 + "dialect",
320 + "dice",
321 + "diet",
322 + "different",
323 + "digit",
324 + "dilute",
325 + "dime",
326 + "dinner",
327 + "diode",
328 + "diplomat",
329 + "directed",
330 + "distance",
331 + "ditch",
332 + "divers",
333 + "dizzy",
334 + "doctor",
335 + "dodge",
336 + "does",
337 + "dogs",
338 + "doing",
339 + "dolphin",
340 + "domestic",
341 + "donuts",
342 + "doorway",
343 + "dormant",
344 + "dosage",
345 + "dotted",
346 + "double",
347 + "dove",
348 + "down",
349 + "dozen",
350 + "dreams",
351 + "drinks",
352 + "drowning",
353 + "drunk",
354 + "drying",
355 + "dual",
356 + "dubbed",
357 + "duckling",
358 + "dude",
359 + "duets",
360 + "duke",
361 + "dullness",
362 + "dummy",
363 + "dunes",
364 + "duplex",
365 + "duration",
366 + "dusted",
367 + "duties",
368 + "dwarf",
369 + "dwelt",
370 + "dwindling",
371 + "dying",
372 + "dynamite",
373 + "dyslexic",
374 + "each",
375 + "eagle",
376 + "earth",
377 + "easy",
378 + "eating",
379 + "eavesdrop",
380 + "eccentric",
381 + "echo",
382 + "eclipse",
383 + "economics",
384 + "ecstatic",
385 + "eden",
386 + "edgy",
387 + "edited",
388 + "educated",
389 + "eels",
390 + "efficient",
391 + "eggs",
392 + "egotistic",
393 + "eight",
394 + "either",
395 + "eject",
396 + "elapse",
397 + "elbow",
398 + "eldest",
399 + "eleven",
400 + "elite",
401 + "elope",
402 + "else",
403 + "eluded",
404 + "emails",
405 + "ember",
406 + "emerge",
407 + "emit",
408 + "emotion",
409 + "empty",
410 + "emulate",
411 + "energy",
412 + "enforce",
413 + "enhanced",
414 + "enigma",
415 + "enjoy",
416 + "enlist",
417 + "enmity",
418 + "enough",
419 + "enraged",
420 + "ensign",
421 + "entrance",
422 + "envy",
423 + "epoxy",
424 + "equip",
425 + "erase",
426 + "erected",
427 + "erosion",
428 + "error",
429 + "eskimos",
430 + "espionage",
431 + "essential",
432 + "estate",
433 + "etched",
434 + "eternal",
435 + "ethics",
436 + "etiquette",
437 + "evaluate",
438 + "evenings",
439 + "evicted",
440 + "evolved",
441 + "examine",
442 + "excess",
443 + "exhale",
444 + "exit",
445 + "exotic",
446 + "exquisite",
447 + "extra",
448 + "exult",
449 + "fabrics",
450 + "factual",
451 + "fading",
452 + "fainted",
453 + "faked",
454 + "fall",
455 + "family",
456 + "fancy",
457 + "farming",
458 + "fatal",
459 + "faulty",
460 + "fawns",
461 + "faxed",
462 + "fazed",
463 + "feast",
464 + "february",
465 + "federal",
466 + "feel",
467 + "feline",
468 + "females",
469 + "fences",
470 + "ferry",
471 + "festival",
472 + "fetches",
473 + "fever",
474 + "fewest",
475 + "fiat",
476 + "fibula",
477 + "fictional",
478 + "fidget",
479 + "fierce",
480 + "fifteen",
481 + "fight",
482 + "films",
483 + "firm",
484 + "fishing",
485 + "fitting",
486 + "five",
487 + "fixate",
488 + "fizzle",
489 + "fleet",
490 + "flippant",
491 + "flying",
492 + "foamy",
493 + "focus",
494 + "foes",
495 + "foggy",
496 + "foiled",
497 + "folding",
498 + "fonts",
499 + "foolish",
500 + "fossil",
501 + "fountain",
502 + "fowls",
503 + "foxes",
504 + "foyer",
505 + "framed",
506 + "friendly",
507 + "frown",
508 + "fruit",
509 + "frying",
510 + "fudge",
511 + "fuel",
512 + "fugitive",
513 + "fully",
514 + "fuming",
515 + "fungal",
516 + "furnished",
517 + "fuselage",
518 + "future",
519 + "fuzzy",
520 + "gables",
521 + "gadget",
522 + "gags",
523 + "gained",
524 + "galaxy",
525 + "gambit",
526 + "gang",
527 + "gasp",
528 + "gather",
529 + "gauze",
530 + "gave",
531 + "gawk",
532 + "gaze",
533 + "gearbox",
534 + "gecko",
535 + "geek",
536 + "gels",
537 + "gemstone",
538 + "general",
539 + "geometry",
540 + "germs",
541 + "gesture",
542 + "getting",
543 + "geyser",
544 + "ghetto",
545 + "ghost",
546 + "giant",
547 + "giddy",
548 + "gifts",
549 + "gigantic",
550 + "gills",
551 + "gimmick",
552 + "ginger",
553 + "girth",
554 + "giving",
555 + "glass",
556 + "gleeful",
557 + "glide",
558 + "gnaw",
559 + "gnome",
560 + "goat",
561 + "goblet",
562 + "godfather",
563 + "goes",
564 + "goggles",
565 + "going",
566 + "goldfish",
567 + "gone",
568 + "goodbye",
569 + "gopher",
570 + "gorilla",
571 + "gossip",
572 + "gotten",
573 + "gourmet",
574 + "governing",
575 + "gown",
576 + "greater",
577 + "grunt",
578 + "guarded",
579 + "guest",
580 + "guide",
581 + "gulp",
582 + "gumball",
583 + "guru",
584 + "gusts",
585 + "gutter",
586 + "guys",
587 + "gymnast",
588 + "gypsy",
589 + "gyrate",
590 + "habitat",
591 + "hacksaw",
592 + "haggled",
593 + "hairy",
594 + "hamburger",
595 + "happens",
596 + "hashing",
597 + "hatchet",
598 + "haunted",
599 + "having",
600 + "hawk",
601 + "haystack",
602 + "hazard",
603 + "hectare",
604 + "hedgehog",
605 + "heels",
606 + "hefty",
607 + "height",
608 + "hemlock",
609 + "hence",
610 + "heron",
611 + "hesitate",
612 + "hexagon",
613 + "hickory",
614 + "hiding",
615 + "highway",
616 + "hijack",
617 + "hiker",
618 + "hills",
619 + "himself",
620 + "hinder",
621 + "hippo",
622 + "hire",
623 + "history",
624 + "hitched",
625 + "hive",
626 + "hoax",
627 + "hobby",
628 + "hockey",
629 + "hoisting",
630 + "hold",
631 + "honked",
632 + "hookup",
633 + "hope",
634 + "hornet",
635 + "hospital",
636 + "hotel",
637 + "hounded",
638 + "hover",
639 + "howls",
640 + "hubcaps",
641 + "huddle",
642 + "huge",
643 + "hull",
644 + "humid",
645 + "hunter",
646 + "hurried",
647 + "husband",
648 + "huts",
649 + "hybrid",
650 + "hydrogen",
651 + "hyper",
652 + "iceberg",
653 + "icing",
654 + "icon",
655 + "identity",
656 + "idiom",
657 + "idled",
658 + "idols",
659 + "igloo",
660 + "ignore",
661 + "iguana",
662 + "illness",
663 + "imagine",
664 + "imbalance",
665 + "imitate",
666 + "impel",
667 + "inactive",
668 + "inbound",
669 + "incur",
670 + "industrial",
671 + "inexact",
672 + "inflamed",
673 + "ingested",
674 + "initiate",
675 + "injury",
676 + "inkling",
677 + "inline",
678 + "inmate",
679 + "innocent",
680 + "inorganic",
681 + "input",
682 + "inquest",
683 + "inroads",
684 + "insult",
685 + "intended",
686 + "inundate",
687 + "invoke",
688 + "inwardly",
689 + "ionic",
690 + "irate",
691 + "iris",
692 + "irony",
693 + "irritate",
694 + "island",
695 + "isolated",
696 + "issued",
697 + "italics",
698 + "itches",
699 + "items",
700 + "itinerary",
701 + "itself",
702 + "ivory",
703 + "jabbed",
704 + "jackets",
705 + "jaded",
706 + "jagged",
707 + "jailed",
708 + "jamming",
709 + "january",
710 + "jargon",
711 + "jaunt",
712 + "javelin",
713 + "jaws",
714 + "jazz",
715 + "jeans",
716 + "jeers",
717 + "jellyfish",
718 + "jeopardy",
719 + "jerseys",
720 + "jester",
721 + "jetting",
722 + "jewels",
723 + "jigsaw",
724 + "jingle",
725 + "jittery",
726 + "jive",
727 + "jobs",
728 + "jockey",
729 + "jogger",
730 + "joining",
731 + "joking",
732 + "jolted",
733 + "jostle",
734 + "journal",
735 + "joyous",
736 + "jubilee",
737 + "judge",
738 + "juggled",
739 + "juicy",
740 + "jukebox",
741 + "july",
742 + "jump",
743 + "junk",
744 + "jury",
745 + "justice",
746 + "juvenile",
747 + "kangaroo",
748 + "karate",
749 + "keep",
750 + "kennel",
751 + "kept",
752 + "kernels",
753 + "kettle",
754 + "keyboard",
755 + "kickoff",
756 + "kidneys",
757 + "king",
758 + "kiosk",
759 + "kisses",
760 + "kitchens",
761 + "kiwi",
762 + "knapsack",
763 + "knee",
764 + "knife",
765 + "knowledge",
766 + "knuckle",
767 + "koala",
768 + "laboratory",
769 + "ladder",
770 + "lagoon",
771 + "lair",
772 + "lakes",
773 + "lamb",
774 + "language",
775 + "laptop",
776 + "large",
777 + "last",
778 + "later",
779 + "launching",
780 + "lava",
781 + "lawsuit",
782 + "layout",
783 + "lazy",
784 + "lectures",
785 + "ledge",
786 + "leech",
787 + "left",
788 + "legion",
789 + "leisure",
790 + "lemon",
791 + "lending",
792 + "leopard",
793 + "lesson",
794 + "lettuce",
795 + "lexicon",
796 + "liar",
797 + "library",
798 + "licks",
799 + "lids",
800 + "lied",
801 + "lifestyle",
802 + "light",
803 + "likewise",
804 + "lilac",
805 + "limits",
806 + "linen",
807 + "lion",
808 + "lipstick",
809 + "liquid",
810 + "listen",
811 + "lively",
812 + "loaded",
813 + "lobster",
814 + "locker",
815 + "lodge",
816 + "lofty",
817 + "logic",
818 + "loincloth",
819 + "long",
820 + "looking",
821 + "lopped",
822 + "lordship",
823 + "losing",
824 + "lottery",
825 + "loudly",
826 + "love",
827 + "lower",
828 + "loyal",
829 + "lucky",
830 + "luggage",
831 + "lukewarm",
832 + "lullaby",
833 + "lumber",
834 + "lunar",
835 + "lurk",
836 + "lush",
837 + "luxury",
838 + "lymph",
839 + "lynx",
840 + "lyrics",
841 + "macro",
842 + "madness",
843 + "magically",
844 + "mailed",
845 + "major",
846 + "makeup",
847 + "malady",
848 + "mammal",
849 + "maps",
850 + "masterful",
851 + "match",
852 + "maul",
853 + "maverick",
854 + "maximum",
855 + "mayor",
856 + "maze",
857 + "meant",
858 + "mechanic",
859 + "medicate",
860 + "meeting",
861 + "megabyte",
862 + "melting",
863 + "memoir",
864 + "menu",
865 + "merger",
866 + "mesh",
867 + "metro",
868 + "mews",
869 + "mice",
870 + "midst",
871 + "mighty",
872 + "mime",
873 + "mirror",
874 + "misery",
875 + "mittens",
876 + "mixture",
877 + "moat",
878 + "mobile",
879 + "mocked",
880 + "mohawk",
881 + "moisture",
882 + "molten",
883 + "moment",
884 + "money",
885 + "moon",
886 + "mops",
887 + "morsel",
888 + "mostly",
889 + "motherly",
890 + "mouth",
891 + "movement",
892 + "mowing",
893 + "much",
894 + "muddy",
895 + "muffin",
896 + "mugged",
897 + "mullet",
898 + "mumble",
899 + "mundane",
900 + "muppet",
901 + "mural",
902 + "musical",
903 + "muzzle",
904 + "myriad",
905 + "mystery",
906 + "myth",
907 + "nabbing",
908 + "nagged",
909 + "nail",
910 + "names",
911 + "nanny",
912 + "napkin",
913 + "narrate",
914 + "nasty",
915 + "natural",
916 + "nautical",
917 + "navy",
918 + "nearby",
919 + "necklace",
920 + "needed",
921 + "negative",
922 + "neither",
923 + "neon",
924 + "nephew",
925 + "nerves",
926 + "nestle",
927 + "network",
928 + "neutral",
929 + "never",
930 + "newt",
931 + "nexus",
932 + "nibs",
933 + "niche",
934 + "niece",
935 + "nifty",
936 + "nightly",
937 + "nimbly",
938 + "nineteen",
939 + "nirvana",
940 + "nitrogen",
941 + "nobody",
942 + "nocturnal",
943 + "nodes",
944 + "noises",
945 + "nomad",
946 + "noodles",
947 + "northern",
948 + "nostril",
949 + "noted",
950 + "nouns",
951 + "novelty",
952 + "nowhere",
953 + "nozzle",
954 + "nuance",
955 + "nucleus",
956 + "nudged",
957 + "nugget",
958 + "nuisance",
959 + "null",
960 + "number",
961 + "nuns",
962 + "nurse",
963 + "nutshell",
964 + "nylon",
965 + "oaks",
966 + "oars",
967 + "oasis",
968 + "oatmeal",
969 + "obedient",
970 + "object",
971 + "obliged",
972 + "obnoxious",
973 + "observant",
974 + "obtains",
975 + "obvious",
976 + "occur",
977 + "ocean",
978 + "october",
979 + "odds",
980 + "odometer",
981 + "offend",
982 + "often",
983 + "oilfield",
984 + "ointment",
985 + "okay",
986 + "older",
987 + "olive",
988 + "olympics",
989 + "omega",
990 + "omission",
991 + "omnibus",
992 + "onboard",
993 + "oncoming",
994 + "oneself",
995 + "ongoing",
996 + "onion",
997 + "online",
998 + "onslaught",
999 + "onto",
1000 + "onward",
1001 + "oozed",
1002 + "opacity",
1003 + "opened",
1004 + "opposite",
1005 + "optical",
1006 + "opus",
1007 + "orange",
1008 + "orbit",
1009 + "orchid",
1010 + "orders",
1011 + "organs",
1012 + "origin",
1013 + "ornament",
1014 + "orphans",
1015 + "oscar",
1016 + "ostrich",
1017 + "otherwise",
1018 + "otter",
1019 + "ouch",
1020 + "ought",
1021 + "ounce",
1022 + "ourselves",
1023 + "oust",
1024 + "outbreak",
1025 + "oval",
1026 + "oven",
1027 + "owed",
1028 + "owls",
1029 + "owner",
1030 + "oxidant",
1031 + "oxygen",
1032 + "oyster",
1033 + "ozone",
1034 + "pact",
1035 + "paddles",
1036 + "pager",
1037 + "pairing",
1038 + "palace",
1039 + "pamphlet",
1040 + "pancakes",
1041 + "paper",
1042 + "paradise",
1043 + "pastry",
1044 + "patio",
1045 + "pause",
1046 + "pavements",
1047 + "pawnshop",
1048 + "payment",
1049 + "peaches",
1050 + "pebbles",
1051 + "peculiar",
1052 + "pedantic",
1053 + "peeled",
1054 + "pegs",
1055 + "pelican",
1056 + "pencil",
1057 + "people",
1058 + "pepper",
1059 + "perfect",
1060 + "pests",
1061 + "petals",
1062 + "phase",
1063 + "pheasants",
1064 + "phone",
1065 + "phrases",
1066 + "physics",
1067 + "piano",
1068 + "picked",
1069 + "pierce",
1070 + "pigment",
1071 + "piloted",
1072 + "pimple",
1073 + "pinched",
1074 + "pioneer",
1075 + "pipeline",
1076 + "pirate",
1077 + "pistons",
1078 + "pitched",
1079 + "pivot",
1080 + "pixels",
1081 + "pizza",
1082 + "playful",
1083 + "pledge",
1084 + "pliers",
1085 + "plotting",
1086 + "plus",
1087 + "plywood",
1088 + "poaching",
1089 + "pockets",
1090 + "podcast",
1091 + "poetry",
1092 + "point",
1093 + "poker",
1094 + "polar",
1095 + "ponies",
1096 + "pool",
1097 + "popular",
1098 + "portents",
1099 + "possible",
1100 + "potato",
1101 + "pouch",
1102 + "poverty",
1103 + "powder",
1104 + "pram",
1105 + "present",
1106 + "pride",
1107 + "problems",
1108 + "pruned",
1109 + "prying",
1110 + "psychic",
1111 + "public",
1112 + "puck",
1113 + "puddle",
1114 + "puffin",
1115 + "pulp",
1116 + "pumpkins",
1117 + "punch",
1118 + "puppy",
1119 + "purged",
1120 + "push",
1121 + "putty",
1122 + "puzzled",
1123 + "pylons",
1124 + "pyramid",
1125 + "python",
1126 + "queen",
1127 + "quick",
1128 + "quote",
1129 + "rabbits",
1130 + "racetrack",
1131 + "radar",
1132 + "rafts",
1133 + "rage",
1134 + "railway",
1135 + "raking",
1136 + "rally",
1137 + "ramped",
1138 + "randomly",
1139 + "rapid",
1140 + "rarest",
1141 + "rash",
1142 + "rated",
1143 + "ravine",
1144 + "rays",
1145 + "razor",
1146 + "react",
1147 + "rebel",
1148 + "recipe",
1149 + "reduce",
1150 + "reef",
1151 + "refer",
1152 + "regular",
1153 + "reheat",
1154 + "reinvest",
1155 + "rejoices",
1156 + "rekindle",
1157 + "relic",
1158 + "remedy",
1159 + "renting",
1160 + "reorder",
1161 + "repent",
1162 + "request",
1163 + "reruns",
1164 + "rest",
1165 + "return",
1166 + "reunion",
1167 + "revamp",
1168 + "rewind",
1169 + "rhino",
1170 + "rhythm",
1171 + "ribbon",
1172 + "richly",
1173 + "ridges",
1174 + "rift",
1175 + "rigid",
1176 + "rims",
1177 + "ringing",
1178 + "riots",
1179 + "ripped",
1180 + "rising",
1181 + "ritual",
1182 + "river",
1183 + "roared",
1184 + "robot",
1185 + "rockets",
1186 + "rodent",
1187 + "rogue",
1188 + "roles",
1189 + "romance",
1190 + "roomy",
1191 + "roped",
1192 + "roster",
1193 + "rotate",
1194 + "rounded",
1195 + "rover",
1196 + "rowboat",
1197 + "royal",
1198 + "ruby",
1199 + "rudely",
1200 + "ruffled",
1201 + "rugged",
1202 + "ruined",
1203 + "ruling",
1204 + "rumble",
1205 + "runway",
1206 + "rural",
1207 + "rustled",
1208 + "ruthless",
1209 + "sabotage",
1210 + "sack",
1211 + "sadness",
1212 + "safety",
1213 + "saga",
1214 + "sailor",
1215 + "sake",
1216 + "salads",
1217 + "sample",
1218 + "sanity",
1219 + "sapling",
1220 + "sarcasm",
1221 + "sash",
1222 + "satin",
1223 + "saucepan",
1224 + "saved",
1225 + "sawmill",
1226 + "saxophone",
1227 + "sayings",
1228 + "scamper",
1229 + "scenic",
1230 + "school",
1231 + "science",
1232 + "scoop",
1233 + "scrub",
1234 + "scuba",
1235 + "seasons",
1236 + "second",
1237 + "sedan",
1238 + "seeded",
1239 + "segments",
1240 + "seismic",
1241 + "selfish",
1242 + "semifinal",
1243 + "sensible",
1244 + "september",
1245 + "sequence",
1246 + "serving",
1247 + "session",
1248 + "setup",
1249 + "seventh",
1250 + "sewage",
1251 + "shackles",
1252 + "shelter",
1253 + "shipped",
1254 + "shocking",
1255 + "shrugged",
1256 + "shuffled",
1257 + "shyness",
1258 + "siblings",
1259 + "sickness",
1260 + "sidekick",
1261 + "sieve",
1262 + "sifting",
1263 + "sighting",
1264 + "silk",
1265 + "simplest",
1266 + "sincerely",
1267 + "sipped",
1268 + "siren",
1269 + "situated",
1270 + "sixteen",
1271 + "sizes",
1272 + "skater",
1273 + "skew",
1274 + "skirting",
1275 + "skulls",
1276 + "skydive",
1277 + "slackens",
1278 + "sleepless",
1279 + "slid",
1280 + "slower",
1281 + "slug",
1282 + "smash",
1283 + "smelting",
1284 + "smidgen",
1285 + "smog",
1286 + "smuggled",
1287 + "snake",
1288 + "sneeze",
1289 + "sniff",
1290 + "snout",
1291 + "snug",
1292 + "soapy",
1293 + "sober",
1294 + "soccer",
1295 + "soda",
1296 + "software",
1297 + "soggy",
1298 + "soil",
1299 + "solved",
1300 + "somewhere",
1301 + "sonic",
1302 + "soothe",
1303 + "soprano",
1304 + "sorry",
1305 + "southern",
1306 + "sovereign",
1307 + "sowed",
1308 + "soya",
1309 + "space",
1310 + "speedy",
1311 + "sphere",
1312 + "spiders",
1313 + "splendid",
1314 + "spout",
1315 + "sprig",
1316 + "spud",
1317 + "spying",
1318 + "square",
1319 + "stacking",
1320 + "stellar",
1321 + "stick",
1322 + "stockpile",
1323 + "strained",
1324 + "stunning",
1325 + "stylishly",
1326 + "subtly",
1327 + "succeed",
1328 + "suddenly",
1329 + "suede",
1330 + "suffice",
1331 + "sugar",
1332 + "suitcase",
1333 + "sulking",
1334 + "summon",
1335 + "sunken",
1336 + "superior",
1337 + "surfer",
1338 + "sushi",
1339 + "suture",
1340 + "swagger",
1341 + "swept",
1342 + "swiftly",
1343 + "sword",
1344 + "swung",
1345 + "syllabus",
1346 + "symptoms",
1347 + "syndrome",
1348 + "syringe",
1349 + "system",
1350 + "taboo",
1351 + "tacit",
1352 + "tadpoles",
1353 + "tagged",
1354 + "tail",
1355 + "taken",
1356 + "talent",
1357 + "tamper",
1358 + "tanks",
1359 + "tapestry",
1360 + "tarnished",
1361 + "tasked",
1362 + "tattoo",
1363 + "taunts",
1364 + "tavern",
1365 + "tawny",
1366 + "taxi",
1367 + "teardrop",
1368 + "technical",
1369 + "tedious",
1370 + "teeming",
1371 + "tell",
1372 + "template",
1373 + "tender",
1374 + "tepid",
1375 + "tequila",
1376 + "terminal",
1377 + "testing",
1378 + "tether",
1379 + "textbook",
1380 + "thaw",
1381 + "theatrics",
1382 + "thirsty",
1383 + "thorn",
1384 + "threaten",
1385 + "thumbs",
1386 + "thwart",
1387 + "ticket",
1388 + "tidy",
1389 + "tiers",
1390 + "tiger",
1391 + "tilt",
1392 + "timber",
1393 + "tinted",
1394 + "tipsy",
1395 + "tirade",
1396 + "tissue",
1397 + "titans",
1398 + "toaster",
1399 + "tobacco",
1400 + "today",
1401 + "toenail",
1402 + "toffee",
1403 + "together",
1404 + "toilet",
1405 + "token",
1406 + "tolerant",
1407 + "tomorrow",
1408 + "tonic",
1409 + "toolbox",
1410 + "topic",
1411 + "torch",
1412 + "tossed",
1413 + "total",
1414 + "touchy",
1415 + "towel",
1416 + "toxic",
1417 + "toyed",
1418 + "trash",
1419 + "trendy",
1420 + "tribal",
1421 + "trolling",
1422 + "truth",
1423 + "trying",
1424 + "tsunami",
1425 + "tubes",
1426 + "tucks",
1427 + "tudor",
1428 + "tuesday",
1429 + "tufts",
1430 + "tugs",
1431 + "tuition",
1432 + "tulips",
1433 + "tumbling",
1434 + "tunnel",
1435 + "turnip",
1436 + "tusks",
1437 + "tutor",
1438 + "tuxedo",
1439 + "twang",
1440 + "tweezers",
1441 + "twice",
1442 + "twofold",
1443 + "tycoon",
1444 + "typist",
1445 + "tyrant",
1446 + "ugly",
1447 + "ulcers",
1448 + "ultimate",
1449 + "umbrella",
1450 + "umpire",
1451 + "unafraid",
1452 + "unbending",
1453 + "uncle",
1454 + "under",
1455 + "uneven",
1456 + "unfit",
1457 + "ungainly",
1458 + "unhappy",
1459 + "union",
1460 + "unjustly",
1461 + "unknown",
1462 + "unlikely",
1463 + "unmask",
1464 + "unnoticed",
1465 + "unopened",
1466 + "unplugs",
1467 + "unquoted",
1468 + "unrest",
1469 + "unsafe",
1470 + "until",
1471 + "unusual",
1472 + "unveil",
1473 + "unwind",
1474 + "unzip",
1475 + "upbeat",
1476 + "upcoming",
1477 + "update",
1478 + "upgrade",
1479 + "uphill",
1480 + "upkeep",
1481 + "upload",
1482 + "upon",
1483 + "upper",
1484 + "upright",
1485 + "upstairs",
1486 + "uptight",
1487 + "upwards",
1488 + "urban",
1489 + "urchins",
1490 + "urgent",
1491 + "usage",
1492 + "useful",
1493 + "usher",
1494 + "using",
1495 + "usual",
1496 + "utensils",
1497 + "utility",
1498 + "utmost",
1499 + "utopia",
1500 + "uttered",
1501 + "vacation",
1502 + "vague",
1503 + "vain",
1504 + "value",
1505 + "vampire",
1506 + "vane",
1507 + "vapidly",
1508 + "vary",
1509 + "vastness",
1510 + "vats",
1511 + "vaults",
1512 + "vector",
1513 + "veered",
1514 + "vegan",
1515 + "vehicle",
1516 + "vein",
1517 + "velvet",
1518 + "venomous",
1519 + "verification",
1520 + "vessel",
1521 + "veteran",
1522 + "vexed",
1523 + "vials",
1524 + "vibrate",
1525 + "victim",
1526 + "video",
1527 + "viewpoint",
1528 + "vigilant",
1529 + "viking",
1530 + "village",
1531 + "vinegar",
1532 + "violin",
1533 + "vipers",
1534 + "virtual",
1535 + "visited",
1536 + "vitals",
1537 + "vivid",
1538 + "vixen",
1539 + "vocal",
1540 + "vogue",
1541 + "voice",
1542 + "volcano",
1543 + "vortex",
1544 + "voted",
1545 + "voucher",
1546 + "vowels",
1547 + "voyage",
1548 + "vulture",
1549 + "wade",
1550 + "waffle",
1551 + "wagtail",
1552 + "waist",
1553 + "waking",
1554 + "wallets",
1555 + "wanted",
1556 + "warped",
1557 + "washing",
1558 + "water",
1559 + "waveform",
1560 + "waxing",
1561 + "wayside",
1562 + "weavers",
1563 + "website",
1564 + "wedge",
1565 + "weekday",
1566 + "weird",
1567 + "welders",
1568 + "went",
1569 + "wept",
1570 + "were",
1571 + "western",
1572 + "wetsuit",
1573 + "whale",
1574 + "when",
1575 + "whipped",
1576 + "whole",
1577 + "wickets",
1578 + "width",
1579 + "wield",
1580 + "wife",
1581 + "wiggle",
1582 + "wildly",
1583 + "winter",
1584 + "wipeout",
1585 + "wiring",
1586 + "wise",
1587 + "withdrawn",
1588 + "wives",
1589 + "wizard",
1590 + "wobbly",
1591 + "woes",
1592 + "woken",
1593 + "wolf",
1594 + "womanly",
1595 + "wonders",
1596 + "woozy",
1597 + "worry",
1598 + "wounded",
1599 + "woven",
1600 + "wrap",
1601 + "wrist",
1602 + "wrong",
1603 + "yacht",
1604 + "yahoo",
1605 + "yanks",
1606 + "yard",
1607 + "yawning",
1608 + "yearbook",
1609 + "yellow",
1610 + "yesterday",
1611 + "yeti",
1612 + "yields",
1613 + "yodel",
1614 + "yoga",
1615 + "younger",
1616 + "yoyo",
1617 + "zapped",
1618 + "zeal",
1619 + "zebra",
1620 + "zero",
1621 + "zesty",
1622 + "zigzags",
1623 + "zinger",
1624 + "zippers",
1625 + "zodiac",
1626 + "zombie",
1627 + "zones",
1628 + "zoom"
1629 + ];
1630 +}
cw_haven/lib/mnemonics/french.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class FrenchMnemonics {
2 + static const words = [
3 + "abandon",
4 + "abattre",
5 + "aboi",
6 + "abolir",
7 + "aborder",
8 + "abri",
9 + "absence",
10 + "absolu",
11 + "abuser",
12 + "acacia",
13 + "acajou",
14 + "accent",
15 + "accord",
16 + "accrocher",
17 + "accuser",
18 + "acerbe",
19 + "achat",
20 + "acheter",
21 + "acide",
22 + "acier",
23 + "acquis",
24 + "acte",
25 + "action",
26 + "adage",
27 + "adepte",
28 + "adieu",
29 + "admettre",
30 + "admis",
31 + "adorer",
32 + "adresser",
33 + "aduler",
34 + "affaire",
35 + "affirmer",
36 + "afin",
37 + "agacer",
38 + "agent",
39 + "agir",
40 + "agiter",
41 + "agonie",
42 + "agrafe",
43 + "agrume",
44 + "aider",
45 + "aigle",
46 + "aigre",
47 + "aile",
48 + "ailleurs",
49 + "aimant",
50 + "aimer",
51 + "ainsi",
52 + "aise",
53 + "ajouter",
54 + "alarme",
55 + "album",
56 + "alcool",
57 + "alerte",
58 + "algue",
59 + "alibi",
60 + "aller",
61 + "allumer",
62 + "alors",
63 + "amande",
64 + "amener",
65 + "amie",
66 + "amorcer",
67 + "amour",
68 + "ample",
69 + "amuser",
70 + "ananas",
71 + "ancien",
72 + "anglais",
73 + "angoisse",
74 + "animal",
75 + "anneau",
76 + "annoncer",
77 + "apercevoir",
78 + "apparence",
79 + "appel",
80 + "apporter",
81 + "apprendre",
82 + "appuyer",
83 + "arbre",
84 + "arcade",
85 + "arceau",
86 + "arche",
87 + "ardeur",
88 + "argent",
89 + "argile",
90 + "aride",
91 + "arme",
92 + "armure",
93 + "arracher",
94 + "arriver",
95 + "article",
96 + "asile",
97 + "aspect",
98 + "assaut",
99 + "assez",
100 + "assister",
101 + "assurer",
102 + "astre",
103 + "astuce",
104 + "atlas",
105 + "atroce",
106 + "attacher",
107 + "attente",
108 + "attirer",
109 + "aube",
110 + "aucun",
111 + "audace",
112 + "auparavant",
113 + "auquel",
114 + "aurore",
115 + "aussi",
116 + "autant",
117 + "auteur",
118 + "autoroute",
119 + "autre",
120 + "aval",
121 + "avant",
122 + "avec",
123 + "avenir",
124 + "averse",
125 + "aveu",
126 + "avide",
127 + "avion",
128 + "avis",
129 + "avoir",
130 + "avouer",
131 + "avril",
132 + "azote",
133 + "azur",
134 + "badge",
135 + "bagage",
136 + "bague",
137 + "bain",
138 + "baisser",
139 + "balai",
140 + "balcon",
141 + "balise",
142 + "balle",
143 + "bambou",
144 + "banane",
145 + "banc",
146 + "bandage",
147 + "banjo",
148 + "banlieue",
149 + "bannir",
150 + "banque",
151 + "baobab",
152 + "barbe",
153 + "barque",
154 + "barrer",
155 + "bassine",
156 + "bataille",
157 + "bateau",
158 + "battre",
159 + "baver",
160 + "bavoir",
161 + "bazar",
162 + "beau",
163 + "beige",
164 + "berger",
165 + "besoin",
166 + "beurre",
167 + "biais",
168 + "biceps",
169 + "bidule",
170 + "bien",
171 + "bijou",
172 + "bilan",
173 + "billet",
174 + "blanc",
175 + "blason",
176 + "bleu",
177 + "bloc",
178 + "blond",
179 + "bocal",
180 + "boire",
181 + "boiserie",
182 + "boiter",
183 + "bonbon",
184 + "bondir",
185 + "bonheur",
186 + "bordure",
187 + "borgne",
188 + "borner",
189 + "bosse",
190 + "bouche",
191 + "bouder",
192 + "bouger",
193 + "boule",
194 + "bourse",
195 + "bout",
196 + "boxe",
197 + "brader",
198 + "braise",
199 + "branche",
200 + "braquer",
201 + "bras",
202 + "brave",
203 + "brebis",
204 + "brevet",
205 + "brider",
206 + "briller",
207 + "brin",
208 + "brique",
209 + "briser",
210 + "broche",
211 + "broder",
212 + "bronze",
213 + "brosser",
214 + "brouter",
215 + "bruit",
216 + "brute",
217 + "budget",
218 + "buffet",
219 + "bulle",
220 + "bureau",
221 + "buriner",
222 + "buste",
223 + "buter",
224 + "butiner",
225 + "cabas",
226 + "cabinet",
227 + "cabri",
228 + "cacao",
229 + "cacher",
230 + "cadeau",
231 + "cadre",
232 + "cage",
233 + "caisse",
234 + "caler",
235 + "calme",
236 + "camarade",
237 + "camion",
238 + "campagne",
239 + "canal",
240 + "canif",
241 + "capable",
242 + "capot",
243 + "carat",
244 + "caresser",
245 + "carie",
246 + "carpe",
247 + "cartel",
248 + "casier",
249 + "casque",
250 + "casserole",
251 + "cause",
252 + "cavale",
253 + "cave",
254 + "ceci",
255 + "cela",
256 + "celui",
257 + "cendre",
258 + "cent",
259 + "cependant",
260 + "cercle",
261 + "cerise",
262 + "cerner",
263 + "certes",
264 + "cerveau",
265 + "cesser",
266 + "chacun",
267 + "chair",
268 + "chaleur",
269 + "chamois",
270 + "chanson",
271 + "chaque",
272 + "charge",
273 + "chasse",
274 + "chat",
275 + "chaud",
276 + "chef",
277 + "chemin",
278 + "cheveu",
279 + "chez",
280 + "chicane",
281 + "chien",
282 + "chiffre",
283 + "chiner",
284 + "chiot",
285 + "chlore",
286 + "choc",
287 + "choix",
288 + "chose",
289 + "chou",
290 + "chute",
291 + "cibler",
292 + "cidre",
293 + "ciel",
294 + "cigale",
295 + "cinq",
296 + "cintre",
297 + "cirage",
298 + "cirque",
299 + "ciseau",
300 + "citation",
301 + "citer",
302 + "citron",
303 + "civet",
304 + "clairon",
305 + "clan",
306 + "classe",
307 + "clavier",
308 + "clef",
309 + "climat",
310 + "cloche",
311 + "cloner",
312 + "clore",
313 + "clos",
314 + "clou",
315 + "club",
316 + "cobra",
317 + "cocon",
318 + "coiffer",
319 + "coin",
320 + "colline",
321 + "colon",
322 + "combat",
323 + "comme",
324 + "compte",
325 + "conclure",
326 + "conduire",
327 + "confier",
328 + "connu",
329 + "conseil",
330 + "contre",
331 + "convenir",
332 + "copier",
333 + "cordial",
334 + "cornet",
335 + "corps",
336 + "cosmos",
337 + "coton",
338 + "couche",
339 + "coude",
340 + "couler",
341 + "coupure",
342 + "cour",
343 + "couteau",
344 + "couvrir",
345 + "crabe",
346 + "crainte",
347 + "crampe",
348 + "cran",
349 + "creuser",
350 + "crever",
351 + "crier",
352 + "crime",
353 + "crin",
354 + "crise",
355 + "crochet",
356 + "croix",
357 + "cruel",
358 + "cuisine",
359 + "cuite",
360 + "culot",
361 + "culte",
362 + "cumul",
363 + "cure",
364 + "curieux",
365 + "cuve",
366 + "dame",
367 + "danger",
368 + "dans",
369 + "davantage",
370 + "debout",
371 + "dedans",
372 + "dehors",
373 + "delta",
374 + "demain",
375 + "demeurer",
376 + "demi",
377 + "dense",
378 + "dent",
379 + "depuis",
380 + "dernier",
381 + "descendre",
382 + "dessus",
383 + "destin",
384 + "dette",
385 + "deuil",
386 + "deux",
387 + "devant",
388 + "devenir",
389 + "devin",
390 + "devoir",
391 + "dicton",
392 + "dieu",
393 + "difficile",
394 + "digestion",
395 + "digue",
396 + "diluer",
397 + "dimanche",
398 + "dinde",
399 + "diode",
400 + "dire",
401 + "diriger",
402 + "discours",
403 + "disposer",
404 + "distance",
405 + "divan",
406 + "divers",
407 + "docile",
408 + "docteur",
409 + "dodu",
410 + "dogme",
411 + "doigt",
412 + "dominer",
413 + "donation",
414 + "donjon",
415 + "donner",
416 + "dopage",
417 + "dorer",
418 + "dormir",
419 + "doseur",
420 + "douane",
421 + "double",
422 + "douche",
423 + "douleur",
424 + "doute",
425 + "doux",
426 + "douzaine",
427 + "draguer",
428 + "drame",
429 + "drap",
430 + "dresser",
431 + "droit",
432 + "duel",
433 + "dune",
434 + "duper",
435 + "durant",
436 + "durcir",
437 + "durer",
438 + "eaux",
439 + "effacer",
440 + "effet",
441 + "effort",
442 + "effrayant",
443 + "elle",
444 + "embrasser",
445 + "emmener",
446 + "emparer",
447 + "empire",
448 + "employer",
449 + "emporter",
450 + "enclos",
451 + "encore",
452 + "endive",
453 + "endormir",
454 + "endroit",
455 + "enduit",
456 + "enfant",
457 + "enfermer",
458 + "enfin",
459 + "enfler",
460 + "enfoncer",
461 + "enfuir",
462 + "engager",
463 + "engin",
464 + "enjeu",
465 + "enlever",
466 + "ennemi",
467 + "ennui",
468 + "ensemble",
469 + "ensuite",
470 + "entamer",
471 + "entendre",
472 + "entier",
473 + "entourer",
474 + "entre",
475 + "envelopper",
476 + "envie",
477 + "envoyer",
478 + "erreur",
479 + "escalier",
480 + "espace",
481 + "espoir",
482 + "esprit",
483 + "essai",
484 + "essor",
485 + "essuyer",
486 + "estimer",
487 + "exact",
488 + "examiner",
489 + "excuse",
490 + "exemple",
491 + "exiger",
492 + "exil",
493 + "exister",
494 + "exode",
495 + "expliquer",
496 + "exposer",
497 + "exprimer",
498 + "extase",
499 + "fable",
500 + "facette",
501 + "facile",
502 + "fade",
503 + "faible",
504 + "faim",
505 + "faire",
506 + "fait",
507 + "falloir",
508 + "famille",
509 + "faner",
510 + "farce",
511 + "farine",
512 + "fatigue",
513 + "faucon",
514 + "faune",
515 + "faute",
516 + "faux",
517 + "faveur",
518 + "favori",
519 + "faxer",
520 + "feinter",
521 + "femme",
522 + "fendre",
523 + "fente",
524 + "ferme",
525 + "festin",
526 + "feuille",
527 + "feutre",
528 + "fiable",
529 + "fibre",
530 + "ficher",
531 + "fier",
532 + "figer",
533 + "figure",
534 + "filet",
535 + "fille",
536 + "filmer",
537 + "fils",
538 + "filtre",
539 + "final",
540 + "finesse",
541 + "finir",
542 + "fiole",
543 + "firme",
544 + "fixe",
545 + "flacon",
546 + "flair",
547 + "flamme",
548 + "flan",
549 + "flaque",
550 + "fleur",
551 + "flocon",
552 + "flore",
553 + "flot",
554 + "flou",
555 + "fluide",
556 + "fluor",
557 + "flux",
558 + "focus",
559 + "foin",
560 + "foire",
561 + "foison",
562 + "folie",
563 + "fonction",
564 + "fondre",
565 + "fonte",
566 + "force",
567 + "forer",
568 + "forger",
569 + "forme",
570 + "fort",
571 + "fosse",
572 + "fouet",
573 + "fouine",
574 + "foule",
575 + "four",
576 + "foyer",
577 + "frais",
578 + "franc",
579 + "frapper",
580 + "freiner",
581 + "frimer",
582 + "friser",
583 + "frite",
584 + "froid",
585 + "froncer",
586 + "fruit",
587 + "fugue",
588 + "fuir",
589 + "fuite",
590 + "fumer",
591 + "fureur",
592 + "furieux",
593 + "fuser",
594 + "fusil",
595 + "futile",
596 + "futur",
597 + "gagner",
598 + "gain",
599 + "gala",
600 + "galet",
601 + "galop",
602 + "gamme",
603 + "gant",
604 + "garage",
605 + "garde",
606 + "garer",
607 + "gauche",
608 + "gaufre",
609 + "gaule",
610 + "gaver",
611 + "gazon",
612 + "geler",
613 + "genou",
614 + "genre",
615 + "gens",
616 + "gercer",
617 + "germer",
618 + "geste",
619 + "gibier",
620 + "gicler",
621 + "gilet",
622 + "girafe",
623 + "givre",
624 + "glace",
625 + "glisser",
626 + "globe",
627 + "gloire",
628 + "gluant",
629 + "gober",
630 + "golf",
631 + "gommer",
632 + "gorge",
633 + "gosier",
634 + "goutte",
635 + "grain",
636 + "gramme",
637 + "grand",
638 + "gras",
639 + "grave",
640 + "gredin",
641 + "griffure",
642 + "griller",
643 + "gris",
644 + "gronder",
645 + "gros",
646 + "grotte",
647 + "groupe",
648 + "grue",
649 + "guerrier",
650 + "guetter",
651 + "guider",
652 + "guise",
653 + "habiter",
654 + "hache",
655 + "haie",
656 + "haine",
657 + "halte",
658 + "hamac",
659 + "hanche",
660 + "hangar",
661 + "hanter",
662 + "haras",
663 + "hareng",
664 + "harpe",
665 + "hasard",
666 + "hausse",
667 + "haut",
668 + "havre",
669 + "herbe",
670 + "heure",
671 + "hibou",
672 + "hier",
673 + "histoire",
674 + "hiver",
675 + "hochet",
676 + "homme",
677 + "honneur",
678 + "honte",
679 + "horde",
680 + "horizon",
681 + "hormone",
682 + "houle",
683 + "housse",
684 + "hublot",
685 + "huile",
686 + "huit",
687 + "humain",
688 + "humble",
689 + "humide",
690 + "humour",
691 + "hurler",
692 + "idole",
693 + "igloo",
694 + "ignorer",
695 + "illusion",
696 + "image",
697 + "immense",
698 + "immobile",
699 + "imposer",
700 + "impression",
701 + "incapable",
702 + "inconnu",
703 + "index",
704 + "indiquer",
705 + "infime",
706 + "injure",
707 + "inox",
708 + "inspirer",
709 + "instant",
710 + "intention",
711 + "intime",
712 + "inutile",
713 + "inventer",
714 + "inviter",
715 + "iode",
716 + "iris",
717 + "issue",
718 + "ivre",
719 + "jade",
720 + "jadis",
721 + "jamais",
722 + "jambe",
723 + "janvier",
724 + "jardin",
725 + "jauge",
726 + "jaunisse",
727 + "jeter",
728 + "jeton",
729 + "jeudi",
730 + "jeune",
731 + "joie",
732 + "joindre",
733 + "joli",
734 + "joueur",
735 + "journal",
736 + "judo",
737 + "juge",
738 + "juillet",
739 + "juin",
740 + "jument",
741 + "jungle",
742 + "jupe",
743 + "jupon",
744 + "jurer",
745 + "juron",
746 + "jury",
747 + "jusque",
748 + "juste",
749 + "kayak",
750 + "ketchup",
751 + "kilo",
752 + "kiwi",
753 + "koala",
754 + "label",
755 + "lacet",
756 + "lacune",
757 + "laine",
758 + "laisse",
759 + "lait",
760 + "lame",
761 + "lancer",
762 + "lande",
763 + "laque",
764 + "lard",
765 + "largeur",
766 + "larme",
767 + "larve",
768 + "lasso",
769 + "laver",
770 + "lendemain",
771 + "lentement",
772 + "lequel",
773 + "lettre",
774 + "leur",
775 + "lever",
776 + "levure",
777 + "liane",
778 + "libre",
779 + "lien",
780 + "lier",
781 + "lieutenant",
782 + "ligne",
783 + "ligoter",
784 + "liguer",
785 + "limace",
786 + "limer",
787 + "limite",
788 + "lingot",
789 + "lion",
790 + "lire",
791 + "lisser",
792 + "litre",
793 + "livre",
794 + "lobe",
795 + "local",
796 + "logis",
797 + "loin",
798 + "loisir",
799 + "long",
800 + "loque",
801 + "lors",
802 + "lotus",
803 + "louer",
804 + "loup",
805 + "lourd",
806 + "louve",
807 + "loyer",
808 + "lubie",
809 + "lucide",
810 + "lueur",
811 + "luge",
812 + "luire",
813 + "lundi",
814 + "lune",
815 + "lustre",
816 + "lutin",
817 + "lutte",
818 + "luxe",
819 + "machine",
820 + "madame",
821 + "magie",
822 + "magnifique",
823 + "magot",
824 + "maigre",
825 + "main",
826 + "mairie",
827 + "maison",
828 + "malade",
829 + "malheur",
830 + "malin",
831 + "manche",
832 + "manger",
833 + "manier",
834 + "manoir",
835 + "manquer",
836 + "marche",
837 + "mardi",
838 + "marge",
839 + "mariage",
840 + "marquer",
841 + "mars",
842 + "masque",
843 + "masse",
844 + "matin",
845 + "mauvais",
846 + "meilleur",
847 + "melon",
848 + "membre",
849 + "menacer",
850 + "mener",
851 + "mensonge",
852 + "mentir",
853 + "menu",
854 + "merci",
855 + "merlu",
856 + "mesure",
857 + "mettre",
858 + "meuble",
859 + "meunier",
860 + "meute",
861 + "miche",
862 + "micro",
863 + "midi",
864 + "miel",
865 + "miette",
866 + "mieux",
867 + "milieu",
868 + "mille",
869 + "mimer",
870 + "mince",
871 + "mineur",
872 + "ministre",
873 + "minute",
874 + "mirage",
875 + "miroir",
876 + "miser",
877 + "mite",
878 + "mixte",
879 + "mobile",
880 + "mode",
881 + "module",
882 + "moins",
883 + "mois",
884 + "moment",
885 + "momie",
886 + "monde",
887 + "monsieur",
888 + "monter",
889 + "moquer",
890 + "moral",
891 + "morceau",
892 + "mordre",
893 + "morose",
894 + "morse",
895 + "mortier",
896 + "morue",
897 + "motif",
898 + "motte",
899 + "moudre",
900 + "moule",
901 + "mourir",
902 + "mousse",
903 + "mouton",
904 + "mouvement",
905 + "moyen",
906 + "muer",
907 + "muette",
908 + "mugir",
909 + "muguet",
910 + "mulot",
911 + "multiple",
912 + "munir",
913 + "muret",
914 + "muse",
915 + "musique",
916 + "muter",
917 + "nacre",
918 + "nager",
919 + "nain",
920 + "naissance",
921 + "narine",
922 + "narrer",
923 + "naseau",
924 + "nasse",
925 + "nation",
926 + "nature",
927 + "naval",
928 + "navet",
929 + "naviguer",
930 + "navrer",
931 + "neige",
932 + "nerf",
933 + "nerveux",
934 + "neuf",
935 + "neutre",
936 + "neuve",
937 + "neveu",
938 + "niche",
939 + "nier",
940 + "niveau",
941 + "noble",
942 + "noce",
943 + "nocif",
944 + "noir",
945 + "nomade",
946 + "nombre",
947 + "nommer",
948 + "nord",
949 + "norme",
950 + "notaire",
951 + "notice",
952 + "notre",
953 + "nouer",
954 + "nougat",
955 + "nourrir",
956 + "nous",
957 + "nouveau",
958 + "novice",
959 + "noyade",
960 + "noyer",
961 + "nuage",
962 + "nuance",
963 + "nuire",
964 + "nuit",
965 + "nulle",
966 + "nuque",
967 + "oasis",
968 + "objet",
969 + "obliger",
970 + "obscur",
971 + "observer",
972 + "obtenir",
973 + "obus",
974 + "occasion",
975 + "occuper",
976 + "ocre",
977 + "octet",
978 + "odeur",
979 + "odorat",
980 + "offense",
981 + "officier",
982 + "offrir",
983 + "ogive",
984 + "oiseau",
985 + "olive",
986 + "ombre",
987 + "onctueux",
988 + "onduler",
989 + "ongle",
990 + "onze",
991 + "opter",
992 + "option",
993 + "orageux",
994 + "oral",
995 + "orange",
996 + "orbite",
997 + "ordinaire",
998 + "ordre",
999 + "oreille",
1000 + "organe",
1001 + "orgie",
1002 + "orgueil",
1003 + "orient",
1004 + "origan",
1005 + "orner",
1006 + "orteil",
1007 + "ortie",
1008 + "oser",
1009 + "osselet",
1010 + "otage",
1011 + "otarie",
1012 + "ouate",
1013 + "oublier",
1014 + "ouest",
1015 + "ours",
1016 + "outil",
1017 + "outre",
1018 + "ouvert",
1019 + "ouvrir",
1020 + "ovale",
1021 + "ozone",
1022 + "pacte",
1023 + "page",
1024 + "paille",
1025 + "pain",
1026 + "paire",
1027 + "paix",
1028 + "palace",
1029 + "palissade",
1030 + "palmier",
1031 + "palpiter",
1032 + "panda",
1033 + "panneau",
1034 + "papa",
1035 + "papier",
1036 + "paquet",
1037 + "parc",
1038 + "pardi",
1039 + "parfois",
1040 + "parler",
1041 + "parmi",
1042 + "parole",
1043 + "partir",
1044 + "parvenir",
1045 + "passer",
1046 + "pastel",
1047 + "patin",
1048 + "patron",
1049 + "paume",
1050 + "pause",
1051 + "pauvre",
1052 + "paver",
1053 + "pavot",
1054 + "payer",
1055 + "pays",
1056 + "peau",
1057 + "peigne",
1058 + "peinture",
1059 + "pelage",
1060 + "pelote",
1061 + "pencher",
1062 + "pendre",
1063 + "penser",
1064 + "pente",
1065 + "percer",
1066 + "perdu",
1067 + "perle",
1068 + "permettre",
1069 + "personne",
1070 + "perte",
1071 + "peser",
1072 + "pesticide",
1073 + "petit",
1074 + "peuple",
1075 + "peur",
1076 + "phase",
1077 + "photo",
1078 + "phrase",
1079 + "piano",
1080 + "pied",
1081 + "pierre",
1082 + "pieu",
1083 + "pile",
1084 + "pilier",
1085 + "pilote",
1086 + "pilule",
1087 + "piment",
1088 + "pincer",
1089 + "pinson",
1090 + "pinte",
1091 + "pion",
1092 + "piquer",
1093 + "pirate",
1094 + "pire",
1095 + "piste",
1096 + "piton",
1097 + "pitre",
1098 + "pivot",
1099 + "pizza",
1100 + "placer",
1101 + "plage",
1102 + "plaire",
1103 + "plan",
1104 + "plaque",
1105 + "plat",
1106 + "plein",
1107 + "pleurer",
1108 + "pliage",
1109 + "plier",
1110 + "plonger",
1111 + "plot",
1112 + "pluie",
1113 + "plume",
1114 + "plus",
1115 + "pneu",
1116 + "poche",
1117 + "podium",
1118 + "poids",
1119 + "poil",
1120 + "point",
1121 + "poire",
1122 + "poison",
1123 + "poitrine",
1124 + "poivre",
1125 + "police",
1126 + "pollen",
1127 + "pomme",
1128 + "pompier",
1129 + "poncer",
1130 + "pondre",
1131 + "pont",
1132 + "portion",
1133 + "poser",
1134 + "position",
1135 + "possible",
1136 + "poste",
1137 + "potage",
1138 + "potin",
1139 + "pouce",
1140 + "poudre",
1141 + "poulet",
1142 + "poumon",
1143 + "poupe",
1144 + "pour",
1145 + "pousser",
1146 + "poutre",
1147 + "pouvoir",
1148 + "prairie",
1149 + "premier",
1150 + "prendre",
1151 + "presque",
1152 + "preuve",
1153 + "prier",
1154 + "primeur",
1155 + "prince",
1156 + "prison",
1157 + "priver",
1158 + "prix",
1159 + "prochain",
1160 + "produire",
1161 + "profond",
1162 + "proie",
1163 + "projet",
1164 + "promener",
1165 + "prononcer",
1166 + "propre",
1167 + "prose",
1168 + "prouver",
1169 + "prune",
1170 + "public",
1171 + "puce",
1172 + "pudeur",
1173 + "puiser",
1174 + "pull",
1175 + "pulpe",
1176 + "puma",
1177 + "punir",
1178 + "purge",
1179 + "putois",
1180 + "quand",
1181 + "quartier",
1182 + "quasi",
1183 + "quatre",
1184 + "quel",
1185 + "question",
1186 + "queue",
1187 + "quiche",
1188 + "quille",
1189 + "quinze",
1190 + "quitter",
1191 + "quoi",
1192 + "rabais",
1193 + "raboter",
1194 + "race",
1195 + "racheter",
1196 + "racine",
1197 + "racler",
1198 + "raconter",
1199 + "radar",
1200 + "radio",
1201 + "rafale",
1202 + "rage",
1203 + "ragot",
1204 + "raideur",
1205 + "raie",
1206 + "rail",
1207 + "raison",
1208 + "ramasser",
1209 + "ramener",
1210 + "rampe",
1211 + "rance",
1212 + "rang",
1213 + "rapace",
1214 + "rapide",
1215 + "rapport",
1216 + "rarement",
1217 + "rasage",
1218 + "raser",
1219 + "rasoir",
1220 + "rassurer",
1221 + "rater",
1222 + "ratio",
1223 + "rature",
1224 + "ravage",
1225 + "ravir",
1226 + "rayer",
1227 + "rayon",
1228 + "rebond",
1229 + "recevoir",
1230 + "recherche",
1231 + "record",
1232 + "reculer",
1233 + "redevenir",
1234 + "refuser",
1235 + "regard",
1236 + "regretter",
1237 + "rein",
1238 + "rejeter",
1239 + "rejoindre",
1240 + "relation",
1241 + "relever",
1242 + "religion",
1243 + "remarquer",
1244 + "remettre",
1245 + "remise",
1246 + "remonter",
1247 + "remplir",
1248 + "remuer",
1249 + "rencontre",
1250 + "rendre",
1251 + "renier",
1252 + "renoncer",
1253 + "rentrer",
1254 + "renverser",
1255 + "repas",
1256 + "repli",
1257 + "reposer",
1258 + "reproche",
1259 + "requin",
1260 + "respect",
1261 + "ressembler",
1262 + "reste",
1263 + "retard",
1264 + "retenir",
1265 + "retirer",
1266 + "retour",
1267 + "retrouver",
1268 + "revenir",
1269 + "revoir",
1270 + "revue",
1271 + "rhume",
1272 + "ricaner",
1273 + "riche",
1274 + "rideau",
1275 + "ridicule",
1276 + "rien",
1277 + "rigide",
1278 + "rincer",
1279 + "rire",
1280 + "risquer",
1281 + "rituel",
1282 + "rivage",
1283 + "rive",
1284 + "robe",
1285 + "robot",
1286 + "robuste",
1287 + "rocade",
1288 + "roche",
1289 + "rodeur",
1290 + "rogner",
1291 + "roman",
1292 + "rompre",
1293 + "ronce",
1294 + "rondeur",
1295 + "ronger",
1296 + "roque",
1297 + "rose",
1298 + "rosir",
1299 + "rotation",
1300 + "rotule",
1301 + "roue",
1302 + "rouge",
1303 + "rouler",
1304 + "route",
1305 + "ruban",
1306 + "rubis",
1307 + "ruche",
1308 + "rude",
1309 + "ruelle",
1310 + "ruer",
1311 + "rugby",
1312 + "rugir",
1313 + "ruine",
1314 + "rumeur",
1315 + "rural",
1316 + "ruse",
1317 + "rustre",
1318 + "sable",
1319 + "sabot",
1320 + "sabre",
1321 + "sacre",
1322 + "sage",
1323 + "saint",
1324 + "saisir",
1325 + "salade",
1326 + "salive",
1327 + "salle",
1328 + "salon",
1329 + "salto",
1330 + "salut",
1331 + "salve",
1332 + "samba",
1333 + "sandale",
1334 + "sanguin",
1335 + "sapin",
1336 + "sarcasme",
1337 + "satisfaire",
1338 + "sauce",
1339 + "sauf",
1340 + "sauge",
1341 + "saule",
1342 + "sauna",
1343 + "sauter",
1344 + "sauver",
1345 + "savoir",
1346 + "science",
1347 + "scoop",
1348 + "score",
1349 + "second",
1350 + "secret",
1351 + "secte",
1352 + "seigneur",
1353 + "sein",
1354 + "seize",
1355 + "selle",
1356 + "selon",
1357 + "semaine",
1358 + "sembler",
1359 + "semer",
1360 + "semis",
1361 + "sensuel",
1362 + "sentir",
1363 + "sept",
1364 + "serpe",
1365 + "serrer",
1366 + "sertir",
1367 + "service",
1368 + "seuil",
1369 + "seulement",
1370 + "short",
1371 + "sien",
1372 + "sigle",
1373 + "signal",
1374 + "silence",
1375 + "silo",
1376 + "simple",
1377 + "singe",
1378 + "sinon",
1379 + "sinus",
1380 + "sioux",
1381 + "sirop",
1382 + "site",
1383 + "situation",
1384 + "skier",
1385 + "snob",
1386 + "sobre",
1387 + "social",
1388 + "socle",
1389 + "sodium",
1390 + "soigner",
1391 + "soir",
1392 + "soixante",
1393 + "soja",
1394 + "solaire",
1395 + "soldat",
1396 + "soleil",
1397 + "solide",
1398 + "solo",
1399 + "solvant",
1400 + "sombre",
1401 + "somme",
1402 + "somnoler",
1403 + "sondage",
1404 + "songeur",
1405 + "sonner",
1406 + "sorte",
1407 + "sosie",
1408 + "sottise",
1409 + "souci",
1410 + "soudain",
1411 + "souffrir",
1412 + "souhaiter",
1413 + "soulever",
1414 + "soumettre",
1415 + "soupe",
1416 + "sourd",
1417 + "soustraire",
1418 + "soutenir",
1419 + "souvent",
1420 + "soyeux",
1421 + "spectacle",
1422 + "sport",
1423 + "stade",
1424 + "stagiaire",
1425 + "stand",
1426 + "star",
1427 + "statue",
1428 + "stock",
1429 + "stop",
1430 + "store",
1431 + "style",
1432 + "suave",
1433 + "subir",
1434 + "sucre",
1435 + "suer",
1436 + "suffire",
1437 + "suie",
1438 + "suite",
1439 + "suivre",
1440 + "sujet",
1441 + "sulfite",
1442 + "supposer",
1443 + "surf",
1444 + "surprendre",
1445 + "surtout",
1446 + "surveiller",
1447 + "tabac",
1448 + "table",
1449 + "tabou",
1450 + "tache",
1451 + "tacler",
1452 + "tacot",
1453 + "tact",
1454 + "taie",
1455 + "taille",
1456 + "taire",
1457 + "talon",
1458 + "talus",
1459 + "tandis",
1460 + "tango",
1461 + "tanin",
1462 + "tant",
1463 + "taper",
1464 + "tapis",
1465 + "tard",
1466 + "tarif",
1467 + "tarot",
1468 + "tarte",
1469 + "tasse",
1470 + "taureau",
1471 + "taux",
1472 + "taverne",
1473 + "taxer",
1474 + "taxi",
1475 + "tellement",
1476 + "temple",
1477 + "tendre",
1478 + "tenir",
1479 + "tenter",
1480 + "tenu",
1481 + "terme",
1482 + "ternir",
1483 + "terre",
1484 + "test",
1485 + "texte",
1486 + "thym",
1487 + "tibia",
1488 + "tiers",
1489 + "tige",
1490 + "tipi",
1491 + "tique",
1492 + "tirer",
1493 + "tissu",
1494 + "titre",
1495 + "toast",
1496 + "toge",
1497 + "toile",
1498 + "toiser",
1499 + "toiture",
1500 + "tomber",
1501 + "tome",
1502 + "tonne",
1503 + "tonte",
1504 + "toque",
1505 + "torse",
1506 + "tortue",
1507 + "totem",
1508 + "toucher",
1509 + "toujours",
1510 + "tour",
1511 + "tousser",
1512 + "tout",
1513 + "toux",
1514 + "trace",
1515 + "train",
1516 + "trame",
1517 + "tranquille",
1518 + "travail",
1519 + "trembler",
1520 + "trente",
1521 + "tribu",
1522 + "trier",
1523 + "trio",
1524 + "tripe",
1525 + "triste",
1526 + "troc",
1527 + "trois",
1528 + "tromper",
1529 + "tronc",
1530 + "trop",
1531 + "trotter",
1532 + "trouer",
1533 + "truc",
1534 + "truite",
1535 + "tuba",
1536 + "tuer",
1537 + "tuile",
1538 + "turbo",
1539 + "tutu",
1540 + "tuyau",
1541 + "type",
1542 + "union",
1543 + "unique",
1544 + "unir",
1545 + "unisson",
1546 + "untel",
1547 + "urne",
1548 + "usage",
1549 + "user",
1550 + "usiner",
1551 + "usure",
1552 + "utile",
1553 + "vache",
1554 + "vague",
1555 + "vaincre",
1556 + "valeur",
1557 + "valoir",
1558 + "valser",
1559 + "valve",
1560 + "vampire",
1561 + "vaseux",
1562 + "vaste",
1563 + "veau",
1564 + "veille",
1565 + "veine",
1566 + "velours",
1567 + "velu",
1568 + "vendre",
1569 + "venir",
1570 + "vent",
1571 + "venue",
1572 + "verbe",
1573 + "verdict",
1574 + "version",
1575 + "vertige",
1576 + "verve",
1577 + "veste",
1578 + "veto",
1579 + "vexer",
1580 + "vice",
1581 + "victime",
1582 + "vide",
1583 + "vieil",
1584 + "vieux",
1585 + "vigie",
1586 + "vigne",
1587 + "ville",
1588 + "vingt",
1589 + "violent",
1590 + "virer",
1591 + "virus",
1592 + "visage",
1593 + "viser",
1594 + "visite",
1595 + "visuel",
1596 + "vitamine",
1597 + "vitrine",
1598 + "vivant",
1599 + "vivre",
1600 + "vocal",
1601 + "vodka",
1602 + "vogue",
1603 + "voici",
1604 + "voile",
1605 + "voir",
1606 + "voisin",
1607 + "voiture",
1608 + "volaille",
1609 + "volcan",
1610 + "voler",
1611 + "volt",
1612 + "votant",
1613 + "votre",
1614 + "vouer",
1615 + "vouloir",
1616 + "vous",
1617 + "voyage",
1618 + "voyou",
1619 + "vrac",
1620 + "vrai",
1621 + "yacht",
1622 + "yeti",
1623 + "yeux",
1624 + "yoga",
1625 + "zeste",
1626 + "zinc",
1627 + "zone",
1628 + "zoom"
1629 + ];
1630 +}
\ No newline at end of file
cw_haven/lib/mnemonics/german.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class GermanMnemonics {
2 + static const words = [
3 + "Abakus",
4 + "Abart",
5 + "abbilden",
6 + "Abbruch",
7 + "Abdrift",
8 + "Abendrot",
9 + "Abfahrt",
10 + "abfeuern",
11 + "Abflug",
12 + "abfragen",
13 + "Abglanz",
14 + "abhärten",
15 + "abheben",
16 + "Abhilfe",
17 + "Abitur",
18 + "Abkehr",
19 + "Ablauf",
20 + "ablecken",
21 + "Ablösung",
22 + "Abnehmer",
23 + "abnutzen",
24 + "Abonnent",
25 + "Abrasion",
26 + "Abrede",
27 + "abrüsten",
28 + "Absicht",
29 + "Absprung",
30 + "Abstand",
31 + "absuchen",
32 + "Abteil",
33 + "Abundanz",
34 + "abwarten",
35 + "Abwurf",
36 + "Abzug",
37 + "Achse",
38 + "Achtung",
39 + "Acker",
40 + "Aderlass",
41 + "Adler",
42 + "Admiral",
43 + "Adresse",
44 + "Affe",
45 + "Affront",
46 + "Afrika",
47 + "Aggregat",
48 + "Agilität",
49 + "ähneln",
50 + "Ahnung",
51 + "Ahorn",
52 + "Akazie",
53 + "Akkord",
54 + "Akrobat",
55 + "Aktfoto",
56 + "Aktivist",
57 + "Albatros",
58 + "Alchimie",
59 + "Alemanne",
60 + "Alibi",
61 + "Alkohol",
62 + "Allee",
63 + "Allüre",
64 + "Almosen",
65 + "Almweide",
66 + "Aloe",
67 + "Alpaka",
68 + "Alpental",
69 + "Alphabet",
70 + "Alpinist",
71 + "Alraune",
72 + "Altbier",
73 + "Alter",
74 + "Altflöte",
75 + "Altruist",
76 + "Alublech",
77 + "Aludose",
78 + "Amateur",
79 + "Amazonas",
80 + "Ameise",
81 + "Amnesie",
82 + "Amok",
83 + "Ampel",
84 + "Amphibie",
85 + "Ampulle",
86 + "Amsel",
87 + "Amulett",
88 + "Anakonda",
89 + "Analogie",
90 + "Ananas",
91 + "Anarchie",
92 + "Anatomie",
93 + "Anbau",
94 + "Anbeginn",
95 + "anbieten",
96 + "Anblick",
97 + "ändern",
98 + "andocken",
99 + "Andrang",
100 + "anecken",
101 + "Anflug",
102 + "Anfrage",
103 + "Anführer",
104 + "Angebot",
105 + "Angler",
106 + "Anhalter",
107 + "Anhöhe",
108 + "Animator",
109 + "Anis",
110 + "Anker",
111 + "ankleben",
112 + "Ankunft",
113 + "Anlage",
114 + "anlocken",
115 + "Anmut",
116 + "Annahme",
117 + "Anomalie",
118 + "Anonymus",
119 + "Anorak",
120 + "anpeilen",
121 + "Anrecht",
122 + "Anruf",
123 + "Ansage",
124 + "Anschein",
125 + "Ansicht",
126 + "Ansporn",
127 + "Anteil",
128 + "Antlitz",
129 + "Antrag",
130 + "Antwort",
131 + "Anwohner",
132 + "Aorta",
133 + "Apfel",
134 + "Appetit",
135 + "Applaus",
136 + "Aquarium",
137 + "Arbeit",
138 + "Arche",
139 + "Argument",
140 + "Arktis",
141 + "Armband",
142 + "Aroma",
143 + "Asche",
144 + "Askese",
145 + "Asphalt",
146 + "Asteroid",
147 + "Ästhetik",
148 + "Astronom",
149 + "Atelier",
150 + "Athlet",
151 + "Atlantik",
152 + "Atmung",
153 + "Audienz",
154 + "aufatmen",
155 + "Auffahrt",
156 + "aufholen",
157 + "aufregen",
158 + "Aufsatz",
159 + "Auftritt",
160 + "Aufwand",
161 + "Augapfel",
162 + "Auktion",
163 + "Ausbruch",
164 + "Ausflug",
165 + "Ausgabe",
166 + "Aushilfe",
167 + "Ausland",
168 + "Ausnahme",
169 + "Aussage",
170 + "Autobahn",
171 + "Avocado",
172 + "Axthieb",
173 + "Bach",
174 + "backen",
175 + "Badesee",
176 + "Bahnhof",
177 + "Balance",
178 + "Balkon",
179 + "Ballett",
180 + "Balsam",
181 + "Banane",
182 + "Bandage",
183 + "Bankett",
184 + "Barbar",
185 + "Barde",
186 + "Barett",
187 + "Bargeld",
188 + "Barkasse",
189 + "Barriere",
190 + "Bart",
191 + "Bass",
192 + "Bastler",
193 + "Batterie",
194 + "Bauch",
195 + "Bauer",
196 + "Bauholz",
197 + "Baujahr",
198 + "Baum",
199 + "Baustahl",
200 + "Bauteil",
201 + "Bauweise",
202 + "Bazar",
203 + "beachten",
204 + "Beatmung",
205 + "beben",
206 + "Becher",
207 + "Becken",
208 + "bedanken",
209 + "beeilen",
210 + "beenden",
211 + "Beere",
212 + "befinden",
213 + "Befreier",
214 + "Begabung",
215 + "Begierde",
216 + "begrüßen",
217 + "Beiboot",
218 + "Beichte",
219 + "Beifall",
220 + "Beigabe",
221 + "Beil",
222 + "Beispiel",
223 + "Beitrag",
224 + "beizen",
225 + "bekommen",
226 + "beladen",
227 + "Beleg",
228 + "bellen",
229 + "belohnen",
230 + "Bemalung",
231 + "Bengel",
232 + "Benutzer",
233 + "Benzin",
234 + "beraten",
235 + "Bereich",
236 + "Bergluft",
237 + "Bericht",
238 + "Bescheid",
239 + "Besitz",
240 + "besorgen",
241 + "Bestand",
242 + "Besuch",
243 + "betanken",
244 + "beten",
245 + "betören",
246 + "Bett",
247 + "Beule",
248 + "Beute",
249 + "Bewegung",
250 + "bewirken",
251 + "Bewohner",
252 + "bezahlen",
253 + "Bezug",
254 + "biegen",
255 + "Biene",
256 + "Bierzelt",
257 + "bieten",
258 + "Bikini",
259 + "Bildung",
260 + "Billard",
261 + "binden",
262 + "Biobauer",
263 + "Biologe",
264 + "Bionik",
265 + "Biotop",
266 + "Birke",
267 + "Bison",
268 + "Bitte",
269 + "Biwak",
270 + "Bizeps",
271 + "blasen",
272 + "Blatt",
273 + "Blauwal",
274 + "Blende",
275 + "Blick",
276 + "Blitz",
277 + "Blockade",
278 + "Blödelei",
279 + "Blondine",
280 + "Blues",
281 + "Blume",
282 + "Blut",
283 + "Bodensee",
284 + "Bogen",
285 + "Boje",
286 + "Bollwerk",
287 + "Bonbon",
288 + "Bonus",
289 + "Boot",
290 + "Bordarzt",
291 + "Börse",
292 + "Böschung",
293 + "Boudoir",
294 + "Boxkampf",
295 + "Boykott",
296 + "Brahms",
297 + "Brandung",
298 + "Brauerei",
299 + "Brecher",
300 + "Breitaxt",
301 + "Bremse",
302 + "brennen",
303 + "Brett",
304 + "Brief",
305 + "Brigade",
306 + "Brillanz",
307 + "bringen",
308 + "brodeln",
309 + "Brosche",
310 + "Brötchen",
311 + "Brücke",
312 + "Brunnen",
313 + "Brüste",
314 + "Brutofen",
315 + "Buch",
316 + "Büffel",
317 + "Bugwelle",
318 + "Bühne",
319 + "Buletten",
320 + "Bullauge",
321 + "Bumerang",
322 + "bummeln",
323 + "Buntglas",
324 + "Bürde",
325 + "Burgherr",
326 + "Bursche",
327 + "Busen",
328 + "Buslinie",
329 + "Bussard",
330 + "Butangas",
331 + "Butter",
332 + "Cabrio",
333 + "campen",
334 + "Captain",
335 + "Cartoon",
336 + "Cello",
337 + "Chalet",
338 + "Charisma",
339 + "Chefarzt",
340 + "Chiffon",
341 + "Chipsatz",
342 + "Chirurg",
343 + "Chor",
344 + "Chronik",
345 + "Chuzpe",
346 + "Clubhaus",
347 + "Cockpit",
348 + "Codewort",
349 + "Cognac",
350 + "Coladose",
351 + "Computer",
352 + "Coupon",
353 + "Cousin",
354 + "Cracking",
355 + "Crash",
356 + "Curry",
357 + "Dach",
358 + "Dackel",
359 + "daddeln",
360 + "daliegen",
361 + "Dame",
362 + "Dammbau",
363 + "Dämon",
364 + "Dampflok",
365 + "Dank",
366 + "Darm",
367 + "Datei",
368 + "Datsche",
369 + "Datteln",
370 + "Datum",
371 + "Dauer",
372 + "Daunen",
373 + "Deckel",
374 + "Decoder",
375 + "Defekt",
376 + "Degen",
377 + "Dehnung",
378 + "Deiche",
379 + "Dekade",
380 + "Dekor",
381 + "Delfin",
382 + "Demut",
383 + "denken",
384 + "Deponie",
385 + "Design",
386 + "Desktop",
387 + "Dessert",
388 + "Detail",
389 + "Detektiv",
390 + "Dezibel",
391 + "Diadem",
392 + "Diagnose",
393 + "Dialekt",
394 + "Diamant",
395 + "Dichter",
396 + "Dickicht",
397 + "Diesel",
398 + "Diktat",
399 + "Diplom",
400 + "Direktor",
401 + "Dirne",
402 + "Diskurs",
403 + "Distanz",
404 + "Docht",
405 + "Dohle",
406 + "Dolch",
407 + "Domäne",
408 + "Donner",
409 + "Dorade",
410 + "Dorf",
411 + "Dörrobst",
412 + "Dorsch",
413 + "Dossier",
414 + "Dozent",
415 + "Drachen",
416 + "Draht",
417 + "Drama",
418 + "Drang",
419 + "Drehbuch",
420 + "Dreieck",
421 + "Dressur",
422 + "Drittel",
423 + "Drossel",
424 + "Druck",
425 + "Duell",
426 + "Duft",
427 + "Düne",
428 + "Dünung",
429 + "dürfen",
430 + "Duschbad",
431 + "Düsenjet",
432 + "Dynamik",
433 + "Ebbe",
434 + "Echolot",
435 + "Echse",
436 + "Eckball",
437 + "Edding",
438 + "Edelweiß",
439 + "Eden",
440 + "Edition",
441 + "Efeu",
442 + "Effekte",
443 + "Egoismus",
444 + "Ehre",
445 + "Eiablage",
446 + "Eiche",
447 + "Eidechse",
448 + "Eidotter",
449 + "Eierkopf",
450 + "Eigelb",
451 + "Eiland",
452 + "Eilbote",
453 + "Eimer",
454 + "einatmen",
455 + "Einband",
456 + "Eindruck",
457 + "Einfall",
458 + "Eingang",
459 + "Einkauf",
460 + "einladen",
461 + "Einöde",
462 + "Einrad",
463 + "Eintopf",
464 + "Einwurf",
465 + "Einzug",
466 + "Eisbär",
467 + "Eisen",
468 + "Eishöhle",
469 + "Eismeer",
470 + "Eiweiß",
471 + "Ekstase",
472 + "Elan",
473 + "Elch",
474 + "Elefant",
475 + "Eleganz",
476 + "Element",
477 + "Elfe",
478 + "Elite",
479 + "Elixier",
480 + "Ellbogen",
481 + "Eloquenz",
482 + "Emigrant",
483 + "Emission",
484 + "Emotion",
485 + "Empathie",
486 + "Empfang",
487 + "Endzeit",
488 + "Energie",
489 + "Engpass",
490 + "Enkel",
491 + "Enklave",
492 + "Ente",
493 + "entheben",
494 + "Entität",
495 + "entladen",
496 + "Entwurf",
497 + "Episode",
498 + "Epoche",
499 + "erachten",
500 + "Erbauer",
501 + "erblühen",
502 + "Erdbeere",
503 + "Erde",
504 + "Erdgas",
505 + "Erdkunde",
506 + "Erdnuss",
507 + "Erdöl",
508 + "Erdteil",
509 + "Ereignis",
510 + "Eremit",
511 + "erfahren",
512 + "Erfolg",
513 + "erfreuen",
514 + "erfüllen",
515 + "Ergebnis",
516 + "erhitzen",
517 + "erkalten",
518 + "erkennen",
519 + "erleben",
520 + "Erlösung",
521 + "ernähren",
522 + "erneuern",
523 + "Ernte",
524 + "Eroberer",
525 + "eröffnen",
526 + "Erosion",
527 + "Erotik",
528 + "Erpel",
529 + "erraten",
530 + "Erreger",
531 + "erröten",
532 + "Ersatz",
533 + "Erstflug",
534 + "Ertrag",
535 + "Eruption",
536 + "erwarten",
537 + "erwidern",
538 + "Erzbau",
539 + "Erzeuger",
540 + "erziehen",
541 + "Esel",
542 + "Eskimo",
543 + "Eskorte",
544 + "Espe",
545 + "Espresso",
546 + "essen",
547 + "Etage",
548 + "Etappe",
549 + "Etat",
550 + "Ethik",
551 + "Etikett",
552 + "Etüde",
553 + "Eule",
554 + "Euphorie",
555 + "Europa",
556 + "Everest",
557 + "Examen",
558 + "Exil",
559 + "Exodus",
560 + "Extrakt",
561 + "Fabel",
562 + "Fabrik",
563 + "Fachmann",
564 + "Fackel",
565 + "Faden",
566 + "Fagott",
567 + "Fahne",
568 + "Faible",
569 + "Fairness",
570 + "Fakt",
571 + "Fakultät",
572 + "Falke",
573 + "Fallobst",
574 + "Fälscher",
575 + "Faltboot",
576 + "Familie",
577 + "Fanclub",
578 + "Fanfare",
579 + "Fangarm",
580 + "Fantasie",
581 + "Farbe",
582 + "Farmhaus",
583 + "Farn",
584 + "Fasan",
585 + "Faser",
586 + "Fassung",
587 + "fasten",
588 + "Faulheit",
589 + "Fauna",
590 + "Faust",
591 + "Favorit",
592 + "Faxgerät",
593 + "Fazit",
594 + "fechten",
595 + "Federboa",
596 + "Fehler",
597 + "Feier",
598 + "Feige",
599 + "feilen",
600 + "Feinripp",
601 + "Feldbett",
602 + "Felge",
603 + "Fellpony",
604 + "Felswand",
605 + "Ferien",
606 + "Ferkel",
607 + "Fernweh",
608 + "Ferse",
609 + "Fest",
610 + "Fettnapf",
611 + "Feuer",
612 + "Fiasko",
613 + "Fichte",
614 + "Fiktion",
615 + "Film",
616 + "Filter",
617 + "Filz",
618 + "Finanzen",
619 + "Findling",
620 + "Finger",
621 + "Fink",
622 + "Finnwal",
623 + "Fisch",
624 + "Fitness",
625 + "Fixpunkt",
626 + "Fixstern",
627 + "Fjord",
628 + "Flachbau",
629 + "Flagge",
630 + "Flamenco",
631 + "Flanke",
632 + "Flasche",
633 + "Flaute",
634 + "Fleck",
635 + "Flegel",
636 + "flehen",
637 + "Fleisch",
638 + "fliegen",
639 + "Flinte",
640 + "Flirt",
641 + "Flocke",
642 + "Floh",
643 + "Floskel",
644 + "Floß",
645 + "Flöte",
646 + "Flugzeug",
647 + "Flunder",
648 + "Flusstal",
649 + "Flutung",
650 + "Fockmast",
651 + "Fohlen",
652 + "Föhnlage",
653 + "Fokus",
654 + "folgen",
655 + "Foliant",
656 + "Folklore",
657 + "Fontäne",
658 + "Förde",
659 + "Forelle",
660 + "Format",
661 + "Forscher",
662 + "Fortgang",
663 + "Forum",
664 + "Fotograf",
665 + "Frachter",
666 + "Fragment",
667 + "Fraktion",
668 + "fräsen",
669 + "Frauenpo",
670 + "Freak",
671 + "Fregatte",
672 + "Freiheit",
673 + "Freude",
674 + "Frieden",
675 + "Frohsinn",
676 + "Frosch",
677 + "Frucht",
678 + "Frühjahr",
679 + "Fuchs",
680 + "Fügung",
681 + "fühlen",
682 + "Füller",
683 + "Fundbüro",
684 + "Funkboje",
685 + "Funzel",
686 + "Furnier",
687 + "Fürsorge",
688 + "Fusel",
689 + "Fußbad",
690 + "Futteral",
691 + "Gabelung",
692 + "gackern",
693 + "Gage",
694 + "gähnen",
695 + "Galaxie",
696 + "Galeere",
697 + "Galopp",
698 + "Gameboy",
699 + "Gamsbart",
700 + "Gandhi",
701 + "Gang",
702 + "Garage",
703 + "Gardine",
704 + "Garküche",
705 + "Garten",
706 + "Gasthaus",
707 + "Gattung",
708 + "gaukeln",
709 + "Gazelle",
710 + "Gebäck",
711 + "Gebirge",
712 + "Gebräu",
713 + "Geburt",
714 + "Gedanke",
715 + "Gedeck",
716 + "Gedicht",
717 + "Gefahr",
718 + "Gefieder",
719 + "Geflügel",
720 + "Gefühl",
721 + "Gegend",
722 + "Gehirn",
723 + "Gehöft",
724 + "Gehweg",
725 + "Geige",
726 + "Geist",
727 + "Gelage",
728 + "Geld",
729 + "Gelenk",
730 + "Gelübde",
731 + "Gemälde",
732 + "Gemeinde",
733 + "Gemüse",
734 + "genesen",
735 + "Genuss",
736 + "Gepäck",
737 + "Geranie",
738 + "Gericht",
739 + "Germane",
740 + "Geruch",
741 + "Gesang",
742 + "Geschenk",
743 + "Gesetz",
744 + "Gesindel",
745 + "Gesöff",
746 + "Gespan",
747 + "Gestade",
748 + "Gesuch",
749 + "Getier",
750 + "Getränk",
751 + "Getümmel",
752 + "Gewand",
753 + "Geweih",
754 + "Gewitter",
755 + "Gewölbe",
756 + "Geysir",
757 + "Giftzahn",
758 + "Gipfel",
759 + "Giraffe",
760 + "Gitarre",
761 + "glänzen",
762 + "Glasauge",
763 + "Glatze",
764 + "Gleis",
765 + "Globus",
766 + "Glück",
767 + "glühen",
768 + "Glutofen",
769 + "Goldzahn",
770 + "Gondel",
771 + "gönnen",
772 + "Gottheit",
773 + "graben",
774 + "Grafik",
775 + "Grashalm",
776 + "Graugans",
777 + "greifen",
778 + "Grenze",
779 + "grillen",
780 + "Groschen",
781 + "Grotte",
782 + "Grube",
783 + "Grünalge",
784 + "Gruppe",
785 + "gruseln",
786 + "Gulasch",
787 + "Gummibär",
788 + "Gurgel",
789 + "Gürtel",
790 + "Güterzug",
791 + "Haarband",
792 + "Habicht",
793 + "hacken",
794 + "hadern",
795 + "Hafen",
796 + "Hagel",
797 + "Hähnchen",
798 + "Haifisch",
799 + "Haken",
800 + "Halbaffe",
801 + "Halsader",
802 + "halten",
803 + "Halunke",
804 + "Handbuch",
805 + "Hanf",
806 + "Harfe",
807 + "Harnisch",
808 + "härten",
809 + "Harz",
810 + "Hasenohr",
811 + "Haube",
812 + "hauchen",
813 + "Haupt",
814 + "Haut",
815 + "Havarie",
816 + "Hebamme",
817 + "hecheln",
818 + "Heck",
819 + "Hedonist",
820 + "Heiler",
821 + "Heimat",
822 + "Heizung",
823 + "Hektik",
824 + "Held",
825 + "helfen",
826 + "Helium",
827 + "Hemd",
828 + "hemmen",
829 + "Hengst",
830 + "Herd",
831 + "Hering",
832 + "Herkunft",
833 + "Hermelin",
834 + "Herrchen",
835 + "Herzdame",
836 + "Heulboje",
837 + "Hexe",
838 + "Hilfe",
839 + "Himbeere",
840 + "Himmel",
841 + "Hingabe",
842 + "hinhören",
843 + "Hinweis",
844 + "Hirsch",
845 + "Hirte",
846 + "Hitzkopf",
847 + "Hobel",
848 + "Hochform",
849 + "Hocker",
850 + "hoffen",
851 + "Hofhund",
852 + "Hofnarr",
853 + "Höhenzug",
854 + "Hohlraum",
855 + "Hölle",
856 + "Holzboot",
857 + "Honig",
858 + "Honorar",
859 + "horchen",
860 + "Hörprobe",
861 + "Höschen",
862 + "Hotel",
863 + "Hubraum",
864 + "Hufeisen",
865 + "Hügel",
866 + "huldigen",
867 + "Hülle",
868 + "Humbug",
869 + "Hummer",
870 + "Humor",
871 + "Hund",
872 + "Hunger",
873 + "Hupe",
874 + "Hürde",
875 + "Hurrikan",
876 + "Hydrant",
877 + "Hypnose",
878 + "Ibis",
879 + "Idee",
880 + "Idiot",
881 + "Igel",
882 + "Illusion",
883 + "Imitat",
884 + "impfen",
885 + "Import",
886 + "Inferno",
887 + "Ingwer",
888 + "Inhalte",
889 + "Inland",
890 + "Insekt",
891 + "Ironie",
892 + "Irrfahrt",
893 + "Irrtum",
894 + "Isolator",
895 + "Istwert",
896 + "Jacke",
897 + "Jade",
898 + "Jagdhund",
899 + "Jäger",
900 + "Jaguar",
901 + "Jahr",
902 + "Jähzorn",
903 + "Jazzfest",
904 + "Jetpilot",
905 + "jobben",
906 + "Jochbein",
907 + "jodeln",
908 + "Jodsalz",
909 + "Jolle",
910 + "Journal",
911 + "Jubel",
912 + "Junge",
913 + "Junimond",
914 + "Jupiter",
915 + "Jutesack",
916 + "Juwel",
917 + "Kabarett",
918 + "Kabine",
919 + "Kabuff",
920 + "Käfer",
921 + "Kaffee",
922 + "Kahlkopf",
923 + "Kaimauer",
924 + "Kajüte",
925 + "Kaktus",
926 + "Kaliber",
927 + "Kaltluft",
928 + "Kamel",
929 + "kämmen",
930 + "Kampagne",
931 + "Kanal",
932 + "Känguru",
933 + "Kanister",
934 + "Kanone",
935 + "Kante",
936 + "Kanu",
937 + "kapern",
938 + "Kapitän",
939 + "Kapuze",
940 + "Karneval",
941 + "Karotte",
942 + "Käsebrot",
943 + "Kasper",
944 + "Kastanie",
945 + "Katalog",
946 + "Kathode",
947 + "Katze",
948 + "kaufen",
949 + "Kaugummi",
950 + "Kauz",
951 + "Kehle",
952 + "Keilerei",
953 + "Keksdose",
954 + "Kellner",
955 + "Keramik",
956 + "Kerze",
957 + "Kessel",
958 + "Kette",
959 + "keuchen",
960 + "kichern",
961 + "Kielboot",
962 + "Kindheit",
963 + "Kinnbart",
964 + "Kinosaal",
965 + "Kiosk",
966 + "Kissen",
967 + "Klammer",
968 + "Klang",
969 + "Klapprad",
970 + "Klartext",
971 + "kleben",
972 + "Klee",
973 + "Kleinod",
974 + "Klima",
975 + "Klingel",
976 + "Klippe",
977 + "Klischee",
978 + "Kloster",
979 + "Klugheit",
980 + "Klüngel",
981 + "kneten",
982 + "Knie",
983 + "Knöchel",
984 + "knüpfen",
985 + "Kobold",
986 + "Kochbuch",
987 + "Kohlrabi",
988 + "Koje",
989 + "Kokosöl",
990 + "Kolibri",
991 + "Kolumne",
992 + "Kombüse",
993 + "Komiker",
994 + "kommen",
995 + "Konto",
996 + "Konzept",
997 + "Kopfkino",
998 + "Kordhose",
999 + "Korken",
1000 + "Korsett",
1001 + "Kosename",
1002 + "Krabbe",
1003 + "Krach",
1004 + "Kraft",
1005 + "Krähe",
1006 + "Kralle",
1007 + "Krapfen",
1008 + "Krater",
1009 + "kraulen",
1010 + "Kreuz",
1011 + "Krokodil",
1012 + "Kröte",
1013 + "Kugel",
1014 + "Kuhhirt",
1015 + "Kühnheit",
1016 + "Künstler",
1017 + "Kurort",
1018 + "Kurve",
1019 + "Kurzfilm",
1020 + "kuscheln",
1021 + "küssen",
1022 + "Kutter",
1023 + "Labor",
1024 + "lachen",
1025 + "Lackaffe",
1026 + "Ladeluke",
1027 + "Lagune",
1028 + "Laib",
1029 + "Lakritze",
1030 + "Lammfell",
1031 + "Land",
1032 + "Langmut",
1033 + "Lappalie",
1034 + "Last",
1035 + "Laterne",
1036 + "Latzhose",
1037 + "Laubsäge",
1038 + "laufen",
1039 + "Laune",
1040 + "Lausbub",
1041 + "Lavasee",
1042 + "Leben",
1043 + "Leder",
1044 + "Leerlauf",
1045 + "Lehm",
1046 + "Lehrer",
1047 + "leihen",
1048 + "Lektüre",
1049 + "Lenker",
1050 + "Lerche",
1051 + "Leseecke",
1052 + "Leuchter",
1053 + "Lexikon",
1054 + "Libelle",
1055 + "Libido",
1056 + "Licht",
1057 + "Liebe",
1058 + "liefern",
1059 + "Liftboy",
1060 + "Limonade",
1061 + "Lineal",
1062 + "Linoleum",
1063 + "List",
1064 + "Liveband",
1065 + "Lobrede",
1066 + "locken",
1067 + "Löffel",
1068 + "Logbuch",
1069 + "Logik",
1070 + "Lohn",
1071 + "Loipe",
1072 + "Lokal",
1073 + "Lorbeer",
1074 + "Lösung",
1075 + "löten",
1076 + "Lottofee",
1077 + "Löwe",
1078 + "Luchs",
1079 + "Luder",
1080 + "Luftpost",
1081 + "Luke",
1082 + "Lümmel",
1083 + "Lunge",
1084 + "lutschen",
1085 + "Luxus",
1086 + "Macht",
1087 + "Magazin",
1088 + "Magier",
1089 + "Magnet",
1090 + "mähen",
1091 + "Mahlzeit",
1092 + "Mahnmal",
1093 + "Maibaum",
1094 + "Maisbrei",
1095 + "Makel",
1096 + "malen",
1097 + "Mammut",
1098 + "Maniküre",
1099 + "Mantel",
1100 + "Marathon",
1101 + "Marder",
1102 + "Marine",
1103 + "Marke",
1104 + "Marmor",
1105 + "Märzluft",
1106 + "Maske",
1107 + "Maßanzug",
1108 + "Maßkrug",
1109 + "Mastkorb",
1110 + "Material",
1111 + "Matratze",
1112 + "Mauerbau",
1113 + "Maulkorb",
1114 + "Mäuschen",
1115 + "Mäzen",
1116 + "Medium",
1117 + "Meinung",
1118 + "melden",
1119 + "Melodie",
1120 + "Mensch",
1121 + "Merkmal",
1122 + "Messe",
1123 + "Metall",
1124 + "Meteor",
1125 + "Methode",
1126 + "Metzger",
1127 + "Mieze",
1128 + "Milchkuh",
1129 + "Mimose",
1130 + "Minirock",
1131 + "Minute",
1132 + "mischen",
1133 + "Missetat",
1134 + "mitgehen",
1135 + "Mittag",
1136 + "Mixtape",
1137 + "Möbel",
1138 + "Modul",
1139 + "mögen",
1140 + "Möhre",
1141 + "Molch",
1142 + "Moment",
1143 + "Monat",
1144 + "Mondflug",
1145 + "Monitor",
1146 + "Monokini",
1147 + "Monster",
1148 + "Monument",
1149 + "Moorhuhn",
1150 + "Moos",
1151 + "Möpse",
1152 + "Moral",
1153 + "Mörtel",
1154 + "Motiv",
1155 + "Motorrad",
1156 + "Möwe",
1157 + "Mühe",
1158 + "Mulatte",
1159 + "Müller",
1160 + "Mumie",
1161 + "Mund",
1162 + "Münze",
1163 + "Muschel",
1164 + "Muster",
1165 + "Mythos",
1166 + "Nabel",
1167 + "Nachtzug",
1168 + "Nackedei",
1169 + "Nagel",
1170 + "Nähe",
1171 + "Nähnadel",
1172 + "Namen",
1173 + "Narbe",
1174 + "Narwal",
1175 + "Nasenbär",
1176 + "Natur",
1177 + "Nebel",
1178 + "necken",
1179 + "Neffe",
1180 + "Neigung",
1181 + "Nektar",
1182 + "Nenner",
1183 + "Neptun",
1184 + "Nerz",
1185 + "Nessel",
1186 + "Nestbau",
1187 + "Netz",
1188 + "Neubau",
1189 + "Neuerung",
1190 + "Neugier",
1191 + "nicken",
1192 + "Niere",
1193 + "Nilpferd",
1194 + "nisten",
1195 + "Nocke",
1196 + "Nomade",
1197 + "Nordmeer",
1198 + "Notdurft",
1199 + "Notstand",
1200 + "Notwehr",
1201 + "Nudismus",
1202 + "Nuss",
1203 + "Nutzhanf",
1204 + "Oase",
1205 + "Obdach",
1206 + "Oberarzt",
1207 + "Objekt",
1208 + "Oboe",
1209 + "Obsthain",
1210 + "Ochse",
1211 + "Odyssee",
1212 + "Ofenholz",
1213 + "öffnen",
1214 + "Ohnmacht",
1215 + "Ohrfeige",
1216 + "Ohrwurm",
1217 + "Ökologie",
1218 + "Oktave",
1219 + "Ölberg",
1220 + "Olive",
1221 + "Ölkrise",
1222 + "Omelett",
1223 + "Onkel",
1224 + "Oper",
1225 + "Optiker",
1226 + "Orange",
1227 + "Orchidee",
1228 + "ordnen",
1229 + "Orgasmus",
1230 + "Orkan",
1231 + "Ortskern",
1232 + "Ortung",
1233 + "Ostasien",
1234 + "Ozean",
1235 + "Paarlauf",
1236 + "Packeis",
1237 + "paddeln",
1238 + "Paket",
1239 + "Palast",
1240 + "Pandabär",
1241 + "Panik",
1242 + "Panorama",
1243 + "Panther",
1244 + "Papagei",
1245 + "Papier",
1246 + "Paprika",
1247 + "Paradies",
1248 + "Parka",
1249 + "Parodie",
1250 + "Partner",
1251 + "Passant",
1252 + "Patent",
1253 + "Patzer",
1254 + "Pause",
1255 + "Pavian",
1256 + "Pedal",
1257 + "Pegel",
1258 + "peilen",
1259 + "Perle",
1260 + "Person",
1261 + "Pfad",
1262 + "Pfau",
1263 + "Pferd",
1264 + "Pfleger",
1265 + "Physik",
1266 + "Pier",
1267 + "Pilotwal",
1268 + "Pinzette",
1269 + "Piste",
1270 + "Plakat",
1271 + "Plankton",
1272 + "Platin",
1273 + "Plombe",
1274 + "plündern",
1275 + "Pobacke",
1276 + "Pokal",
1277 + "polieren",
1278 + "Popmusik",
1279 + "Porträt",
1280 + "Posaune",
1281 + "Postamt",
1282 + "Pottwal",
1283 + "Pracht",
1284 + "Pranke",
1285 + "Preis",
1286 + "Primat",
1287 + "Prinzip",
1288 + "Protest",
1289 + "Proviant",
1290 + "Prüfung",
1291 + "Pubertät",
1292 + "Pudding",
1293 + "Pullover",
1294 + "Pulsader",
1295 + "Punkt",
1296 + "Pute",
1297 + "Putsch",
1298 + "Puzzle",
1299 + "Python",
1300 + "quaken",
1301 + "Qualle",
1302 + "Quark",
1303 + "Quellsee",
1304 + "Querkopf",
1305 + "Quitte",
1306 + "Quote",
1307 + "Rabauke",
1308 + "Rache",
1309 + "Radclub",
1310 + "Radhose",
1311 + "Radio",
1312 + "Radtour",
1313 + "Rahmen",
1314 + "Rampe",
1315 + "Randlage",
1316 + "Ranzen",
1317 + "Rapsöl",
1318 + "Raserei",
1319 + "rasten",
1320 + "Rasur",
1321 + "Rätsel",
1322 + "Raubtier",
1323 + "Raumzeit",
1324 + "Rausch",
1325 + "Reaktor",
1326 + "Realität",
1327 + "Rebell",
1328 + "Rede",
1329 + "Reetdach",
1330 + "Regatta",
1331 + "Regen",
1332 + "Rehkitz",
1333 + "Reifen",
1334 + "Reim",
1335 + "Reise",
1336 + "Reizung",
1337 + "Rekord",
1338 + "Relevanz",
1339 + "Rennboot",
1340 + "Respekt",
1341 + "Restmüll",
1342 + "retten",
1343 + "Reue",
1344 + "Revolte",
1345 + "Rhetorik",
1346 + "Rhythmus",
1347 + "Richtung",
1348 + "Riegel",
1349 + "Rindvieh",
1350 + "Rippchen",
1351 + "Ritter",
1352 + "Robbe",
1353 + "Roboter",
1354 + "Rockband",
1355 + "Rohdaten",
1356 + "Roller",
1357 + "Roman",
1358 + "röntgen",
1359 + "Rose",
1360 + "Rosskur",
1361 + "Rost",
1362 + "Rotahorn",
1363 + "Rotglut",
1364 + "Rotznase",
1365 + "Rubrik",
1366 + "Rückweg",
1367 + "Rufmord",
1368 + "Ruhe",
1369 + "Ruine",
1370 + "Rumpf",
1371 + "Runde",
1372 + "Rüstung",
1373 + "rütteln",
1374 + "Saaltür",
1375 + "Saatguts",
1376 + "Säbel",
1377 + "Sachbuch",
1378 + "Sack",
1379 + "Saft",
1380 + "sagen",
1381 + "Sahneeis",
1382 + "Salat",
1383 + "Salbe",
1384 + "Salz",
1385 + "Sammlung",
1386 + "Samt",
1387 + "Sandbank",
1388 + "Sanftmut",
1389 + "Sardine",
1390 + "Satire",
1391 + "Sattel",
1392 + "Satzbau",
1393 + "Sauerei",
1394 + "Saum",
1395 + "Säure",
1396 + "Schall",
1397 + "Scheitel",
1398 + "Schiff",
1399 + "Schlager",
1400 + "Schmied",
1401 + "Schnee",
1402 + "Scholle",
1403 + "Schrank",
1404 + "Schulbus",
1405 + "Schwan",
1406 + "Seeadler",
1407 + "Seefahrt",
1408 + "Seehund",
1409 + "Seeufer",
1410 + "segeln",
1411 + "Sehnerv",
1412 + "Seide",
1413 + "Seilzug",
1414 + "Senf",
1415 + "Sessel",
1416 + "Seufzer",
1417 + "Sexgott",
1418 + "Sichtung",
1419 + "Signal",
1420 + "Silber",
1421 + "singen",
1422 + "Sinn",
1423 + "Sirup",
1424 + "Sitzbank",
1425 + "Skandal",
1426 + "Skikurs",
1427 + "Skipper",
1428 + "Skizze",
1429 + "Smaragd",
1430 + "Socke",
1431 + "Sohn",
1432 + "Sommer",
1433 + "Songtext",
1434 + "Sorte",
1435 + "Spagat",
1436 + "Spannung",
1437 + "Spargel",
1438 + "Specht",
1439 + "Speiseöl",
1440 + "Spiegel",
1441 + "Sport",
1442 + "spülen",
1443 + "Stadtbus",
1444 + "Stall",
1445 + "Stärke",
1446 + "Stativ",
1447 + "staunen",
1448 + "Stern",
1449 + "Stiftung",
1450 + "Stollen",
1451 + "Strömung",
1452 + "Sturm",
1453 + "Substanz",
1454 + "Südalpen",
1455 + "Sumpf",
1456 + "surfen",
1457 + "Tabak",
1458 + "Tafel",
1459 + "Tagebau",
1460 + "takeln",
1461 + "Taktung",
1462 + "Talsohle",
1463 + "Tand",
1464 + "Tanzbär",
1465 + "Tapir",
1466 + "Tarantel",
1467 + "Tarnname",
1468 + "Tasse",
1469 + "Tatnacht",
1470 + "Tatsache",
1471 + "Tatze",
1472 + "Taube",
1473 + "tauchen",
1474 + "Taufpate",
1475 + "Taumel",
1476 + "Teelicht",
1477 + "Teich",
1478 + "teilen",
1479 + "Tempo",
1480 + "Tenor",
1481 + "Terrasse",
1482 + "Testflug",
1483 + "Theater",
1484 + "Thermik",
1485 + "ticken",
1486 + "Tiefflug",
1487 + "Tierart",
1488 + "Tigerhai",
1489 + "Tinte",
1490 + "Tischler",
1491 + "toben",
1492 + "Toleranz",
1493 + "Tölpel",
1494 + "Tonband",
1495 + "Topf",
1496 + "Topmodel",
1497 + "Torbogen",
1498 + "Torlinie",
1499 + "Torte",
1500 + "Tourist",
1501 + "Tragesel",
1502 + "trampeln",
1503 + "Trapez",
1504 + "Traum",
1505 + "treffen",
1506 + "Trennung",
1507 + "Treue",
1508 + "Trick",
1509 + "trimmen",
1510 + "Trödel",
1511 + "Trost",
1512 + "Trumpf",
1513 + "tüfteln",
1514 + "Turban",
1515 + "Turm",
1516 + "Übermut",
1517 + "Ufer",
1518 + "Uhrwerk",
1519 + "umarmen",
1520 + "Umbau",
1521 + "Umfeld",
1522 + "Umgang",
1523 + "Umsturz",
1524 + "Unart",
1525 + "Unfug",
1526 + "Unimog",
1527 + "Unruhe",
1528 + "Unwucht",
1529 + "Uranerz",
1530 + "Urlaub",
1531 + "Urmensch",
1532 + "Utopie",
1533 + "Vakuum",
1534 + "Valuta",
1535 + "Vandale",
1536 + "Vase",
1537 + "Vektor",
1538 + "Ventil",
1539 + "Verb",
1540 + "Verdeck",
1541 + "Verfall",
1542 + "Vergaser",
1543 + "verhexen",
1544 + "Verlag",
1545 + "Vers",
1546 + "Vesper",
1547 + "Vieh",
1548 + "Viereck",
1549 + "Vinyl",
1550 + "Virus",
1551 + "Vitrine",
1552 + "Vollblut",
1553 + "Vorbote",
1554 + "Vorrat",
1555 + "Vorsicht",
1556 + "Vulkan",
1557 + "Wachstum",
1558 + "Wade",
1559 + "Wagemut",
1560 + "Wahlen",
1561 + "Wahrheit",
1562 + "Wald",
1563 + "Walhai",
1564 + "Wallach",
1565 + "Walnuss",
1566 + "Walzer",
1567 + "wandeln",
1568 + "Wanze",
1569 + "wärmen",
1570 + "Warnruf",
1571 + "Wäsche",
1572 + "Wasser",
1573 + "Weberei",
1574 + "wechseln",
1575 + "Wegegeld",
1576 + "wehren",
1577 + "Weiher",
1578 + "Weinglas",
1579 + "Weißbier",
1580 + "Weitwurf",
1581 + "Welle",
1582 + "Weltall",
1583 + "Werkbank",
1584 + "Werwolf",
1585 + "Wetter",
1586 + "wiehern",
1587 + "Wildgans",
1588 + "Wind",
1589 + "Wohl",
1590 + "Wohnort",
1591 + "Wolf",
1592 + "Wollust",
1593 + "Wortlaut",
1594 + "Wrack",
1595 + "Wunder",
1596 + "Wurfaxt",
1597 + "Wurst",
1598 + "Yacht",
1599 + "Yeti",
1600 + "Zacke",
1601 + "Zahl",
1602 + "zähmen",
1603 + "Zahnfee",
1604 + "Zäpfchen",
1605 + "Zaster",
1606 + "Zaumzeug",
1607 + "Zebra",
1608 + "zeigen",
1609 + "Zeitlupe",
1610 + "Zellkern",
1611 + "Zeltdach",
1612 + "Zensor",
1613 + "Zerfall",
1614 + "Zeug",
1615 + "Ziege",
1616 + "Zielfoto",
1617 + "Zimteis",
1618 + "Zobel",
1619 + "Zollhund",
1620 + "Zombie",
1621 + "Zöpfe",
1622 + "Zucht",
1623 + "Zufahrt",
1624 + "Zugfahrt",
1625 + "Zugvogel",
1626 + "Zündung",
1627 + "Zweck",
1628 + "Zyklop"
1629 + ];
1630 +}
\ No newline at end of file
cw_haven/lib/mnemonics/italian.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class ItalianMnemonics {
2 + static const words = [
3 + "abbinare",
4 + "abbonato",
5 + "abisso",
6 + "abitare",
7 + "abominio",
8 + "accadere",
9 + "accesso",
10 + "acciaio",
11 + "accordo",
12 + "accumulo",
13 + "acido",
14 + "acqua",
15 + "acrobata",
16 + "acustico",
17 + "adattare",
18 + "addetto",
19 + "addio",
20 + "addome",
21 + "adeguato",
22 + "aderire",
23 + "adorare",
24 + "adottare",
25 + "adozione",
26 + "adulto",
27 + "aereo",
28 + "aerobica",
29 + "affare",
30 + "affetto",
31 + "affidare",
32 + "affogato",
33 + "affronto",
34 + "africano",
35 + "afrodite",
36 + "agenzia",
37 + "aggancio",
38 + "aggeggio",
39 + "aggiunta",
40 + "agio",
41 + "agire",
42 + "agitare",
43 + "aglio",
44 + "agnello",
45 + "agosto",
46 + "aiutare",
47 + "albero",
48 + "albo",
49 + "alce",
50 + "alchimia",
51 + "alcool",
52 + "alfabeto",
53 + "algebra",
54 + "alimento",
55 + "allarme",
56 + "alleanza",
57 + "allievo",
58 + "alloggio",
59 + "alluce",
60 + "alpi",
61 + "alterare",
62 + "altro",
63 + "aluminio",
64 + "amante",
65 + "amarezza",
66 + "ambiente",
67 + "ambrosia",
68 + "america",
69 + "amico",
70 + "ammalare",
71 + "ammirare",
72 + "amnesia",
73 + "amnistia",
74 + "amore",
75 + "ampliare",
76 + "amputare",
77 + "analisi",
78 + "anamnesi",
79 + "ananas",
80 + "anarchia",
81 + "anatra",
82 + "anca",
83 + "ancorato",
84 + "andare",
85 + "androide",
86 + "aneddoto",
87 + "anello",
88 + "angelo",
89 + "angolino",
90 + "anguilla",
91 + "anidride",
92 + "anima",
93 + "annegare",
94 + "anno",
95 + "annuncio",
96 + "anomalia",
97 + "antenna",
98 + "anticipo",
99 + "aperto",
100 + "apostolo",
101 + "appalto",
102 + "appello",
103 + "appiglio",
104 + "applauso",
105 + "appoggio",
106 + "appurare",
107 + "aprile",
108 + "aquila",
109 + "arabo",
110 + "arachidi",
111 + "aragosta",
112 + "arancia",
113 + "arbitrio",
114 + "archivio",
115 + "arco",
116 + "argento",
117 + "argilla",
118 + "aria",
119 + "ariete",
120 + "arma",
121 + "armonia",
122 + "aroma",
123 + "arrivare",
124 + "arrosto",
125 + "arsenale",
126 + "arte",
127 + "artiglio",
128 + "asfalto",
129 + "asfissia",
130 + "asino",
131 + "asparagi",
132 + "aspirina",
133 + "assalire",
134 + "assegno",
135 + "assolto",
136 + "assurdo",
137 + "asta",
138 + "astratto",
139 + "atlante",
140 + "atletica",
141 + "atomo",
142 + "atropina",
143 + "attacco",
144 + "attesa",
145 + "attico",
146 + "atto",
147 + "attrarre",
148 + "auguri",
149 + "aula",
150 + "aumento",
151 + "aurora",
152 + "auspicio",
153 + "autista",
154 + "auto",
155 + "autunno",
156 + "avanzare",
157 + "avarizia",
158 + "avere",
159 + "aviatore",
160 + "avido",
161 + "avorio",
162 + "avvenire",
163 + "avviso",
164 + "avvocato",
165 + "azienda",
166 + "azione",
167 + "azzardo",
168 + "azzurro",
169 + "babbuino",
170 + "bacio",
171 + "badante",
172 + "baffi",
173 + "bagaglio",
174 + "bagliore",
175 + "bagno",
176 + "balcone",
177 + "balena",
178 + "ballare",
179 + "balordo",
180 + "balsamo",
181 + "bambola",
182 + "bancomat",
183 + "banda",
184 + "barato",
185 + "barba",
186 + "barista",
187 + "barriera",
188 + "basette",
189 + "basilico",
190 + "bassista",
191 + "bastare",
192 + "battello",
193 + "bavaglio",
194 + "beccare",
195 + "beduino",
196 + "bellezza",
197 + "bene",
198 + "benzina",
199 + "berretto",
200 + "bestia",
201 + "bevitore",
202 + "bianco",
203 + "bibbia",
204 + "biberon",
205 + "bibita",
206 + "bici",
207 + "bidone",
208 + "bilancia",
209 + "biliardo",
210 + "binario",
211 + "binocolo",
212 + "biologia",
213 + "biondina",
214 + "biopsia",
215 + "biossido",
216 + "birbante",
217 + "birra",
218 + "biscotto",
219 + "bisogno",
220 + "bistecca",
221 + "bivio",
222 + "blindare",
223 + "bloccare",
224 + "bocca",
225 + "bollire",
226 + "bombola",
227 + "bonifico",
228 + "borghese",
229 + "borsa",
230 + "bottino",
231 + "botulino",
232 + "braccio",
233 + "bradipo",
234 + "branco",
235 + "bravo",
236 + "bresaola",
237 + "bretelle",
238 + "brevetto",
239 + "briciola",
240 + "brigante",
241 + "brillare",
242 + "brindare",
243 + "brivido",
244 + "broccoli",
245 + "brontolo",
246 + "bruciare",
247 + "brufolo",
248 + "bucare",
249 + "buddista",
250 + "budino",
251 + "bufera",
252 + "buffo",
253 + "bugiardo",
254 + "buio",
255 + "buono",
256 + "burrone",
257 + "bussola",
258 + "bustina",
259 + "buttare",
260 + "cabernet",
261 + "cabina",
262 + "cacao",
263 + "cacciare",
264 + "cactus",
265 + "cadavere",
266 + "caffe",
267 + "calamari",
268 + "calcio",
269 + "caldaia",
270 + "calmare",
271 + "calunnia",
272 + "calvario",
273 + "calzone",
274 + "cambiare",
275 + "camera",
276 + "camion",
277 + "cammello",
278 + "campana",
279 + "canarino",
280 + "cancello",
281 + "candore",
282 + "cane",
283 + "canguro",
284 + "cannone",
285 + "canoa",
286 + "cantare",
287 + "canzone",
288 + "caos",
289 + "capanna",
290 + "capello",
291 + "capire",
292 + "capo",
293 + "capperi",
294 + "capra",
295 + "capsula",
296 + "caraffa",
297 + "carbone",
298 + "carciofo",
299 + "cardigan",
300 + "carenza",
301 + "caricare",
302 + "carota",
303 + "carrello",
304 + "carta",
305 + "casa",
306 + "cascare",
307 + "caserma",
308 + "cashmere",
309 + "casino",
310 + "cassetta",
311 + "castello",
312 + "catalogo",
313 + "catena",
314 + "catorcio",
315 + "cattivo",
316 + "causa",
317 + "cauzione",
318 + "cavallo",
319 + "caverna",
320 + "caviglia",
321 + "cavo",
322 + "cazzotto",
323 + "celibato",
324 + "cemento",
325 + "cenare",
326 + "centrale",
327 + "ceramica",
328 + "cercare",
329 + "ceretta",
330 + "cerniera",
331 + "certezza",
332 + "cervello",
333 + "cessione",
334 + "cestino",
335 + "cetriolo",
336 + "chiave",
337 + "chiedere",
338 + "chilo",
339 + "chimera",
340 + "chiodo",
341 + "chirurgo",
342 + "chitarra",
343 + "chiudere",
344 + "ciabatta",
345 + "ciao",
346 + "cibo",
347 + "ciccia",
348 + "cicerone",
349 + "ciclone",
350 + "cicogna",
351 + "cielo",
352 + "cifra",
353 + "cigno",
354 + "ciliegia",
355 + "cimitero",
356 + "cinema",
357 + "cinque",
358 + "cintura",
359 + "ciondolo",
360 + "ciotola",
361 + "cipolla",
362 + "cippato",
363 + "circuito",
364 + "cisterna",
365 + "citofono",
366 + "ciuccio",
367 + "civetta",
368 + "civico",
369 + "clausola",
370 + "cliente",
371 + "clima",
372 + "clinica",
373 + "cobra",
374 + "coccole",
375 + "cocktail",
376 + "cocomero",
377 + "codice",
378 + "coesione",
379 + "cogliere",
380 + "cognome",
381 + "colla",
382 + "colomba",
383 + "colpire",
384 + "coltello",
385 + "comando",
386 + "comitato",
387 + "commedia",
388 + "comodino",
389 + "compagna",
390 + "comune",
391 + "concerto",
392 + "condotto",
393 + "conforto",
394 + "congiura",
395 + "coniglio",
396 + "consegna",
397 + "conto",
398 + "convegno",
399 + "coperta",
400 + "copia",
401 + "coprire",
402 + "corazza",
403 + "corda",
404 + "corleone",
405 + "cornice",
406 + "corona",
407 + "corpo",
408 + "corrente",
409 + "corsa",
410 + "cortesia",
411 + "corvo",
412 + "coso",
413 + "costume",
414 + "cotone",
415 + "cottura",
416 + "cozza",
417 + "crampo",
418 + "cratere",
419 + "cravatta",
420 + "creare",
421 + "credere",
422 + "crema",
423 + "crescere",
424 + "crimine",
425 + "criterio",
426 + "croce",
427 + "crollare",
428 + "cronaca",
429 + "crostata",
430 + "croupier",
431 + "cubetto",
432 + "cucciolo",
433 + "cucina",
434 + "cultura",
435 + "cuoco",
436 + "cuore",
437 + "cupido",
438 + "cupola",
439 + "cura",
440 + "curva",
441 + "cuscino",
442 + "custode",
443 + "danzare",
444 + "data",
445 + "decennio",
446 + "decidere",
447 + "decollo",
448 + "dedicare",
449 + "dedurre",
450 + "definire",
451 + "delegare",
452 + "delfino",
453 + "delitto",
454 + "demone",
455 + "dentista",
456 + "denuncia",
457 + "deposito",
458 + "derivare",
459 + "deserto",
460 + "designer",
461 + "destino",
462 + "detonare",
463 + "dettagli",
464 + "diagnosi",
465 + "dialogo",
466 + "diamante",
467 + "diario",
468 + "diavolo",
469 + "dicembre",
470 + "difesa",
471 + "digerire",
472 + "digitare",
473 + "diluvio",
474 + "dinamica",
475 + "dipinto",
476 + "diploma",
477 + "diramare",
478 + "dire",
479 + "dirigere",
480 + "dirupo",
481 + "discesa",
482 + "disdetta",
483 + "disegno",
484 + "disporre",
485 + "dissenso",
486 + "distacco",
487 + "dito",
488 + "ditta",
489 + "diva",
490 + "divenire",
491 + "dividere",
492 + "divorare",
493 + "docente",
494 + "dolcetto",
495 + "dolore",
496 + "domatore",
497 + "domenica",
498 + "dominare",
499 + "donatore",
500 + "donna",
501 + "dorato",
502 + "dormire",
503 + "dorso",
504 + "dosaggio",
505 + "dottore",
506 + "dovere",
507 + "download",
508 + "dragone",
509 + "dramma",
510 + "dubbio",
511 + "dubitare",
512 + "duetto",
513 + "durata",
514 + "ebbrezza",
515 + "eccesso",
516 + "eccitare",
517 + "eclissi",
518 + "economia",
519 + "edera",
520 + "edificio",
521 + "editore",
522 + "edizione",
523 + "educare",
524 + "effetto",
525 + "egitto",
526 + "egiziano",
527 + "elastico",
528 + "elefante",
529 + "eleggere",
530 + "elemento",
531 + "elenco",
532 + "elezione",
533 + "elmetto",
534 + "elogio",
535 + "embrione",
536 + "emergere",
537 + "emettere",
538 + "eminenza",
539 + "emisfero",
540 + "emozione",
541 + "empatia",
542 + "energia",
543 + "enfasi",
544 + "enigma",
545 + "entrare",
546 + "enzima",
547 + "epidemia",
548 + "epilogo",
549 + "episodio",
550 + "epoca",
551 + "equivoco",
552 + "erba",
553 + "erede",
554 + "eroe",
555 + "erotico",
556 + "errore",
557 + "eruzione",
558 + "esaltare",
559 + "esame",
560 + "esaudire",
561 + "eseguire",
562 + "esempio",
563 + "esigere",
564 + "esistere",
565 + "esito",
566 + "esperto",
567 + "espresso",
568 + "essere",
569 + "estasi",
570 + "esterno",
571 + "estrarre",
572 + "eterno",
573 + "etica",
574 + "euforico",
575 + "europa",
576 + "evacuare",
577 + "evasione",
578 + "evento",
579 + "evidenza",
580 + "evitare",
581 + "evolvere",
582 + "fabbrica",
583 + "facciata",
584 + "fagiano",
585 + "fagotto",
586 + "falco",
587 + "fame",
588 + "famiglia",
589 + "fanale",
590 + "fango",
591 + "fantasia",
592 + "farfalla",
593 + "farmacia",
594 + "faro",
595 + "fase",
596 + "fastidio",
597 + "faticare",
598 + "fatto",
599 + "favola",
600 + "febbre",
601 + "femmina",
602 + "femore",
603 + "fenomeno",
604 + "fermata",
605 + "feromoni",
606 + "ferrari",
607 + "fessura",
608 + "festa",
609 + "fiaba",
610 + "fiamma",
611 + "fianco",
612 + "fiat",
613 + "fibbia",
614 + "fidare",
615 + "fieno",
616 + "figa",
617 + "figlio",
618 + "figura",
619 + "filetto",
620 + "filmato",
621 + "filosofo",
622 + "filtrare",
623 + "finanza",
624 + "finestra",
625 + "fingere",
626 + "finire",
627 + "finta",
628 + "finzione",
629 + "fiocco",
630 + "fioraio",
631 + "firewall",
632 + "firmare",
633 + "fisico",
634 + "fissare",
635 + "fittizio",
636 + "fiume",
637 + "flacone",
638 + "flagello",
639 + "flirtare",
640 + "flusso",
641 + "focaccia",
642 + "foglio",
643 + "fognario",
644 + "follia",
645 + "fonderia",
646 + "fontana",
647 + "forbici",
648 + "forcella",
649 + "foresta",
650 + "forgiare",
651 + "formare",
652 + "fornace",
653 + "foro",
654 + "fortuna",
655 + "forzare",
656 + "fosforo",
657 + "fotoni",
658 + "fracasso",
659 + "fragola",
660 + "frantumi",
661 + "fratello",
662 + "frazione",
663 + "freccia",
664 + "freddo",
665 + "frenare",
666 + "fresco",
667 + "friggere",
668 + "frittata",
669 + "frivolo",
670 + "frizione",
671 + "fronte",
672 + "frullato",
673 + "frumento",
674 + "frusta",
675 + "frutto",
676 + "fucile",
677 + "fuggire",
678 + "fulmine",
679 + "fumare",
680 + "funzione",
681 + "fuoco",
682 + "furbizia",
683 + "furgone",
684 + "furia",
685 + "furore",
686 + "fusibile",
687 + "fuso",
688 + "futuro",
689 + "gabbiano",
690 + "galassia",
691 + "gallina",
692 + "gamba",
693 + "gancio",
694 + "garanzia",
695 + "garofano",
696 + "gasolio",
697 + "gatto",
698 + "gazebo",
699 + "gazzetta",
700 + "gelato",
701 + "gemelli",
702 + "generare",
703 + "genitori",
704 + "gennaio",
705 + "geologia",
706 + "germania",
707 + "gestire",
708 + "gettare",
709 + "ghepardo",
710 + "ghiaccio",
711 + "giaccone",
712 + "giaguaro",
713 + "giallo",
714 + "giappone",
715 + "giardino",
716 + "gigante",
717 + "gioco",
718 + "gioiello",
719 + "giorno",
720 + "giovane",
721 + "giraffa",
722 + "giudizio",
723 + "giurare",
724 + "giusto",
725 + "globo",
726 + "gloria",
727 + "glucosio",
728 + "gnocca",
729 + "gocciola",
730 + "godere",
731 + "gomito",
732 + "gomma",
733 + "gonfiare",
734 + "gorilla",
735 + "governo",
736 + "gradire",
737 + "graffiti",
738 + "granchio",
739 + "grappolo",
740 + "grasso",
741 + "grattare",
742 + "gridare",
743 + "grissino",
744 + "grondaia",
745 + "grugnito",
746 + "gruppo",
747 + "guadagno",
748 + "guaio",
749 + "guancia",
750 + "guardare",
751 + "gufo",
752 + "guidare",
753 + "guscio",
754 + "gusto",
755 + "icona",
756 + "idea",
757 + "identico",
758 + "idolo",
759 + "idoneo",
760 + "idrante",
761 + "idrogeno",
762 + "igiene",
763 + "ignoto",
764 + "imbarco",
765 + "immagine",
766 + "immobile",
767 + "imparare",
768 + "impedire",
769 + "impianto",
770 + "importo",
771 + "impresa",
772 + "impulso",
773 + "incanto",
774 + "incendio",
775 + "incidere",
776 + "incontro",
777 + "incrocia",
778 + "incubo",
779 + "indagare",
780 + "indice",
781 + "indotto",
782 + "infanzia",
783 + "inferno",
784 + "infinito",
785 + "infranto",
786 + "ingerire",
787 + "inglese",
788 + "ingoiare",
789 + "ingresso",
790 + "iniziare",
791 + "innesco",
792 + "insalata",
793 + "inserire",
794 + "insicuro",
795 + "insonnia",
796 + "insulto",
797 + "interno",
798 + "introiti",
799 + "invasori",
800 + "inverno",
801 + "invito",
802 + "invocare",
803 + "ipnosi",
804 + "ipocrita",
805 + "ipotesi",
806 + "ironia",
807 + "irrigare",
808 + "iscritto",
809 + "isola",
810 + "ispirare",
811 + "isterico",
812 + "istinto",
813 + "istruire",
814 + "italiano",
815 + "jazz",
816 + "labbra",
817 + "labrador",
818 + "ladro",
819 + "lago",
820 + "lamento",
821 + "lampone",
822 + "lancetta",
823 + "lanterna",
824 + "lapide",
825 + "larva",
826 + "lasagne",
827 + "lasciare",
828 + "lastra",
829 + "latte",
830 + "laurea",
831 + "lavagna",
832 + "lavorare",
833 + "leccare",
834 + "legare",
835 + "leggere",
836 + "lenzuolo",
837 + "leone",
838 + "lepre",
839 + "letargo",
840 + "lettera",
841 + "levare",
842 + "levitare",
843 + "lezione",
844 + "liberare",
845 + "libidine",
846 + "libro",
847 + "licenza",
848 + "lievito",
849 + "limite",
850 + "lince",
851 + "lingua",
852 + "liquore",
853 + "lire",
854 + "listino",
855 + "litigare",
856 + "litro",
857 + "locale",
858 + "lottare",
859 + "lucciola",
860 + "lucidare",
861 + "luglio",
862 + "luna",
863 + "macchina",
864 + "madama",
865 + "madre",
866 + "maestro",
867 + "maggio",
868 + "magico",
869 + "maglione",
870 + "magnolia",
871 + "mago",
872 + "maialino",
873 + "maionese",
874 + "malattia",
875 + "male",
876 + "malloppo",
877 + "mancare",
878 + "mandorla",
879 + "mangiare",
880 + "manico",
881 + "manopola",
882 + "mansarda",
883 + "mantello",
884 + "manubrio",
885 + "manzo",
886 + "mappa",
887 + "mare",
888 + "margine",
889 + "marinaio",
890 + "marmotta",
891 + "marocco",
892 + "martello",
893 + "marzo",
894 + "maschera",
895 + "matrice",
896 + "maturare",
897 + "mazzetta",
898 + "meandri",
899 + "medaglia",
900 + "medico",
901 + "medusa",
902 + "megafono",
903 + "melone",
904 + "membrana",
905 + "menta",
906 + "mercato",
907 + "meritare",
908 + "merluzzo",
909 + "mese",
910 + "mestiere",
911 + "metafora",
912 + "meteo",
913 + "metodo",
914 + "mettere",
915 + "miele",
916 + "miglio",
917 + "miliardo",
918 + "mimetica",
919 + "minatore",
920 + "minuto",
921 + "miracolo",
922 + "mirtillo",
923 + "missile",
924 + "mistero",
925 + "misura",
926 + "mito",
927 + "mobile",
928 + "moda",
929 + "moderare",
930 + "moglie",
931 + "molecola",
932 + "molle",
933 + "momento",
934 + "moneta",
935 + "mongolia",
936 + "monologo",
937 + "montagna",
938 + "morale",
939 + "morbillo",
940 + "mordere",
941 + "mosaico",
942 + "mosca",
943 + "mostro",
944 + "motivare",
945 + "moto",
946 + "mulino",
947 + "mulo",
948 + "muovere",
949 + "muraglia",
950 + "muscolo",
951 + "museo",
952 + "musica",
953 + "mutande",
954 + "nascere",
955 + "nastro",
956 + "natale",
957 + "natura",
958 + "nave",
959 + "navigare",
960 + "negare",
961 + "negozio",
962 + "nemico",
963 + "nero",
964 + "nervo",
965 + "nessuno",
966 + "nettare",
967 + "neutroni",
968 + "neve",
969 + "nevicare",
970 + "nicotina",
971 + "nido",
972 + "nipote",
973 + "nocciola",
974 + "noleggio",
975 + "nome",
976 + "nonno",
977 + "norvegia",
978 + "notare",
979 + "notizia",
980 + "nove",
981 + "nucleo",
982 + "nuda",
983 + "nuotare",
984 + "nutrire",
985 + "obbligo",
986 + "occhio",
987 + "occupare",
988 + "oceano",
989 + "odissea",
990 + "odore",
991 + "offerta",
992 + "officina",
993 + "offrire",
994 + "oggetto",
995 + "oggi",
996 + "olfatto",
997 + "olio",
998 + "oliva",
999 + "ombelico",
1000 + "ombrello",
1001 + "omuncolo",
1002 + "ondata",
1003 + "onore",
1004 + "opera",
1005 + "opinione",
1006 + "opuscolo",
1007 + "opzione",
1008 + "orario",
1009 + "orbita",
1010 + "orchidea",
1011 + "ordine",
1012 + "orecchio",
1013 + "orgasmo",
1014 + "orgoglio",
1015 + "origine",
1016 + "orologio",
1017 + "oroscopo",
1018 + "orso",
1019 + "oscurare",
1020 + "ospedale",
1021 + "ospite",
1022 + "ossigeno",
1023 + "ostacolo",
1024 + "ostriche",
1025 + "ottenere",
1026 + "ottimo",
1027 + "ottobre",
1028 + "ovest",
1029 + "pacco",
1030 + "pace",
1031 + "pacifico",
1032 + "padella",
1033 + "pagare",
1034 + "pagina",
1035 + "pagnotta",
1036 + "palazzo",
1037 + "palestra",
1038 + "palpebre",
1039 + "pancetta",
1040 + "panfilo",
1041 + "panino",
1042 + "pannello",
1043 + "panorama",
1044 + "papa",
1045 + "paperino",
1046 + "paradiso",
1047 + "parcella",
1048 + "parente",
1049 + "parlare",
1050 + "parodia",
1051 + "parrucca",
1052 + "partire",
1053 + "passare",
1054 + "pasta",
1055 + "patata",
1056 + "patente",
1057 + "patogeno",
1058 + "patriota",
1059 + "pausa",
1060 + "pazienza",
1061 + "peccare",
1062 + "pecora",
1063 + "pedalare",
1064 + "pelare",
1065 + "pena",
1066 + "pendenza",
1067 + "penisola",
1068 + "pennello",
1069 + "pensare",
1070 + "pentirsi",
1071 + "percorso",
1072 + "perdono",
1073 + "perfetto",
1074 + "perizoma",
1075 + "perla",
1076 + "permesso",
1077 + "persona",
1078 + "pesare",
1079 + "pesce",
1080 + "peso",
1081 + "petardo",
1082 + "petrolio",
1083 + "pezzo",
1084 + "piacere",
1085 + "pianeta",
1086 + "piastra",
1087 + "piatto",
1088 + "piazza",
1089 + "piccolo",
1090 + "piede",
1091 + "piegare",
1092 + "pietra",
1093 + "pigiama",
1094 + "pigliare",
1095 + "pigrizia",
1096 + "pilastro",
1097 + "pilota",
1098 + "pinguino",
1099 + "pioggia",
1100 + "piombo",
1101 + "pionieri",
1102 + "piovra",
1103 + "pipa",
1104 + "pirata",
1105 + "pirolisi",
1106 + "piscina",
1107 + "pisolino",
1108 + "pista",
1109 + "pitone",
1110 + "piumino",
1111 + "pizza",
1112 + "plastica",
1113 + "platino",
1114 + "poesia",
1115 + "poiana",
1116 + "polaroid",
1117 + "polenta",
1118 + "polimero",
1119 + "pollo",
1120 + "polmone",
1121 + "polpetta",
1122 + "poltrona",
1123 + "pomodoro",
1124 + "pompa",
1125 + "popolo",
1126 + "porco",
1127 + "porta",
1128 + "porzione",
1129 + "possesso",
1130 + "postino",
1131 + "potassio",
1132 + "potere",
1133 + "poverino",
1134 + "pranzo",
1135 + "prato",
1136 + "prefisso",
1137 + "prelievo",
1138 + "premio",
1139 + "prendere",
1140 + "prestare",
1141 + "pretesa",
1142 + "prezzo",
1143 + "primario",
1144 + "privacy",
1145 + "problema",
1146 + "processo",
1147 + "prodotto",
1148 + "profeta",
1149 + "progetto",
1150 + "promessa",
1151 + "pronto",
1152 + "proposta",
1153 + "proroga",
1154 + "prossimo",
1155 + "proteina",
1156 + "prova",
1157 + "prudenza",
1158 + "pubblico",
1159 + "pudore",
1160 + "pugilato",
1161 + "pulire",
1162 + "pulsante",
1163 + "puntare",
1164 + "pupazzo",
1165 + "puzzle",
1166 + "quaderno",
1167 + "qualcuno",
1168 + "quarzo",
1169 + "quercia",
1170 + "quintale",
1171 + "rabbia",
1172 + "racconto",
1173 + "radice",
1174 + "raffica",
1175 + "ragazza",
1176 + "ragione",
1177 + "rammento",
1178 + "ramo",
1179 + "rana",
1180 + "randagio",
1181 + "rapace",
1182 + "rapinare",
1183 + "rapporto",
1184 + "rasatura",
1185 + "ravioli",
1186 + "reagire",
1187 + "realista",
1188 + "reattore",
1189 + "reazione",
1190 + "recitare",
1191 + "recluso",
1192 + "record",
1193 + "recupero",
1194 + "redigere",
1195 + "regalare",
1196 + "regina",
1197 + "regola",
1198 + "relatore",
1199 + "reliquia",
1200 + "remare",
1201 + "rendere",
1202 + "reparto",
1203 + "resina",
1204 + "resto",
1205 + "rete",
1206 + "retorica",
1207 + "rettile",
1208 + "revocare",
1209 + "riaprire",
1210 + "ribadire",
1211 + "ribelle",
1212 + "ricambio",
1213 + "ricetta",
1214 + "richiamo",
1215 + "ricordo",
1216 + "ridurre",
1217 + "riempire",
1218 + "riferire",
1219 + "riflesso",
1220 + "righello",
1221 + "rilancio",
1222 + "rilevare",
1223 + "rilievo",
1224 + "rimanere",
1225 + "rimborso",
1226 + "rinforzo",
1227 + "rinuncia",
1228 + "riparo",
1229 + "ripetere",
1230 + "riposare",
1231 + "ripulire",
1232 + "risalita",
1233 + "riscatto",
1234 + "riserva",
1235 + "riso",
1236 + "rispetto",
1237 + "ritaglio",
1238 + "ritmo",
1239 + "ritorno",
1240 + "ritratto",
1241 + "rituale",
1242 + "riunione",
1243 + "riuscire",
1244 + "riva",
1245 + "robotica",
1246 + "rondine",
1247 + "rosa",
1248 + "rospo",
1249 + "rosso",
1250 + "rotonda",
1251 + "rotta",
1252 + "roulotte",
1253 + "rubare",
1254 + "rubrica",
1255 + "ruffiano",
1256 + "rumore",
1257 + "ruota",
1258 + "ruscello",
1259 + "sabbia",
1260 + "sacco",
1261 + "saggio",
1262 + "sale",
1263 + "salire",
1264 + "salmone",
1265 + "salto",
1266 + "salutare",
1267 + "salvia",
1268 + "sangue",
1269 + "sanzioni",
1270 + "sapere",
1271 + "sapienza",
1272 + "sarcasmo",
1273 + "sardine",
1274 + "sartoria",
1275 + "sbalzo",
1276 + "sbarcare",
1277 + "sberla",
1278 + "sborsare",
1279 + "scadenza",
1280 + "scafo",
1281 + "scala",
1282 + "scambio",
1283 + "scappare",
1284 + "scarpa",
1285 + "scatola",
1286 + "scelta",
1287 + "scena",
1288 + "sceriffo",
1289 + "scheggia",
1290 + "schiuma",
1291 + "sciarpa",
1292 + "scienza",
1293 + "scimmia",
1294 + "sciopero",
1295 + "scivolo",
1296 + "sclerare",
1297 + "scolpire",
1298 + "sconto",
1299 + "scopa",
1300 + "scordare",
1301 + "scossa",
1302 + "scrivere",
1303 + "scrupolo",
1304 + "scuderia",
1305 + "scultore",
1306 + "scuola",
1307 + "scusare",
1308 + "sdraiare",
1309 + "secolo",
1310 + "sedativo",
1311 + "sedere",
1312 + "sedia",
1313 + "segare",
1314 + "segreto",
1315 + "seguire",
1316 + "semaforo",
1317 + "seme",
1318 + "senape",
1319 + "seno",
1320 + "sentiero",
1321 + "separare",
1322 + "sepolcro",
1323 + "sequenza",
1324 + "serata",
1325 + "serpente",
1326 + "servizio",
1327 + "sesso",
1328 + "seta",
1329 + "settore",
1330 + "sfamare",
1331 + "sfera",
1332 + "sfidare",
1333 + "sfiorare",
1334 + "sfogare",
1335 + "sgabello",
1336 + "sicuro",
1337 + "siepe",
1338 + "sigaro",
1339 + "silenzio",
1340 + "silicone",
1341 + "simbiosi",
1342 + "simpatia",
1343 + "simulare",
1344 + "sinapsi",
1345 + "sindrome",
1346 + "sinergia",
1347 + "sinonimo",
1348 + "sintonia",
1349 + "sirena",
1350 + "siringa",
1351 + "sistema",
1352 + "sito",
1353 + "smalto",
1354 + "smentire",
1355 + "smontare",
1356 + "soccorso",
1357 + "socio",
1358 + "soffitto",
1359 + "software",
1360 + "soggetto",
1361 + "sogliola",
1362 + "sognare",
1363 + "soldi",
1364 + "sole",
1365 + "sollievo",
1366 + "solo",
1367 + "sommario",
1368 + "sondare",
1369 + "sonno",
1370 + "sorpresa",
1371 + "sorriso",
1372 + "sospiro",
1373 + "sostegno",
1374 + "sovrano",
1375 + "spaccare",
1376 + "spada",
1377 + "spagnolo",
1378 + "spalla",
1379 + "sparire",
1380 + "spavento",
1381 + "spazio",
1382 + "specchio",
1383 + "spedire",
1384 + "spegnere",
1385 + "spendere",
1386 + "speranza",
1387 + "spessore",
1388 + "spezzare",
1389 + "spiaggia",
1390 + "spiccare",
1391 + "spiegare",
1392 + "spiffero",
1393 + "spingere",
1394 + "sponda",
1395 + "sporcare",
1396 + "spostare",
1397 + "spremuta",
1398 + "spugna",
1399 + "spumante",
1400 + "spuntare",
1401 + "squadra",
1402 + "squillo",
1403 + "staccare",
1404 + "stadio",
1405 + "stagione",
1406 + "stallone",
1407 + "stampa",
1408 + "stancare",
1409 + "starnuto",
1410 + "statura",
1411 + "stella",
1412 + "stendere",
1413 + "sterzo",
1414 + "stilista",
1415 + "stimolo",
1416 + "stinco",
1417 + "stiva",
1418 + "stoffa",
1419 + "storia",
1420 + "strada",
1421 + "stregone",
1422 + "striscia",
1423 + "studiare",
1424 + "stufa",
1425 + "stupendo",
1426 + "subire",
1427 + "successo",
1428 + "sudare",
1429 + "suono",
1430 + "superare",
1431 + "supporto",
1432 + "surfista",
1433 + "sussurro",
1434 + "svelto",
1435 + "svenire",
1436 + "sviluppo",
1437 + "svolta",
1438 + "svuotare",
1439 + "tabacco",
1440 + "tabella",
1441 + "tabu",
1442 + "tacchino",
1443 + "tacere",
1444 + "taglio",
1445 + "talento",
1446 + "tangente",
1447 + "tappeto",
1448 + "tartufo",
1449 + "tassello",
1450 + "tastiera",
1451 + "tavolo",
1452 + "tazza",
1453 + "teatro",
1454 + "tedesco",
1455 + "telaio",
1456 + "telefono",
1457 + "tema",
1458 + "temere",
1459 + "tempo",
1460 + "tendenza",
1461 + "tenebre",
1462 + "tensione",
1463 + "tentare",
1464 + "teologia",
1465 + "teorema",
1466 + "termica",
1467 + "terrazzo",
1468 + "teschio",
1469 + "tesi",
1470 + "tesoro",
1471 + "tessera",
1472 + "testa",
1473 + "thriller",
1474 + "tifoso",
1475 + "tigre",
1476 + "timbrare",
1477 + "timido",
1478 + "tinta",
1479 + "tirare",
1480 + "tisana",
1481 + "titano",
1482 + "titolo",
1483 + "toccare",
1484 + "togliere",
1485 + "topolino",
1486 + "torcia",
1487 + "torrente",
1488 + "tovaglia",
1489 + "traffico",
1490 + "tragitto",
1491 + "training",
1492 + "tramonto",
1493 + "transito",
1494 + "trapezio",
1495 + "trasloco",
1496 + "trattore",
1497 + "trazione",
1498 + "treccia",
1499 + "tregua",
1500 + "treno",
1501 + "triciclo",
1502 + "tridente",
1503 + "trilogia",
1504 + "tromba",
1505 + "troncare",
1506 + "trota",
1507 + "trovare",
1508 + "trucco",
1509 + "tubo",
1510 + "tulipano",
1511 + "tumulto",
1512 + "tunisia",
1513 + "tuono",
1514 + "turista",
1515 + "tuta",
1516 + "tutelare",
1517 + "tutore",
1518 + "ubriaco",
1519 + "uccello",
1520 + "udienza",
1521 + "udito",
1522 + "uffa",
1523 + "umanoide",
1524 + "umore",
1525 + "unghia",
1526 + "unguento",
1527 + "unicorno",
1528 + "unione",
1529 + "universo",
1530 + "uomo",
1531 + "uragano",
1532 + "uranio",
1533 + "urlare",
1534 + "uscire",
1535 + "utente",
1536 + "utilizzo",
1537 + "vacanza",
1538 + "vacca",
1539 + "vaglio",
1540 + "vagonata",
1541 + "valle",
1542 + "valore",
1543 + "valutare",
1544 + "valvola",
1545 + "vampiro",
1546 + "vaniglia",
1547 + "vanto",
1548 + "vapore",
1549 + "variante",
1550 + "vasca",
1551 + "vaselina",
1552 + "vassoio",
1553 + "vedere",
1554 + "vegetale",
1555 + "veglia",
1556 + "veicolo",
1557 + "vela",
1558 + "veleno",
1559 + "velivolo",
1560 + "velluto",
1561 + "vendere",
1562 + "venerare",
1563 + "venire",
1564 + "vento",
1565 + "veranda",
1566 + "verbo",
1567 + "verdura",
1568 + "vergine",
1569 + "verifica",
1570 + "vernice",
1571 + "vero",
1572 + "verruca",
1573 + "versare",
1574 + "vertebra",
1575 + "vescica",
1576 + "vespaio",
1577 + "vestito",
1578 + "vesuvio",
1579 + "veterano",
1580 + "vetro",
1581 + "vetta",
1582 + "viadotto",
1583 + "viaggio",
1584 + "vibrare",
1585 + "vicenda",
1586 + "vichingo",
1587 + "vietare",
1588 + "vigilare",
1589 + "vigneto",
1590 + "villa",
1591 + "vincere",
1592 + "violino",
1593 + "vipera",
1594 + "virgola",
1595 + "virtuoso",
1596 + "visita",
1597 + "vita",
1598 + "vitello",
1599 + "vittima",
1600 + "vivavoce",
1601 + "vivere",
1602 + "viziato",
1603 + "voglia",
1604 + "volare",
1605 + "volpe",
1606 + "volto",
1607 + "volume",
1608 + "vongole",
1609 + "voragine",
1610 + "vortice",
1611 + "votare",
1612 + "vulcano",
1613 + "vuotare",
1614 + "zabaione",
1615 + "zaffiro",
1616 + "zainetto",
1617 + "zampa",
1618 + "zanzara",
1619 + "zattera",
1620 + "zavorra",
1621 + "zenzero",
1622 + "zero",
1623 + "zingaro",
1624 + "zittire",
1625 + "zoccolo",
1626 + "zolfo",
1627 + "zombie",
1628 + "zucchero"
1629 + ];
1630 +}
\ No newline at end of file
cw_haven/lib/mnemonics/japanese.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class JapaneseMnemonics {
2 + static const words = [
3 + "あいこくしん",
4 + "あいさつ",
5 + "あいだ",
6 + "あおぞら",
7 + "あかちゃん",
8 + "あきる",
9 + "あけがた",
10 + "あける",
11 + "あこがれる",
12 + "あさい",
13 + "あさひ",
14 + "あしあと",
15 + "あじわう",
16 + "あずかる",
17 + "あずき",
18 + "あそぶ",
19 + "あたえる",
20 + "あたためる",
21 + "あたりまえ",
22 + "あたる",
23 + "あつい",
24 + "あつかう",
25 + "あっしゅく",
26 + "あつまり",
27 + "あつめる",
28 + "あてな",
29 + "あてはまる",
30 + "あひる",
31 + "あぶら",
32 + "あぶる",
33 + "あふれる",
34 + "あまい",
35 + "あまど",
36 + "あまやかす",
37 + "あまり",
38 + "あみもの",
39 + "あめりか",
40 + "あやまる",
41 + "あゆむ",
42 + "あらいぐま",
43 + "あらし",
44 + "あらすじ",
45 + "あらためる",
46 + "あらゆる",
47 + "あらわす",
48 + "ありがとう",
49 + "あわせる",
50 + "あわてる",
51 + "あんい",
52 + "あんがい",
53 + "あんこ",
54 + "あんぜん",
55 + "あんてい",
56 + "あんない",
57 + "あんまり",
58 + "いいだす",
59 + "いおん",
60 + "いがい",
61 + "いがく",
62 + "いきおい",
63 + "いきなり",
64 + "いきもの",
65 + "いきる",
66 + "いくじ",
67 + "いくぶん",
68 + "いけばな",
69 + "いけん",
70 + "いこう",
71 + "いこく",
72 + "いこつ",
73 + "いさましい",
74 + "いさん",
75 + "いしき",
76 + "いじゅう",
77 + "いじょう",
78 + "いじわる",
79 + "いずみ",
80 + "いずれ",
81 + "いせい",
82 + "いせえび",
83 + "いせかい",
84 + "いせき",
85 + "いぜん",
86 + "いそうろう",
87 + "いそがしい",
88 + "いだい",
89 + "いだく",
90 + "いたずら",
91 + "いたみ",
92 + "いたりあ",
93 + "いちおう",
94 + "いちじ",
95 + "いちど",
96 + "いちば",
97 + "いちぶ",
98 + "いちりゅう",
99 + "いつか",
100 + "いっしゅん",
101 + "いっせい",
102 + "いっそう",
103 + "いったん",
104 + "いっち",
105 + "いってい",
106 + "いっぽう",
107 + "いてざ",
108 + "いてん",
109 + "いどう",
110 + "いとこ",
111 + "いない",
112 + "いなか",
113 + "いねむり",
114 + "いのち",
115 + "いのる",
116 + "いはつ",
117 + "いばる",
118 + "いはん",
119 + "いびき",
120 + "いひん",
121 + "いふく",
122 + "いへん",
123 + "いほう",
124 + "いみん",
125 + "いもうと",
126 + "いもたれ",
127 + "いもり",
128 + "いやがる",
129 + "いやす",
130 + "いよかん",
131 + "いよく",
132 + "いらい",
133 + "いらすと",
134 + "いりぐち",
135 + "いりょう",
136 + "いれい",
137 + "いれもの",
138 + "いれる",
139 + "いろえんぴつ",
140 + "いわい",
141 + "いわう",
142 + "いわかん",
143 + "いわば",
144 + "いわゆる",
145 + "いんげんまめ",
146 + "いんさつ",
147 + "いんしょう",
148 + "いんよう",
149 + "うえき",
150 + "うえる",
151 + "うおざ",
152 + "うがい",
153 + "うかぶ",
154 + "うかべる",
155 + "うきわ",
156 + "うくらいな",
157 + "うくれれ",
158 + "うけたまわる",
159 + "うけつけ",
160 + "うけとる",
161 + "うけもつ",
162 + "うける",
163 + "うごかす",
164 + "うごく",
165 + "うこん",
166 + "うさぎ",
167 + "うしなう",
168 + "うしろがみ",
169 + "うすい",
170 + "うすぎ",
171 + "うすぐらい",
172 + "うすめる",
173 + "うせつ",
174 + "うちあわせ",
175 + "うちがわ",
176 + "うちき",
177 + "うちゅう",
178 + "うっかり",
179 + "うつくしい",
180 + "うったえる",
181 + "うつる",
182 + "うどん",
183 + "うなぎ",
184 + "うなじ",
185 + "うなずく",
186 + "うなる",
187 + "うねる",
188 + "うのう",
189 + "うぶげ",
190 + "うぶごえ",
191 + "うまれる",
192 + "うめる",
193 + "うもう",
194 + "うやまう",
195 + "うよく",
196 + "うらがえす",
197 + "うらぐち",
198 + "うらない",
199 + "うりあげ",
200 + "うりきれ",
201 + "うるさい",
202 + "うれしい",
203 + "うれゆき",
204 + "うれる",
205 + "うろこ",
206 + "うわき",
207 + "うわさ",
208 + "うんこう",
209 + "うんちん",
210 + "うんてん",
211 + "うんどう",
212 + "えいえん",
213 + "えいが",
214 + "えいきょう",
215 + "えいご",
216 + "えいせい",
217 + "えいぶん",
218 + "えいよう",
219 + "えいわ",
220 + "えおり",
221 + "えがお",
222 + "えがく",
223 + "えきたい",
224 + "えくせる",
225 + "えしゃく",
226 + "えすて",
227 + "えつらん",
228 + "えのぐ",
229 + "えほうまき",
230 + "えほん",
231 + "えまき",
232 + "えもじ",
233 + "えもの",
234 + "えらい",
235 + "えらぶ",
236 + "えりあ",
237 + "えんえん",
238 + "えんかい",
239 + "えんぎ",
240 + "えんげき",
241 + "えんしゅう",
242 + "えんぜつ",
243 + "えんそく",
244 + "えんちょう",
245 + "えんとつ",
246 + "おいかける",
247 + "おいこす",
248 + "おいしい",
249 + "おいつく",
250 + "おうえん",
251 + "おうさま",
252 + "おうじ",
253 + "おうせつ",
254 + "おうたい",
255 + "おうふく",
256 + "おうべい",
257 + "おうよう",
258 + "おえる",
259 + "おおい",
260 + "おおう",
261 + "おおどおり",
262 + "おおや",
263 + "おおよそ",
264 + "おかえり",
265 + "おかず",
266 + "おがむ",
267 + "おかわり",
268 + "おぎなう",
269 + "おきる",
270 + "おくさま",
271 + "おくじょう",
272 + "おくりがな",
273 + "おくる",
274 + "おくれる",
275 + "おこす",
276 + "おこなう",
277 + "おこる",
278 + "おさえる",
279 + "おさない",
280 + "おさめる",
281 + "おしいれ",
282 + "おしえる",
283 + "おじぎ",
284 + "おじさん",
285 + "おしゃれ",
286 + "おそらく",
287 + "おそわる",
288 + "おたがい",
289 + "おたく",
290 + "おだやか",
291 + "おちつく",
292 + "おっと",
293 + "おつり",
294 + "おでかけ",
295 + "おとしもの",
296 + "おとなしい",
297 + "おどり",
298 + "おどろかす",
299 + "おばさん",
300 + "おまいり",
301 + "おめでとう",
302 + "おもいで",
303 + "おもう",
304 + "おもたい",
305 + "おもちゃ",
306 + "おやつ",
307 + "おやゆび",
308 + "およぼす",
309 + "おらんだ",
310 + "おろす",
311 + "おんがく",
312 + "おんけい",
313 + "おんしゃ",
314 + "おんせん",
315 + "おんだん",
316 + "おんちゅう",
317 + "おんどけい",
318 + "かあつ",
319 + "かいが",
320 + "がいき",
321 + "がいけん",
322 + "がいこう",
323 + "かいさつ",
324 + "かいしゃ",
325 + "かいすいよく",
326 + "かいぜん",
327 + "かいぞうど",
328 + "かいつう",
329 + "かいてん",
330 + "かいとう",
331 + "かいふく",
332 + "がいへき",
333 + "かいほう",
334 + "かいよう",
335 + "がいらい",
336 + "かいわ",
337 + "かえる",
338 + "かおり",
339 + "かかえる",
340 + "かがく",
341 + "かがし",
342 + "かがみ",
343 + "かくご",
344 + "かくとく",
345 + "かざる",
346 + "がぞう",
347 + "かたい",
348 + "かたち",
349 + "がちょう",
350 + "がっきゅう",
351 + "がっこう",
352 + "がっさん",
353 + "がっしょう",
354 + "かなざわし",
355 + "かのう",
356 + "がはく",
357 + "かぶか",
358 + "かほう",
359 + "かほご",
360 + "かまう",
361 + "かまぼこ",
362 + "かめれおん",
363 + "かゆい",
364 + "かようび",
365 + "からい",
366 + "かるい",
367 + "かろう",
368 + "かわく",
369 + "かわら",
370 + "がんか",
371 + "かんけい",
372 + "かんこう",
373 + "かんしゃ",
374 + "かんそう",
375 + "かんたん",
376 + "かんち",
377 + "がんばる",
378 + "きあい",
379 + "きあつ",
380 + "きいろ",
381 + "ぎいん",
382 + "きうい",
383 + "きうん",
384 + "きえる",
385 + "きおう",
386 + "きおく",
387 + "きおち",
388 + "きおん",
389 + "きかい",
390 + "きかく",
391 + "きかんしゃ",
392 + "ききて",
393 + "きくばり",
394 + "きくらげ",
395 + "きけんせい",
396 + "きこう",
397 + "きこえる",
398 + "きこく",
399 + "きさい",
400 + "きさく",
401 + "きさま",
402 + "きさらぎ",
403 + "ぎじかがく",
404 + "ぎしき",
405 + "ぎじたいけん",
406 + "ぎじにってい",
407 + "ぎじゅつしゃ",
408 + "きすう",
409 + "きせい",
410 + "きせき",
411 + "きせつ",
412 + "きそう",
413 + "きぞく",
414 + "きぞん",
415 + "きたえる",
416 + "きちょう",
417 + "きつえん",
418 + "ぎっちり",
419 + "きつつき",
420 + "きつね",
421 + "きてい",
422 + "きどう",
423 + "きどく",
424 + "きない",
425 + "きなが",
426 + "きなこ",
427 + "きぬごし",
428 + "きねん",
429 + "きのう",
430 + "きのした",
431 + "きはく",
432 + "きびしい",
433 + "きひん",
434 + "きふく",
435 + "きぶん",
436 + "きぼう",
437 + "きほん",
438 + "きまる",
439 + "きみつ",
440 + "きむずかしい",
441 + "きめる",
442 + "きもだめし",
443 + "きもち",
444 + "きもの",
445 + "きゃく",
446 + "きやく",
447 + "ぎゅうにく",
448 + "きよう",
449 + "きょうりゅう",
450 + "きらい",
451 + "きらく",
452 + "きりん",
453 + "きれい",
454 + "きれつ",
455 + "きろく",
456 + "ぎろん",
457 + "きわめる",
458 + "ぎんいろ",
459 + "きんかくじ",
460 + "きんじょ",
461 + "きんようび",
462 + "ぐあい",
463 + "くいず",
464 + "くうかん",
465 + "くうき",
466 + "くうぐん",
467 + "くうこう",
468 + "ぐうせい",
469 + "くうそう",
470 + "ぐうたら",
471 + "くうふく",
472 + "くうぼ",
473 + "くかん",
474 + "くきょう",
475 + "くげん",
476 + "ぐこう",
477 + "くさい",
478 + "くさき",
479 + "くさばな",
480 + "くさる",
481 + "くしゃみ",
482 + "くしょう",
483 + "くすのき",
484 + "くすりゆび",
485 + "くせげ",
486 + "くせん",
487 + "ぐたいてき",
488 + "くださる",
489 + "くたびれる",
490 + "くちこみ",
491 + "くちさき",
492 + "くつした",
493 + "ぐっすり",
494 + "くつろぐ",
495 + "くとうてん",
496 + "くどく",
497 + "くなん",
498 + "くねくね",
499 + "くのう",
500 + "くふう",
501 + "くみあわせ",
502 + "くみたてる",
503 + "くめる",
504 + "くやくしょ",
505 + "くらす",
506 + "くらべる",
507 + "くるま",
508 + "くれる",
509 + "くろう",
510 + "くわしい",
511 + "ぐんかん",
512 + "ぐんしょく",
513 + "ぐんたい",
514 + "ぐんて",
515 + "けあな",
516 + "けいかく",
517 + "けいけん",
518 + "けいこ",
519 + "けいさつ",
520 + "げいじゅつ",
521 + "けいたい",
522 + "げいのうじん",
523 + "けいれき",
524 + "けいろ",
525 + "けおとす",
526 + "けおりもの",
527 + "げきか",
528 + "げきげん",
529 + "げきだん",
530 + "げきちん",
531 + "げきとつ",
532 + "げきは",
533 + "げきやく",
534 + "げこう",
535 + "げこくじょう",
536 + "げざい",
537 + "けさき",
538 + "げざん",
539 + "けしき",
540 + "けしごむ",
541 + "けしょう",
542 + "げすと",
543 + "けたば",
544 + "けちゃっぷ",
545 + "けちらす",
546 + "けつあつ",
547 + "けつい",
548 + "けつえき",
549 + "けっこん",
550 + "けつじょ",
551 + "けっせき",
552 + "けってい",
553 + "けつまつ",
554 + "げつようび",
555 + "げつれい",
556 + "けつろん",
557 + "げどく",
558 + "けとばす",
559 + "けとる",
560 + "けなげ",
561 + "けなす",
562 + "けなみ",
563 + "けぬき",
564 + "げねつ",
565 + "けねん",
566 + "けはい",
567 + "げひん",
568 + "けぶかい",
569 + "げぼく",
570 + "けまり",
571 + "けみかる",
572 + "けむし",
573 + "けむり",
574 + "けもの",
575 + "けらい",
576 + "けろけろ",
577 + "けわしい",
578 + "けんい",
579 + "けんえつ",
580 + "けんお",
581 + "けんか",
582 + "げんき",
583 + "けんげん",
584 + "けんこう",
585 + "けんさく",
586 + "けんしゅう",
587 + "けんすう",
588 + "げんそう",
589 + "けんちく",
590 + "けんてい",
591 + "けんとう",
592 + "けんない",
593 + "けんにん",
594 + "げんぶつ",
595 + "けんま",
596 + "けんみん",
597 + "けんめい",
598 + "けんらん",
599 + "けんり",
600 + "こあくま",
601 + "こいぬ",
602 + "こいびと",
603 + "ごうい",
604 + "こうえん",
605 + "こうおん",
606 + "こうかん",
607 + "ごうきゅう",
608 + "ごうけい",
609 + "こうこう",
610 + "こうさい",
611 + "こうじ",
612 + "こうすい",
613 + "ごうせい",
614 + "こうそく",
615 + "こうたい",
616 + "こうちゃ",
617 + "こうつう",
618 + "こうてい",
619 + "こうどう",
620 + "こうない",
621 + "こうはい",
622 + "ごうほう",
623 + "ごうまん",
624 + "こうもく",
625 + "こうりつ",
626 + "こえる",
627 + "こおり",
628 + "ごかい",
629 + "ごがつ",
630 + "ごかん",
631 + "こくご",
632 + "こくさい",
633 + "こくとう",
634 + "こくない",
635 + "こくはく",
636 + "こぐま",
637 + "こけい",
638 + "こける",
639 + "ここのか",
640 + "こころ",
641 + "こさめ",
642 + "こしつ",
643 + "こすう",
644 + "こせい",
645 + "こせき",
646 + "こぜん",
647 + "こそだて",
648 + "こたい",
649 + "こたえる",
650 + "こたつ",
651 + "こちょう",
652 + "こっか",
653 + "こつこつ",
654 + "こつばん",
655 + "こつぶ",
656 + "こてい",
657 + "こてん",
658 + "ことがら",
659 + "ことし",
660 + "ことば",
661 + "ことり",
662 + "こなごな",
663 + "こねこね",
664 + "このまま",
665 + "このみ",
666 + "このよ",
667 + "ごはん",
668 + "こひつじ",
669 + "こふう",
670 + "こふん",
671 + "こぼれる",
672 + "ごまあぶら",
673 + "こまかい",
674 + "ごますり",
675 + "こまつな",
676 + "こまる",
677 + "こむぎこ",
678 + "こもじ",
679 + "こもち",
680 + "こもの",
681 + "こもん",
682 + "こやく",
683 + "こやま",
684 + "こゆう",
685 + "こゆび",
686 + "こよい",
687 + "こよう",
688 + "こりる",
689 + "これくしょん",
690 + "ころっけ",
691 + "こわもて",
692 + "こわれる",
693 + "こんいん",
694 + "こんかい",
695 + "こんき",
696 + "こんしゅう",
697 + "こんすい",
698 + "こんだて",
699 + "こんとん",
700 + "こんなん",
701 + "こんびに",
702 + "こんぽん",
703 + "こんまけ",
704 + "こんや",
705 + "こんれい",
706 + "こんわく",
707 + "ざいえき",
708 + "さいかい",
709 + "さいきん",
710 + "ざいげん",
711 + "ざいこ",
712 + "さいしょ",
713 + "さいせい",
714 + "ざいたく",
715 + "ざいちゅう",
716 + "さいてき",
717 + "ざいりょう",
718 + "さうな",
719 + "さかいし",
720 + "さがす",
721 + "さかな",
722 + "さかみち",
723 + "さがる",
724 + "さぎょう",
725 + "さくし",
726 + "さくひん",
727 + "さくら",
728 + "さこく",
729 + "さこつ",
730 + "さずかる",
731 + "ざせき",
732 + "さたん",
733 + "さつえい",
734 + "ざつおん",
735 + "ざっか",
736 + "ざつがく",
737 + "さっきょく",
738 + "ざっし",
739 + "さつじん",
740 + "ざっそう",
741 + "さつたば",
742 + "さつまいも",
743 + "さてい",
744 + "さといも",
745 + "さとう",
746 + "さとおや",
747 + "さとし",
748 + "さとる",
749 + "さのう",
750 + "さばく",
751 + "さびしい",
752 + "さべつ",
753 + "さほう",
754 + "さほど",
755 + "さます",
756 + "さみしい",
757 + "さみだれ",
758 + "さむけ",
759 + "さめる",
760 + "さやえんどう",
761 + "さゆう",
762 + "さよう",
763 + "さよく",
764 + "さらだ",
765 + "ざるそば",
766 + "さわやか",
767 + "さわる",
768 + "さんいん",
769 + "さんか",
770 + "さんきゃく",
771 + "さんこう",
772 + "さんさい",
773 + "ざんしょ",
774 + "さんすう",
775 + "さんせい",
776 + "さんそ",
777 + "さんち",
778 + "さんま",
779 + "さんみ",
780 + "さんらん",
781 + "しあい",
782 + "しあげ",
783 + "しあさって",
784 + "しあわせ",
785 + "しいく",
786 + "しいん",
787 + "しうち",
788 + "しえい",
789 + "しおけ",
790 + "しかい",
791 + "しかく",
792 + "じかん",
793 + "しごと",
794 + "しすう",
795 + "じだい",
796 + "したうけ",
797 + "したぎ",
798 + "したて",
799 + "したみ",
800 + "しちょう",
801 + "しちりん",
802 + "しっかり",
803 + "しつじ",
804 + "しつもん",
805 + "してい",
806 + "してき",
807 + "してつ",
808 + "じてん",
809 + "じどう",
810 + "しなぎれ",
811 + "しなもの",
812 + "しなん",
813 + "しねま",
814 + "しねん",
815 + "しのぐ",
816 + "しのぶ",
817 + "しはい",
818 + "しばかり",
819 + "しはつ",
820 + "しはらい",
821 + "しはん",
822 + "しひょう",
823 + "しふく",
824 + "じぶん",
825 + "しへい",
826 + "しほう",
827 + "しほん",
828 + "しまう",
829 + "しまる",
830 + "しみん",
831 + "しむける",
832 + "じむしょ",
833 + "しめい",
834 + "しめる",
835 + "しもん",
836 + "しゃいん",
837 + "しゃうん",
838 + "しゃおん",
839 + "じゃがいも",
840 + "しやくしょ",
841 + "しゃくほう",
842 + "しゃけん",
843 + "しゃこ",
844 + "しゃざい",
845 + "しゃしん",
846 + "しゃせん",
847 + "しゃそう",
848 + "しゃたい",
849 + "しゃちょう",
850 + "しゃっきん",
851 + "じゃま",
852 + "しゃりん",
853 + "しゃれい",
854 + "じゆう",
855 + "じゅうしょ",
856 + "しゅくはく",
857 + "じゅしん",
858 + "しゅっせき",
859 + "しゅみ",
860 + "しゅらば",
861 + "じゅんばん",
862 + "しょうかい",
863 + "しょくたく",
864 + "しょっけん",
865 + "しょどう",
866 + "しょもつ",
867 + "しらせる",
868 + "しらべる",
869 + "しんか",
870 + "しんこう",
871 + "じんじゃ",
872 + "しんせいじ",
873 + "しんちく",
874 + "しんりん",
875 + "すあげ",
876 + "すあし",
877 + "すあな",
878 + "ずあん",
879 + "すいえい",
880 + "すいか",
881 + "すいとう",
882 + "ずいぶん",
883 + "すいようび",
884 + "すうがく",
885 + "すうじつ",
886 + "すうせん",
887 + "すおどり",
888 + "すきま",
889 + "すくう",
890 + "すくない",
891 + "すける",
892 + "すごい",
893 + "すこし",
894 + "ずさん",
895 + "すずしい",
896 + "すすむ",
897 + "すすめる",
898 + "すっかり",
899 + "ずっしり",
900 + "ずっと",
901 + "すてき",
902 + "すてる",
903 + "すねる",
904 + "すのこ",
905 + "すはだ",
906 + "すばらしい",
907 + "ずひょう",
908 + "ずぶぬれ",
909 + "すぶり",
910 + "すふれ",
911 + "すべて",
912 + "すべる",
913 + "ずほう",
914 + "すぼん",
915 + "すまい",
916 + "すめし",
917 + "すもう",
918 + "すやき",
919 + "すらすら",
920 + "するめ",
921 + "すれちがう",
922 + "すろっと",
923 + "すわる",
924 + "すんぜん",
925 + "すんぽう",
926 + "せあぶら",
927 + "せいかつ",
928 + "せいげん",
929 + "せいじ",
930 + "せいよう",
931 + "せおう",
932 + "せかいかん",
933 + "せきにん",
934 + "せきむ",
935 + "せきゆ",
936 + "せきらんうん",
937 + "せけん",
938 + "せこう",
939 + "せすじ",
940 + "せたい",
941 + "せたけ",
942 + "せっかく",
943 + "せっきゃく",
944 + "ぜっく",
945 + "せっけん",
946 + "せっこつ",
947 + "せっさたくま",
948 + "せつぞく",
949 + "せつだん",
950 + "せつでん",
951 + "せっぱん",
952 + "せつび",
953 + "せつぶん",
954 + "せつめい",
955 + "せつりつ",
956 + "せなか",
957 + "せのび",
958 + "せはば",
959 + "せびろ",
960 + "せぼね",
961 + "せまい",
962 + "せまる",
963 + "せめる",
964 + "せもたれ",
965 + "せりふ",
966 + "ぜんあく",
967 + "せんい",
968 + "せんえい",
969 + "せんか",
970 + "せんきょ",
971 + "せんく",
972 + "せんげん",
973 + "ぜんご",
974 + "せんさい",
975 + "せんしゅ",
976 + "せんすい",
977 + "せんせい",
978 + "せんぞ",
979 + "せんたく",
980 + "せんちょう",
981 + "せんてい",
982 + "せんとう",
983 + "せんぬき",
984 + "せんねん",
985 + "せんぱい",
986 + "ぜんぶ",
987 + "ぜんぽう",
988 + "せんむ",
989 + "せんめんじょ",
990 + "せんもん",
991 + "せんやく",
992 + "せんゆう",
993 + "せんよう",
994 + "ぜんら",
995 + "ぜんりゃく",
996 + "せんれい",
997 + "せんろ",
998 + "そあく",
999 + "そいとげる",
1000 + "そいね",
1001 + "そうがんきょう",
1002 + "そうき",
1003 + "そうご",
1004 + "そうしん",
1005 + "そうだん",
1006 + "そうなん",
1007 + "そうび",
1008 + "そうめん",
1009 + "そうり",
1010 + "そえもの",
1011 + "そえん",
1012 + "そがい",
1013 + "そげき",
1014 + "そこう",
1015 + "そこそこ",
1016 + "そざい",
1017 + "そしな",
1018 + "そせい",
1019 + "そせん",
1020 + "そそぐ",
1021 + "そだてる",
1022 + "そつう",
1023 + "そつえん",
1024 + "そっかん",
1025 + "そつぎょう",
1026 + "そっけつ",
1027 + "そっこう",
1028 + "そっせん",
1029 + "そっと",
1030 + "そとがわ",
1031 + "そとづら",
1032 + "そなえる",
1033 + "そなた",
1034 + "そふぼ",
1035 + "そぼく",
1036 + "そぼろ",
1037 + "そまつ",
1038 + "そまる",
1039 + "そむく",
1040 + "そむりえ",
1041 + "そめる",
1042 + "そもそも",
1043 + "そよかぜ",
1044 + "そらまめ",
1045 + "そろう",
1046 + "そんかい",
1047 + "そんけい",
1048 + "そんざい",
1049 + "そんしつ",
1050 + "そんぞく",
1051 + "そんちょう",
1052 + "ぞんび",
1053 + "ぞんぶん",
1054 + "そんみん",
1055 + "たあい",
1056 + "たいいん",
1057 + "たいうん",
1058 + "たいえき",
1059 + "たいおう",
1060 + "だいがく",
1061 + "たいき",
1062 + "たいぐう",
1063 + "たいけん",
1064 + "たいこ",
1065 + "たいざい",
1066 + "だいじょうぶ",
1067 + "だいすき",
1068 + "たいせつ",
1069 + "たいそう",
1070 + "だいたい",
1071 + "たいちょう",
1072 + "たいてい",
1073 + "だいどころ",
1074 + "たいない",
1075 + "たいねつ",
1076 + "たいのう",
1077 + "たいはん",
1078 + "だいひょう",
1079 + "たいふう",
1080 + "たいへん",
1081 + "たいほ",
1082 + "たいまつばな",
1083 + "たいみんぐ",
1084 + "たいむ",
1085 + "たいめん",
1086 + "たいやき",
1087 + "たいよう",
1088 + "たいら",
1089 + "たいりょく",
1090 + "たいる",
1091 + "たいわん",
1092 + "たうえ",
1093 + "たえる",
1094 + "たおす",
1095 + "たおる",
1096 + "たおれる",
1097 + "たかい",
1098 + "たかね",
1099 + "たきび",
1100 + "たくさん",
1101 + "たこく",
1102 + "たこやき",
1103 + "たさい",
1104 + "たしざん",
1105 + "だじゃれ",
1106 + "たすける",
1107 + "たずさわる",
1108 + "たそがれ",
1109 + "たたかう",
1110 + "たたく",
1111 + "ただしい",
1112 + "たたみ",
1113 + "たちばな",
1114 + "だっかい",
1115 + "だっきゃく",
1116 + "だっこ",
1117 + "だっしゅつ",
1118 + "だったい",
1119 + "たてる",
1120 + "たとえる",
1121 + "たなばた",
1122 + "たにん",
1123 + "たぬき",
1124 + "たのしみ",
1125 + "たはつ",
1126 + "たぶん",
1127 + "たべる",
1128 + "たぼう",
1129 + "たまご",
1130 + "たまる",
1131 + "だむる",
1132 + "ためいき",
1133 + "ためす",
1134 + "ためる",
1135 + "たもつ",
1136 + "たやすい",
1137 + "たよる",
1138 + "たらす",
1139 + "たりきほんがん",
1140 + "たりょう",
1141 + "たりる",
1142 + "たると",
1143 + "たれる",
1144 + "たれんと",
1145 + "たろっと",
1146 + "たわむれる",
1147 + "だんあつ",
1148 + "たんい",
1149 + "たんおん",
1150 + "たんか",
1151 + "たんき",
1152 + "たんけん",
1153 + "たんご",
1154 + "たんさん",
1155 + "たんじょうび",
1156 + "だんせい",
1157 + "たんそく",
1158 + "たんたい",
1159 + "だんち",
1160 + "たんてい",
1161 + "たんとう",
1162 + "だんな",
1163 + "たんにん",
1164 + "だんねつ",
1165 + "たんのう",
1166 + "たんぴん",
1167 + "だんぼう",
1168 + "たんまつ",
1169 + "たんめい",
1170 + "だんれつ",
1171 + "だんろ",
1172 + "だんわ",
1173 + "ちあい",
1174 + "ちあん",
1175 + "ちいき",
1176 + "ちいさい",
1177 + "ちえん",
1178 + "ちかい",
1179 + "ちから",
1180 + "ちきゅう",
1181 + "ちきん",
1182 + "ちけいず",
1183 + "ちけん",
1184 + "ちこく",
1185 + "ちさい",
1186 + "ちしき",
1187 + "ちしりょう",
1188 + "ちせい",
1189 + "ちそう",
1190 + "ちたい",
1191 + "ちたん",
1192 + "ちちおや",
1193 + "ちつじょ",
1194 + "ちてき",
1195 + "ちてん",
1196 + "ちぬき",
1197 + "ちぬり",
1198 + "ちのう",
1199 + "ちひょう",
1200 + "ちへいせん",
1201 + "ちほう",
1202 + "ちまた",
1203 + "ちみつ",
1204 + "ちみどろ",
1205 + "ちめいど",
1206 + "ちゃんこなべ",
1207 + "ちゅうい",
1208 + "ちゆりょく",
1209 + "ちょうし",
1210 + "ちょさくけん",
1211 + "ちらし",
1212 + "ちらみ",
1213 + "ちりがみ",
1214 + "ちりょう",
1215 + "ちるど",
1216 + "ちわわ",
1217 + "ちんたい",
1218 + "ちんもく",
1219 + "ついか",
1220 + "ついたち",
1221 + "つうか",
1222 + "つうじょう",
1223 + "つうはん",
1224 + "つうわ",
1225 + "つかう",
1226 + "つかれる",
1227 + "つくね",
1228 + "つくる",
1229 + "つけね",
1230 + "つける",
1231 + "つごう",
1232 + "つたえる",
1233 + "つづく",
1234 + "つつじ",
1235 + "つつむ",
1236 + "つとめる",
1237 + "つながる",
1238 + "つなみ",
1239 + "つねづね",
1240 + "つのる",
1241 + "つぶす",
1242 + "つまらない",
1243 + "つまる",
1244 + "つみき",
1245 + "つめたい",
1246 + "つもり",
1247 + "つもる",
1248 + "つよい",
1249 + "つるぼ",
1250 + "つるみく",
1251 + "つわもの",
1252 + "つわり",
1253 + "てあし",
1254 + "てあて",
1255 + "てあみ",
1256 + "ていおん",
1257 + "ていか",
1258 + "ていき",
1259 + "ていけい",
1260 + "ていこく",
1261 + "ていさつ",
1262 + "ていし",
1263 + "ていせい",
1264 + "ていたい",
1265 + "ていど",
1266 + "ていねい",
1267 + "ていひょう",
1268 + "ていへん",
1269 + "ていぼう",
1270 + "てうち",
1271 + "ておくれ",
1272 + "てきとう",
1273 + "てくび",
1274 + "でこぼこ",
1275 + "てさぎょう",
1276 + "てさげ",
1277 + "てすり",
1278 + "てそう",
1279 + "てちがい",
1280 + "てちょう",
1281 + "てつがく",
1282 + "てつづき",
1283 + "でっぱ",
1284 + "てつぼう",
1285 + "てつや",
1286 + "でぬかえ",
1287 + "てぬき",
1288 + "てぬぐい",
1289 + "てのひら",
1290 + "てはい",
1291 + "てぶくろ",
1292 + "てふだ",
1293 + "てほどき",
1294 + "てほん",
1295 + "てまえ",
1296 + "てまきずし",
1297 + "てみじか",
1298 + "てみやげ",
1299 + "てらす",
1300 + "てれび",
1301 + "てわけ",
1302 + "てわたし",
1303 + "でんあつ",
1304 + "てんいん",
1305 + "てんかい",
1306 + "てんき",
1307 + "てんぐ",
1308 + "てんけん",
1309 + "てんごく",
1310 + "てんさい",
1311 + "てんし",
1312 + "てんすう",
1313 + "でんち",
1314 + "てんてき",
1315 + "てんとう",
1316 + "てんない",
1317 + "てんぷら",
1318 + "てんぼうだい",
1319 + "てんめつ",
1320 + "てんらんかい",
1321 + "でんりょく",
1322 + "でんわ",
1323 + "どあい",
1324 + "といれ",
1325 + "どうかん",
1326 + "とうきゅう",
1327 + "どうぐ",
1328 + "とうし",
1329 + "とうむぎ",
1330 + "とおい",
1331 + "とおか",
1332 + "とおく",
1333 + "とおす",
1334 + "とおる",
1335 + "とかい",
1336 + "とかす",
1337 + "ときおり",
1338 + "ときどき",
1339 + "とくい",
1340 + "とくしゅう",
1341 + "とくてん",
1342 + "とくに",
1343 + "とくべつ",
1344 + "とけい",
1345 + "とける",
1346 + "とこや",
1347 + "とさか",
1348 + "としょかん",
1349 + "とそう",
1350 + "とたん",
1351 + "とちゅう",
1352 + "とっきゅう",
1353 + "とっくん",
1354 + "とつぜん",
1355 + "とつにゅう",
1356 + "とどける",
1357 + "ととのえる",
1358 + "とない",
1359 + "となえる",
1360 + "となり",
1361 + "とのさま",
1362 + "とばす",
1363 + "どぶがわ",
1364 + "とほう",
1365 + "とまる",
1366 + "とめる",
1367 + "ともだち",
1368 + "ともる",
1369 + "どようび",
1370 + "とらえる",
1371 + "とんかつ",
1372 + "どんぶり",
1373 + "ないかく",
1374 + "ないこう",
1375 + "ないしょ",
1376 + "ないす",
1377 + "ないせん",
1378 + "ないそう",
1379 + "なおす",
1380 + "ながい",
1381 + "なくす",
1382 + "なげる",
1383 + "なこうど",
1384 + "なさけ",
1385 + "なたでここ",
1386 + "なっとう",
1387 + "なつやすみ",
1388 + "ななおし",
1389 + "なにごと",
1390 + "なにもの",
1391 + "なにわ",
1392 + "なのか",
1393 + "なふだ",
1394 + "なまいき",
1395 + "なまえ",
1396 + "なまみ",
1397 + "なみだ",
1398 + "なめらか",
1399 + "なめる",
1400 + "なやむ",
1401 + "ならう",
1402 + "ならび",
1403 + "ならぶ",
1404 + "なれる",
1405 + "なわとび",
1406 + "なわばり",
1407 + "にあう",
1408 + "にいがた",
1409 + "にうけ",
1410 + "におい",
1411 + "にかい",
1412 + "にがて",
1413 + "にきび",
1414 + "にくしみ",
1415 + "にくまん",
1416 + "にげる",
1417 + "にさんかたんそ",
1418 + "にしき",
1419 + "にせもの",
1420 + "にちじょう",
1421 + "にちようび",
1422 + "にっか",
1423 + "にっき",
1424 + "にっけい",
1425 + "にっこう",
1426 + "にっさん",
1427 + "にっしょく",
1428 + "にっすう",
1429 + "にっせき",
1430 + "にってい",
1431 + "になう",
1432 + "にほん",
1433 + "にまめ",
1434 + "にもつ",
1435 + "にやり",
1436 + "にゅういん",
1437 + "にりんしゃ",
1438 + "にわとり",
1439 + "にんい",
1440 + "にんか",
1441 + "にんき",
1442 + "にんげん",
1443 + "にんしき",
1444 + "にんずう",
1445 + "にんそう",
1446 + "にんたい",
1447 + "にんち",
1448 + "にんてい",
1449 + "にんにく",
1450 + "にんぷ",
1451 + "にんまり",
1452 + "にんむ",
1453 + "にんめい",
1454 + "にんよう",
1455 + "ぬいくぎ",
1456 + "ぬかす",
1457 + "ぬぐいとる",
1458 + "ぬぐう",
1459 + "ぬくもり",
1460 + "ぬすむ",
1461 + "ぬまえび",
1462 + "ぬめり",
1463 + "ぬらす",
1464 + "ぬんちゃく",
1465 + "ねあげ",
1466 + "ねいき",
1467 + "ねいる",
1468 + "ねいろ",
1469 + "ねぐせ",
1470 + "ねくたい",
1471 + "ねくら",
1472 + "ねこぜ",
1473 + "ねこむ",
1474 + "ねさげ",
1475 + "ねすごす",
1476 + "ねそべる",
1477 + "ねだん",
1478 + "ねつい",
1479 + "ねっしん",
1480 + "ねつぞう",
1481 + "ねったいぎょ",
1482 + "ねぶそく",
1483 + "ねふだ",
1484 + "ねぼう",
1485 + "ねほりはほり",
1486 + "ねまき",
1487 + "ねまわし",
1488 + "ねみみ",
1489 + "ねむい",
1490 + "ねむたい",
1491 + "ねもと",
1492 + "ねらう",
1493 + "ねわざ",
1494 + "ねんいり",
1495 + "ねんおし",
1496 + "ねんかん",
1497 + "ねんきん",
1498 + "ねんぐ",
1499 + "ねんざ",
1500 + "ねんし",
1501 + "ねんちゃく",
1502 + "ねんど",
1503 + "ねんぴ",
1504 + "ねんぶつ",
1505 + "ねんまつ",
1506 + "ねんりょう",
1507 + "ねんれい",
1508 + "のいず",
1509 + "のおづま",
1510 + "のがす",
1511 + "のきなみ",
1512 + "のこぎり",
1513 + "のこす",
1514 + "のこる",
1515 + "のせる",
1516 + "のぞく",
1517 + "のぞむ",
1518 + "のたまう",
1519 + "のちほど",
1520 + "のっく",
1521 + "のばす",
1522 + "のはら",
1523 + "のべる",
1524 + "のぼる",
1525 + "のみもの",
1526 + "のやま",
1527 + "のらいぬ",
1528 + "のらねこ",
1529 + "のりもの",
1530 + "のりゆき",
1531 + "のれん",
1532 + "のんき",
1533 + "ばあい",
1534 + "はあく",
1535 + "ばあさん",
1536 + "ばいか",
1537 + "ばいく",
1538 + "はいけん",
1539 + "はいご",
1540 + "はいしん",
1541 + "はいすい",
1542 + "はいせん",
1543 + "はいそう",
1544 + "はいち",
1545 + "ばいばい",
1546 + "はいれつ",
1547 + "はえる",
1548 + "はおる",
1549 + "はかい",
1550 + "ばかり",
1551 + "はかる",
1552 + "はくしゅ",
1553 + "はけん",
1554 + "はこぶ",
1555 + "はさみ",
1556 + "はさん",
1557 + "はしご",
1558 + "ばしょ",
1559 + "はしる",
1560 + "はせる",
1561 + "ぱそこん",
1562 + "はそん",
1563 + "はたん",
1564 + "はちみつ",
1565 + "はつおん",
1566 + "はっかく",
1567 + "はづき",
1568 + "はっきり",
1569 + "はっくつ",
1570 + "はっけん",
1571 + "はっこう",
1572 + "はっさん",
1573 + "はっしん",
1574 + "はったつ",
1575 + "はっちゅう",
1576 + "はってん",
1577 + "はっぴょう",
1578 + "はっぽう",
1579 + "はなす",
1580 + "はなび",
1581 + "はにかむ",
1582 + "はぶらし",
1583 + "はみがき",
1584 + "はむかう",
1585 + "はめつ",
1586 + "はやい",
1587 + "はやし",
1588 + "はらう",
1589 + "はろうぃん",
1590 + "はわい",
1591 + "はんい",
1592 + "はんえい",
1593 + "はんおん",
1594 + "はんかく",
1595 + "はんきょう",
1596 + "ばんぐみ",
1597 + "はんこ",
1598 + "はんしゃ",
1599 + "はんすう",
1600 + "はんだん",
1601 + "ぱんち",
1602 + "ぱんつ",
1603 + "はんてい",
1604 + "はんとし",
1605 + "はんのう",
1606 + "はんぱ",
1607 + "はんぶん",
1608 + "はんぺん",
1609 + "はんぼうき",
1610 + "はんめい",
1611 + "はんらん",
1612 + "はんろん",
1613 + "ひいき",
1614 + "ひうん",
1615 + "ひえる",
1616 + "ひかく",
1617 + "ひかり",
1618 + "ひかる",
1619 + "ひかん",
1620 + "ひくい",
1621 + "ひけつ",
1622 + "ひこうき",
1623 + "ひこく",
1624 + "ひさい",
1625 + "ひさしぶり",
1626 + "ひさん",
1627 + "びじゅつかん",
1628 + "ひしょ"
1629 + ];
1630 +}
\ No newline at end of file
cw_haven/lib/mnemonics/portuguese.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class PortugueseMnemonics {
2 + static const words = [
3 + "abaular",
4 + "abdominal",
5 + "abeto",
6 + "abissinio",
7 + "abjeto",
8 + "ablucao",
9 + "abnegar",
10 + "abotoar",
11 + "abrutalhar",
12 + "absurdo",
13 + "abutre",
14 + "acautelar",
15 + "accessorios",
16 + "acetona",
17 + "achocolatado",
18 + "acirrar",
19 + "acne",
20 + "acovardar",
21 + "acrostico",
22 + "actinomicete",
23 + "acustico",
24 + "adaptavel",
25 + "adeus",
26 + "adivinho",
27 + "adjunto",
28 + "admoestar",
29 + "adnominal",
30 + "adotivo",
31 + "adquirir",
32 + "adriatico",
33 + "adsorcao",
34 + "adutora",
35 + "advogar",
36 + "aerossol",
37 + "afazeres",
38 + "afetuoso",
39 + "afixo",
40 + "afluir",
41 + "afortunar",
42 + "afrouxar",
43 + "aftosa",
44 + "afunilar",
45 + "agentes",
46 + "agito",
47 + "aglutinar",
48 + "aiatola",
49 + "aimore",
50 + "aino",
51 + "aipo",
52 + "airoso",
53 + "ajeitar",
54 + "ajoelhar",
55 + "ajudante",
56 + "ajuste",
57 + "alazao",
58 + "albumina",
59 + "alcunha",
60 + "alegria",
61 + "alexandre",
62 + "alforriar",
63 + "alguns",
64 + "alhures",
65 + "alivio",
66 + "almoxarife",
67 + "alotropico",
68 + "alpiste",
69 + "alquimista",
70 + "alsaciano",
71 + "altura",
72 + "aluviao",
73 + "alvura",
74 + "amazonico",
75 + "ambulatorio",
76 + "ametodico",
77 + "amizades",
78 + "amniotico",
79 + "amovivel",
80 + "amurada",
81 + "anatomico",
82 + "ancorar",
83 + "anexo",
84 + "anfora",
85 + "aniversario",
86 + "anjo",
87 + "anotar",
88 + "ansioso",
89 + "anturio",
90 + "anuviar",
91 + "anverso",
92 + "anzol",
93 + "aonde",
94 + "apaziguar",
95 + "apito",
96 + "aplicavel",
97 + "apoteotico",
98 + "aprimorar",
99 + "aprumo",
100 + "apto",
101 + "apuros",
102 + "aquoso",
103 + "arauto",
104 + "arbusto",
105 + "arduo",
106 + "aresta",
107 + "arfar",
108 + "arguto",
109 + "aritmetico",
110 + "arlequim",
111 + "armisticio",
112 + "aromatizar",
113 + "arpoar",
114 + "arquivo",
115 + "arrumar",
116 + "arsenio",
117 + "arturiano",
118 + "aruaque",
119 + "arvores",
120 + "asbesto",
121 + "ascorbico",
122 + "aspirina",
123 + "asqueroso",
124 + "assustar",
125 + "astuto",
126 + "atazanar",
127 + "ativo",
128 + "atletismo",
129 + "atmosferico",
130 + "atormentar",
131 + "atroz",
132 + "aturdir",
133 + "audivel",
134 + "auferir",
135 + "augusto",
136 + "aula",
137 + "aumento",
138 + "aurora",
139 + "autuar",
140 + "avatar",
141 + "avexar",
142 + "avizinhar",
143 + "avolumar",
144 + "avulso",
145 + "axiomatico",
146 + "azerbaijano",
147 + "azimute",
148 + "azoto",
149 + "azulejo",
150 + "bacteriologista",
151 + "badulaque",
152 + "baforada",
153 + "baixote",
154 + "bajular",
155 + "balzaquiana",
156 + "bambuzal",
157 + "banzo",
158 + "baoba",
159 + "baqueta",
160 + "barulho",
161 + "bastonete",
162 + "batuta",
163 + "bauxita",
164 + "bavaro",
165 + "bazuca",
166 + "bcrepuscular",
167 + "beato",
168 + "beduino",
169 + "begonia",
170 + "behaviorista",
171 + "beisebol",
172 + "belzebu",
173 + "bemol",
174 + "benzido",
175 + "beocio",
176 + "bequer",
177 + "berro",
178 + "besuntar",
179 + "betume",
180 + "bexiga",
181 + "bezerro",
182 + "biatlon",
183 + "biboca",
184 + "bicuspide",
185 + "bidirecional",
186 + "bienio",
187 + "bifurcar",
188 + "bigorna",
189 + "bijuteria",
190 + "bimotor",
191 + "binormal",
192 + "bioxido",
193 + "bipolarizacao",
194 + "biquini",
195 + "birutice",
196 + "bisturi",
197 + "bituca",
198 + "biunivoco",
199 + "bivalve",
200 + "bizarro",
201 + "blasfemo",
202 + "blenorreia",
203 + "blindar",
204 + "bloqueio",
205 + "blusao",
206 + "boazuda",
207 + "bofete",
208 + "bojudo",
209 + "bolso",
210 + "bombordo",
211 + "bonzo",
212 + "botina",
213 + "boquiaberto",
214 + "bostoniano",
215 + "botulismo",
216 + "bourbon",
217 + "bovino",
218 + "boximane",
219 + "bravura",
220 + "brevidade",
221 + "britar",
222 + "broxar",
223 + "bruno",
224 + "bruxuleio",
225 + "bubonico",
226 + "bucolico",
227 + "buda",
228 + "budista",
229 + "bueiro",
230 + "buffer",
231 + "bugre",
232 + "bujao",
233 + "bumerangue",
234 + "burundines",
235 + "busto",
236 + "butique",
237 + "buzios",
238 + "caatinga",
239 + "cabuqui",
240 + "cacunda",
241 + "cafuzo",
242 + "cajueiro",
243 + "camurca",
244 + "canudo",
245 + "caquizeiro",
246 + "carvoeiro",
247 + "casulo",
248 + "catuaba",
249 + "cauterizar",
250 + "cebolinha",
251 + "cedula",
252 + "ceifeiro",
253 + "celulose",
254 + "cerzir",
255 + "cesto",
256 + "cetro",
257 + "ceus",
258 + "cevar",
259 + "chavena",
260 + "cheroqui",
261 + "chita",
262 + "chovido",
263 + "chuvoso",
264 + "ciatico",
265 + "cibernetico",
266 + "cicuta",
267 + "cidreira",
268 + "cientistas",
269 + "cifrar",
270 + "cigarro",
271 + "cilio",
272 + "cimo",
273 + "cinzento",
274 + "cioso",
275 + "cipriota",
276 + "cirurgico",
277 + "cisto",
278 + "citrico",
279 + "ciumento",
280 + "civismo",
281 + "clavicula",
282 + "clero",
283 + "clitoris",
284 + "cluster",
285 + "coaxial",
286 + "cobrir",
287 + "cocota",
288 + "codorniz",
289 + "coexistir",
290 + "cogumelo",
291 + "coito",
292 + "colusao",
293 + "compaixao",
294 + "comutativo",
295 + "contentamento",
296 + "convulsivo",
297 + "coordenativa",
298 + "coquetel",
299 + "correto",
300 + "corvo",
301 + "costureiro",
302 + "cotovia",
303 + "covil",
304 + "cozinheiro",
305 + "cretino",
306 + "cristo",
307 + "crivo",
308 + "crotalo",
309 + "cruzes",
310 + "cubo",
311 + "cucuia",
312 + "cueiro",
313 + "cuidar",
314 + "cujo",
315 + "cultural",
316 + "cunilingua",
317 + "cupula",
318 + "curvo",
319 + "custoso",
320 + "cutucar",
321 + "czarismo",
322 + "dablio",
323 + "dacota",
324 + "dados",
325 + "daguerreotipo",
326 + "daiquiri",
327 + "daltonismo",
328 + "damista",
329 + "dantesco",
330 + "daquilo",
331 + "darwinista",
332 + "dasein",
333 + "dativo",
334 + "deao",
335 + "debutantes",
336 + "decurso",
337 + "deduzir",
338 + "defunto",
339 + "degustar",
340 + "dejeto",
341 + "deltoide",
342 + "demover",
343 + "denunciar",
344 + "deputado",
345 + "deque",
346 + "dervixe",
347 + "desvirtuar",
348 + "deturpar",
349 + "deuteronomio",
350 + "devoto",
351 + "dextrose",
352 + "dezoito",
353 + "diatribe",
354 + "dicotomico",
355 + "didatico",
356 + "dietista",
357 + "difuso",
358 + "digressao",
359 + "diluvio",
360 + "diminuto",
361 + "dinheiro",
362 + "dinossauro",
363 + "dioxido",
364 + "diplomatico",
365 + "dique",
366 + "dirimivel",
367 + "disturbio",
368 + "diurno",
369 + "divulgar",
370 + "dizivel",
371 + "doar",
372 + "dobro",
373 + "docura",
374 + "dodoi",
375 + "doer",
376 + "dogue",
377 + "doloso",
378 + "domo",
379 + "donzela",
380 + "doping",
381 + "dorsal",
382 + "dossie",
383 + "dote",
384 + "doutro",
385 + "doze",
386 + "dravidico",
387 + "dreno",
388 + "driver",
389 + "dropes",
390 + "druso",
391 + "dubnio",
392 + "ducto",
393 + "dueto",
394 + "dulija",
395 + "dundum",
396 + "duodeno",
397 + "duquesa",
398 + "durou",
399 + "duvidoso",
400 + "duzia",
401 + "ebano",
402 + "ebrio",
403 + "eburneo",
404 + "echarpe",
405 + "eclusa",
406 + "ecossistema",
407 + "ectoplasma",
408 + "ecumenismo",
409 + "eczema",
410 + "eden",
411 + "editorial",
412 + "edredom",
413 + "edulcorar",
414 + "efetuar",
415 + "efigie",
416 + "efluvio",
417 + "egiptologo",
418 + "egresso",
419 + "egua",
420 + "einsteiniano",
421 + "eira",
422 + "eivar",
423 + "eixos",
424 + "ejetar",
425 + "elastomero",
426 + "eldorado",
427 + "elixir",
428 + "elmo",
429 + "eloquente",
430 + "elucidativo",
431 + "emaranhar",
432 + "embutir",
433 + "emerito",
434 + "emfa",
435 + "emitir",
436 + "emotivo",
437 + "empuxo",
438 + "emulsao",
439 + "enamorar",
440 + "encurvar",
441 + "enduro",
442 + "enevoar",
443 + "enfurnar",
444 + "enguico",
445 + "enho",
446 + "enigmista",
447 + "enlutar",
448 + "enormidade",
449 + "enpreendimento",
450 + "enquanto",
451 + "enriquecer",
452 + "enrugar",
453 + "entusiastico",
454 + "enunciar",
455 + "envolvimento",
456 + "enxuto",
457 + "enzimatico",
458 + "eolico",
459 + "epiteto",
460 + "epoxi",
461 + "epura",
462 + "equivoco",
463 + "erario",
464 + "erbio",
465 + "ereto",
466 + "erguido",
467 + "erisipela",
468 + "ermo",
469 + "erotizar",
470 + "erros",
471 + "erupcao",
472 + "ervilha",
473 + "esburacar",
474 + "escutar",
475 + "esfuziante",
476 + "esguio",
477 + "esloveno",
478 + "esmurrar",
479 + "esoterismo",
480 + "esperanca",
481 + "espirito",
482 + "espurio",
483 + "essencialmente",
484 + "esturricar",
485 + "esvoacar",
486 + "etario",
487 + "eterno",
488 + "etiquetar",
489 + "etnologo",
490 + "etos",
491 + "etrusco",
492 + "euclidiano",
493 + "euforico",
494 + "eugenico",
495 + "eunuco",
496 + "europio",
497 + "eustaquio",
498 + "eutanasia",
499 + "evasivo",
500 + "eventualidade",
501 + "evitavel",
502 + "evoluir",
503 + "exaustor",
504 + "excursionista",
505 + "exercito",
506 + "exfoliado",
507 + "exito",
508 + "exotico",
509 + "expurgo",
510 + "exsudar",
511 + "extrusora",
512 + "exumar",
513 + "fabuloso",
514 + "facultativo",
515 + "fado",
516 + "fagulha",
517 + "faixas",
518 + "fajuto",
519 + "faltoso",
520 + "famoso",
521 + "fanzine",
522 + "fapesp",
523 + "faquir",
524 + "fartura",
525 + "fastio",
526 + "faturista",
527 + "fausto",
528 + "favorito",
529 + "faxineira",
530 + "fazer",
531 + "fealdade",
532 + "febril",
533 + "fecundo",
534 + "fedorento",
535 + "feerico",
536 + "feixe",
537 + "felicidade",
538 + "felpudo",
539 + "feltro",
540 + "femur",
541 + "fenotipo",
542 + "fervura",
543 + "festivo",
544 + "feto",
545 + "feudo",
546 + "fevereiro",
547 + "fezinha",
548 + "fiasco",
549 + "fibra",
550 + "ficticio",
551 + "fiduciario",
552 + "fiesp",
553 + "fifa",
554 + "figurino",
555 + "fijiano",
556 + "filtro",
557 + "finura",
558 + "fiorde",
559 + "fiquei",
560 + "firula",
561 + "fissurar",
562 + "fitoteca",
563 + "fivela",
564 + "fixo",
565 + "flavio",
566 + "flexor",
567 + "flibusteiro",
568 + "flotilha",
569 + "fluxograma",
570 + "fobos",
571 + "foco",
572 + "fofura",
573 + "foguista",
574 + "foie",
575 + "foliculo",
576 + "fominha",
577 + "fonte",
578 + "forum",
579 + "fosso",
580 + "fotossintese",
581 + "foxtrote",
582 + "fraudulento",
583 + "frevo",
584 + "frivolo",
585 + "frouxo",
586 + "frutose",
587 + "fuba",
588 + "fucsia",
589 + "fugitivo",
590 + "fuinha",
591 + "fujao",
592 + "fulustreco",
593 + "fumo",
594 + "funileiro",
595 + "furunculo",
596 + "fustigar",
597 + "futurologo",
598 + "fuxico",
599 + "fuzue",
600 + "gabriel",
601 + "gado",
602 + "gaelico",
603 + "gafieira",
604 + "gaguejo",
605 + "gaivota",
606 + "gajo",
607 + "galvanoplastico",
608 + "gamo",
609 + "ganso",
610 + "garrucha",
611 + "gastronomo",
612 + "gatuno",
613 + "gaussiano",
614 + "gaviao",
615 + "gaxeta",
616 + "gazeteiro",
617 + "gear",
618 + "geiser",
619 + "geminiano",
620 + "generoso",
621 + "genuino",
622 + "geossinclinal",
623 + "gerundio",
624 + "gestual",
625 + "getulista",
626 + "gibi",
627 + "gigolo",
628 + "gilete",
629 + "ginseng",
630 + "giroscopio",
631 + "glaucio",
632 + "glacial",
633 + "gleba",
634 + "glifo",
635 + "glote",
636 + "glutonia",
637 + "gnostico",
638 + "goela",
639 + "gogo",
640 + "goitaca",
641 + "golpista",
642 + "gomo",
643 + "gonzo",
644 + "gorro",
645 + "gostou",
646 + "goticula",
647 + "gourmet",
648 + "governo",
649 + "gozo",
650 + "graxo",
651 + "grevista",
652 + "grito",
653 + "grotesco",
654 + "gruta",
655 + "guaxinim",
656 + "gude",
657 + "gueto",
658 + "guizo",
659 + "guloso",
660 + "gume",
661 + "guru",
662 + "gustativo",
663 + "grelhado",
664 + "gutural",
665 + "habitue",
666 + "haitiano",
667 + "halterofilista",
668 + "hamburguer",
669 + "hanseniase",
670 + "happening",
671 + "harpista",
672 + "hastear",
673 + "haveres",
674 + "hebreu",
675 + "hectometro",
676 + "hedonista",
677 + "hegira",
678 + "helena",
679 + "helminto",
680 + "hemorroidas",
681 + "henrique",
682 + "heptassilabo",
683 + "hertziano",
684 + "hesitar",
685 + "heterossexual",
686 + "heuristico",
687 + "hexagono",
688 + "hiato",
689 + "hibrido",
690 + "hidrostatico",
691 + "hieroglifo",
692 + "hifenizar",
693 + "higienizar",
694 + "hilario",
695 + "himen",
696 + "hino",
697 + "hippie",
698 + "hirsuto",
699 + "historiografia",
700 + "hitlerista",
701 + "hodometro",
702 + "hoje",
703 + "holograma",
704 + "homus",
705 + "honroso",
706 + "hoquei",
707 + "horto",
708 + "hostilizar",
709 + "hotentote",
710 + "huguenote",
711 + "humilde",
712 + "huno",
713 + "hurra",
714 + "hutu",
715 + "iaia",
716 + "ialorixa",
717 + "iambico",
718 + "iansa",
719 + "iaque",
720 + "iara",
721 + "iatista",
722 + "iberico",
723 + "ibis",
724 + "icar",
725 + "iceberg",
726 + "icosagono",
727 + "idade",
728 + "ideologo",
729 + "idiotice",
730 + "idoso",
731 + "iemenita",
732 + "iene",
733 + "igarape",
734 + "iglu",
735 + "ignorar",
736 + "igreja",
737 + "iguaria",
738 + "iidiche",
739 + "ilativo",
740 + "iletrado",
741 + "ilharga",
742 + "ilimitado",
743 + "ilogismo",
744 + "ilustrissimo",
745 + "imaturo",
746 + "imbuzeiro",
747 + "imerso",
748 + "imitavel",
749 + "imovel",
750 + "imputar",
751 + "imutavel",
752 + "inaveriguavel",
753 + "incutir",
754 + "induzir",
755 + "inextricavel",
756 + "infusao",
757 + "ingua",
758 + "inhame",
759 + "iniquo",
760 + "injusto",
761 + "inning",
762 + "inoxidavel",
763 + "inquisitorial",
764 + "insustentavel",
765 + "intumescimento",
766 + "inutilizavel",
767 + "invulneravel",
768 + "inzoneiro",
769 + "iodo",
770 + "iogurte",
771 + "ioio",
772 + "ionosfera",
773 + "ioruba",
774 + "iota",
775 + "ipsilon",
776 + "irascivel",
777 + "iris",
778 + "irlandes",
779 + "irmaos",
780 + "iroques",
781 + "irrupcao",
782 + "isca",
783 + "isento",
784 + "islandes",
785 + "isotopo",
786 + "isqueiro",
787 + "israelita",
788 + "isso",
789 + "isto",
790 + "iterbio",
791 + "itinerario",
792 + "itrio",
793 + "iuane",
794 + "iugoslavo",
795 + "jabuticabeira",
796 + "jacutinga",
797 + "jade",
798 + "jagunco",
799 + "jainista",
800 + "jaleco",
801 + "jambo",
802 + "jantarada",
803 + "japones",
804 + "jaqueta",
805 + "jarro",
806 + "jasmim",
807 + "jato",
808 + "jaula",
809 + "javel",
810 + "jazz",
811 + "jegue",
812 + "jeitoso",
813 + "jejum",
814 + "jenipapo",
815 + "jeova",
816 + "jequitiba",
817 + "jersei",
818 + "jesus",
819 + "jetom",
820 + "jiboia",
821 + "jihad",
822 + "jilo",
823 + "jingle",
824 + "jipe",
825 + "jocoso",
826 + "joelho",
827 + "joguete",
828 + "joio",
829 + "jojoba",
830 + "jorro",
831 + "jota",
832 + "joule",
833 + "joviano",
834 + "jubiloso",
835 + "judoca",
836 + "jugular",
837 + "juizo",
838 + "jujuba",
839 + "juliano",
840 + "jumento",
841 + "junto",
842 + "jururu",
843 + "justo",
844 + "juta",
845 + "juventude",
846 + "labutar",
847 + "laguna",
848 + "laico",
849 + "lajota",
850 + "lanterninha",
851 + "lapso",
852 + "laquear",
853 + "lastro",
854 + "lauto",
855 + "lavrar",
856 + "laxativo",
857 + "lazer",
858 + "leasing",
859 + "lebre",
860 + "lecionar",
861 + "ledo",
862 + "leguminoso",
863 + "leitura",
864 + "lele",
865 + "lemure",
866 + "lento",
867 + "leonardo",
868 + "leopardo",
869 + "lepton",
870 + "leque",
871 + "leste",
872 + "letreiro",
873 + "leucocito",
874 + "levitico",
875 + "lexicologo",
876 + "lhama",
877 + "lhufas",
878 + "liame",
879 + "licoroso",
880 + "lidocaina",
881 + "liliputiano",
882 + "limusine",
883 + "linotipo",
884 + "lipoproteina",
885 + "liquidos",
886 + "lirismo",
887 + "lisura",
888 + "liturgico",
889 + "livros",
890 + "lixo",
891 + "lobulo",
892 + "locutor",
893 + "lodo",
894 + "logro",
895 + "lojista",
896 + "lombriga",
897 + "lontra",
898 + "loop",
899 + "loquaz",
900 + "lorota",
901 + "losango",
902 + "lotus",
903 + "louvor",
904 + "luar",
905 + "lubrificavel",
906 + "lucros",
907 + "lugubre",
908 + "luis",
909 + "luminoso",
910 + "luneta",
911 + "lustroso",
912 + "luto",
913 + "luvas",
914 + "luxuriante",
915 + "luzeiro",
916 + "maduro",
917 + "maestro",
918 + "mafioso",
919 + "magro",
920 + "maiuscula",
921 + "majoritario",
922 + "malvisto",
923 + "mamute",
924 + "manutencao",
925 + "mapoteca",
926 + "maquinista",
927 + "marzipa",
928 + "masturbar",
929 + "matuto",
930 + "mausoleu",
931 + "mavioso",
932 + "maxixe",
933 + "mazurca",
934 + "meandro",
935 + "mecha",
936 + "medusa",
937 + "mefistofelico",
938 + "megera",
939 + "meirinho",
940 + "melro",
941 + "memorizar",
942 + "menu",
943 + "mequetrefe",
944 + "mertiolate",
945 + "mestria",
946 + "metroviario",
947 + "mexilhao",
948 + "mezanino",
949 + "miau",
950 + "microssegundo",
951 + "midia",
952 + "migratorio",
953 + "mimosa",
954 + "minuto",
955 + "miosotis",
956 + "mirtilo",
957 + "misturar",
958 + "mitzvah",
959 + "miudos",
960 + "mixuruca",
961 + "mnemonico",
962 + "moagem",
963 + "mobilizar",
964 + "modulo",
965 + "moer",
966 + "mofo",
967 + "mogno",
968 + "moita",
969 + "molusco",
970 + "monumento",
971 + "moqueca",
972 + "morubixaba",
973 + "mostruario",
974 + "motriz",
975 + "mouse",
976 + "movivel",
977 + "mozarela",
978 + "muarra",
979 + "muculmano",
980 + "mudo",
981 + "mugir",
982 + "muitos",
983 + "mumunha",
984 + "munir",
985 + "muon",
986 + "muquira",
987 + "murros",
988 + "musselina",
989 + "nacoes",
990 + "nado",
991 + "naftalina",
992 + "nago",
993 + "naipe",
994 + "naja",
995 + "nalgum",
996 + "namoro",
997 + "nanquim",
998 + "napolitano",
999 + "naquilo",
1000 + "nascimento",
1001 + "nautilo",
1002 + "navios",
1003 + "nazista",
1004 + "nebuloso",
1005 + "nectarina",
1006 + "nefrologo",
1007 + "negus",
1008 + "nelore",
1009 + "nenufar",
1010 + "nepotismo",
1011 + "nervura",
1012 + "neste",
1013 + "netuno",
1014 + "neutron",
1015 + "nevoeiro",
1016 + "newtoniano",
1017 + "nexo",
1018 + "nhenhenhem",
1019 + "nhoque",
1020 + "nigeriano",
1021 + "niilista",
1022 + "ninho",
1023 + "niobio",
1024 + "niponico",
1025 + "niquelar",
1026 + "nirvana",
1027 + "nisto",
1028 + "nitroglicerina",
1029 + "nivoso",
1030 + "nobreza",
1031 + "nocivo",
1032 + "noel",
1033 + "nogueira",
1034 + "noivo",
1035 + "nojo",
1036 + "nominativo",
1037 + "nonuplo",
1038 + "noruegues",
1039 + "nostalgico",
1040 + "noturno",
1041 + "nouveau",
1042 + "nuanca",
1043 + "nublar",
1044 + "nucleotideo",
1045 + "nudista",
1046 + "nulo",
1047 + "numismatico",
1048 + "nunquinha",
1049 + "nupcias",
1050 + "nutritivo",
1051 + "nuvens",
1052 + "oasis",
1053 + "obcecar",
1054 + "obeso",
1055 + "obituario",
1056 + "objetos",
1057 + "oblongo",
1058 + "obnoxio",
1059 + "obrigatorio",
1060 + "obstruir",
1061 + "obtuso",
1062 + "obus",
1063 + "obvio",
1064 + "ocaso",
1065 + "occipital",
1066 + "oceanografo",
1067 + "ocioso",
1068 + "oclusivo",
1069 + "ocorrer",
1070 + "ocre",
1071 + "octogono",
1072 + "odalisca",
1073 + "odisseia",
1074 + "odorifico",
1075 + "oersted",
1076 + "oeste",
1077 + "ofertar",
1078 + "ofidio",
1079 + "oftalmologo",
1080 + "ogiva",
1081 + "ogum",
1082 + "oigale",
1083 + "oitavo",
1084 + "oitocentos",
1085 + "ojeriza",
1086 + "olaria",
1087 + "oleoso",
1088 + "olfato",
1089 + "olhos",
1090 + "oliveira",
1091 + "olmo",
1092 + "olor",
1093 + "olvidavel",
1094 + "ombudsman",
1095 + "omeleteira",
1096 + "omitir",
1097 + "omoplata",
1098 + "onanismo",
1099 + "ondular",
1100 + "oneroso",
1101 + "onomatopeico",
1102 + "ontologico",
1103 + "onus",
1104 + "onze",
1105 + "opalescente",
1106 + "opcional",
1107 + "operistico",
1108 + "opio",
1109 + "oposto",
1110 + "oprobrio",
1111 + "optometrista",
1112 + "opusculo",
1113 + "oratorio",
1114 + "orbital",
1115 + "orcar",
1116 + "orfao",
1117 + "orixa",
1118 + "orla",
1119 + "ornitologo",
1120 + "orquidea",
1121 + "ortorrombico",
1122 + "orvalho",
1123 + "osculo",
1124 + "osmotico",
1125 + "ossudo",
1126 + "ostrogodo",
1127 + "otario",
1128 + "otite",
1129 + "ouro",
1130 + "ousar",
1131 + "outubro",
1132 + "ouvir",
1133 + "ovario",
1134 + "overnight",
1135 + "oviparo",
1136 + "ovni",
1137 + "ovoviviparo",
1138 + "ovulo",
1139 + "oxala",
1140 + "oxente",
1141 + "oxiuro",
1142 + "oxossi",
1143 + "ozonizar",
1144 + "paciente",
1145 + "pactuar",
1146 + "padronizar",
1147 + "paete",
1148 + "pagodeiro",
1149 + "paixao",
1150 + "pajem",
1151 + "paludismo",
1152 + "pampas",
1153 + "panturrilha",
1154 + "papudo",
1155 + "paquistanes",
1156 + "pastoso",
1157 + "patua",
1158 + "paulo",
1159 + "pauzinhos",
1160 + "pavoroso",
1161 + "paxa",
1162 + "pazes",
1163 + "peao",
1164 + "pecuniario",
1165 + "pedunculo",
1166 + "pegaso",
1167 + "peixinho",
1168 + "pejorativo",
1169 + "pelvis",
1170 + "penuria",
1171 + "pequno",
1172 + "petunia",
1173 + "pezada",
1174 + "piauiense",
1175 + "pictorico",
1176 + "pierro",
1177 + "pigmeu",
1178 + "pijama",
1179 + "pilulas",
1180 + "pimpolho",
1181 + "pintura",
1182 + "piorar",
1183 + "pipocar",
1184 + "piqueteiro",
1185 + "pirulito",
1186 + "pistoleiro",
1187 + "pituitaria",
1188 + "pivotar",
1189 + "pixote",
1190 + "pizzaria",
1191 + "plistoceno",
1192 + "plotar",
1193 + "pluviometrico",
1194 + "pneumonico",
1195 + "poco",
1196 + "podridao",
1197 + "poetisa",
1198 + "pogrom",
1199 + "pois",
1200 + "polvorosa",
1201 + "pomposo",
1202 + "ponderado",
1203 + "pontudo",
1204 + "populoso",
1205 + "poquer",
1206 + "porvir",
1207 + "posudo",
1208 + "potro",
1209 + "pouso",
1210 + "povoar",
1211 + "prazo",
1212 + "prezar",
1213 + "privilegios",
1214 + "proximo",
1215 + "prussiano",
1216 + "pseudopode",
1217 + "psoriase",
1218 + "pterossauros",
1219 + "ptialina",
1220 + "ptolemaico",
1221 + "pudor",
1222 + "pueril",
1223 + "pufe",
1224 + "pugilista",
1225 + "puir",
1226 + "pujante",
1227 + "pulverizar",
1228 + "pumba",
1229 + "punk",
1230 + "purulento",
1231 + "pustula",
1232 + "putsch",
1233 + "puxe",
1234 + "quatrocentos",
1235 + "quetzal",
1236 + "quixotesco",
1237 + "quotizavel",
1238 + "rabujice",
1239 + "racista",
1240 + "radonio",
1241 + "rafia",
1242 + "ragu",
1243 + "rajado",
1244 + "ralo",
1245 + "rampeiro",
1246 + "ranzinza",
1247 + "raptor",
1248 + "raquitismo",
1249 + "raro",
1250 + "rasurar",
1251 + "ratoeira",
1252 + "ravioli",
1253 + "razoavel",
1254 + "reavivar",
1255 + "rebuscar",
1256 + "recusavel",
1257 + "reduzivel",
1258 + "reexposicao",
1259 + "refutavel",
1260 + "regurgitar",
1261 + "reivindicavel",
1262 + "rejuvenescimento",
1263 + "relva",
1264 + "remuneravel",
1265 + "renunciar",
1266 + "reorientar",
1267 + "repuxo",
1268 + "requisito",
1269 + "resumo",
1270 + "returno",
1271 + "reutilizar",
1272 + "revolvido",
1273 + "rezonear",
1274 + "riacho",
1275 + "ribossomo",
1276 + "ricota",
1277 + "ridiculo",
1278 + "rifle",
1279 + "rigoroso",
1280 + "rijo",
1281 + "rimel",
1282 + "rins",
1283 + "rios",
1284 + "riqueza",
1285 + "respeito",
1286 + "rissole",
1287 + "ritualistico",
1288 + "rivalizar",
1289 + "rixa",
1290 + "robusto",
1291 + "rococo",
1292 + "rodoviario",
1293 + "roer",
1294 + "rogo",
1295 + "rojao",
1296 + "rolo",
1297 + "rompimento",
1298 + "ronronar",
1299 + "roqueiro",
1300 + "rorqual",
1301 + "rosto",
1302 + "rotundo",
1303 + "rouxinol",
1304 + "roxo",
1305 + "royal",
1306 + "ruas",
1307 + "rucula",
1308 + "rudimentos",
1309 + "ruela",
1310 + "rufo",
1311 + "rugoso",
1312 + "ruivo",
1313 + "rule",
1314 + "rumoroso",
1315 + "runico",
1316 + "ruptura",
1317 + "rural",
1318 + "rustico",
1319 + "rutilar",
1320 + "saariano",
1321 + "sabujo",
1322 + "sacudir",
1323 + "sadomasoquista",
1324 + "safra",
1325 + "sagui",
1326 + "sais",
1327 + "samurai",
1328 + "santuario",
1329 + "sapo",
1330 + "saquear",
1331 + "sartriano",
1332 + "saturno",
1333 + "saude",
1334 + "sauva",
1335 + "saveiro",
1336 + "saxofonista",
1337 + "sazonal",
1338 + "scherzo",
1339 + "script",
1340 + "seara",
1341 + "seborreia",
1342 + "secura",
1343 + "seduzir",
1344 + "sefardim",
1345 + "seguro",
1346 + "seja",
1347 + "selvas",
1348 + "sempre",
1349 + "senzala",
1350 + "sepultura",
1351 + "sequoia",
1352 + "sestercio",
1353 + "setuplo",
1354 + "seus",
1355 + "seviciar",
1356 + "sezonismo",
1357 + "shalom",
1358 + "siames",
1359 + "sibilante",
1360 + "sicrano",
1361 + "sidra",
1362 + "sifilitico",
1363 + "signos",
1364 + "silvo",
1365 + "simultaneo",
1366 + "sinusite",
1367 + "sionista",
1368 + "sirio",
1369 + "sisudo",
1370 + "situar",
1371 + "sivan",
1372 + "slide",
1373 + "slogan",
1374 + "soar",
1375 + "sobrio",
1376 + "socratico",
1377 + "sodomizar",
1378 + "soerguer",
1379 + "software",
1380 + "sogro",
1381 + "soja",
1382 + "solver",
1383 + "somente",
1384 + "sonso",
1385 + "sopro",
1386 + "soquete",
1387 + "sorveteiro",
1388 + "sossego",
1389 + "soturno",
1390 + "sousafone",
1391 + "sovinice",
1392 + "sozinho",
1393 + "suavizar",
1394 + "subverter",
1395 + "sucursal",
1396 + "sudoriparo",
1397 + "sufragio",
1398 + "sugestoes",
1399 + "suite",
1400 + "sujo",
1401 + "sultao",
1402 + "sumula",
1403 + "suntuoso",
1404 + "suor",
1405 + "supurar",
1406 + "suruba",
1407 + "susto",
1408 + "suturar",
1409 + "suvenir",
1410 + "tabuleta",
1411 + "taco",
1412 + "tadjique",
1413 + "tafeta",
1414 + "tagarelice",
1415 + "taitiano",
1416 + "talvez",
1417 + "tampouco",
1418 + "tanzaniano",
1419 + "taoista",
1420 + "tapume",
1421 + "taquion",
1422 + "tarugo",
1423 + "tascar",
1424 + "tatuar",
1425 + "tautologico",
1426 + "tavola",
1427 + "taxionomista",
1428 + "tchecoslovaco",
1429 + "teatrologo",
1430 + "tectonismo",
1431 + "tedioso",
1432 + "teflon",
1433 + "tegumento",
1434 + "teixo",
1435 + "telurio",
1436 + "temporas",
1437 + "tenue",
1438 + "teosofico",
1439 + "tepido",
1440 + "tequila",
1441 + "terrorista",
1442 + "testosterona",
1443 + "tetrico",
1444 + "teutonico",
1445 + "teve",
1446 + "texugo",
1447 + "tiara",
1448 + "tibia",
1449 + "tiete",
1450 + "tifoide",
1451 + "tigresa",
1452 + "tijolo",
1453 + "tilintar",
1454 + "timpano",
1455 + "tintureiro",
1456 + "tiquete",
1457 + "tiroteio",
1458 + "tisico",
1459 + "titulos",
1460 + "tive",
1461 + "toar",
1462 + "toboga",
1463 + "tofu",
1464 + "togoles",
1465 + "toicinho",
1466 + "tolueno",
1467 + "tomografo",
1468 + "tontura",
1469 + "toponimo",
1470 + "toquio",
1471 + "torvelinho",
1472 + "tostar",
1473 + "toto",
1474 + "touro",
1475 + "toxina",
1476 + "trazer",
1477 + "trezentos",
1478 + "trivialidade",
1479 + "trovoar",
1480 + "truta",
1481 + "tuaregue",
1482 + "tubular",
1483 + "tucano",
1484 + "tudo",
1485 + "tufo",
1486 + "tuiste",
1487 + "tulipa",
1488 + "tumultuoso",
1489 + "tunisino",
1490 + "tupiniquim",
1491 + "turvo",
1492 + "tutu",
1493 + "ucraniano",
1494 + "udenista",
1495 + "ufanista",
1496 + "ufologo",
1497 + "ugaritico",
1498 + "uiste",
1499 + "uivo",
1500 + "ulceroso",
1501 + "ulema",
1502 + "ultravioleta",
1503 + "umbilical",
1504 + "umero",
1505 + "umido",
1506 + "umlaut",
1507 + "unanimidade",
1508 + "unesco",
1509 + "ungulado",
1510 + "unheiro",
1511 + "univoco",
1512 + "untuoso",
1513 + "urano",
1514 + "urbano",
1515 + "urdir",
1516 + "uretra",
1517 + "urgente",
1518 + "urinol",
1519 + "urna",
1520 + "urologo",
1521 + "urro",
1522 + "ursulina",
1523 + "urtiga",
1524 + "urupe",
1525 + "usavel",
1526 + "usbeque",
1527 + "usei",
1528 + "usineiro",
1529 + "usurpar",
1530 + "utero",
1531 + "utilizar",
1532 + "utopico",
1533 + "uvular",
1534 + "uxoricidio",
1535 + "vacuo",
1536 + "vadio",
1537 + "vaguear",
1538 + "vaivem",
1539 + "valvula",
1540 + "vampiro",
1541 + "vantajoso",
1542 + "vaporoso",
1543 + "vaquinha",
1544 + "varziano",
1545 + "vasto",
1546 + "vaticinio",
1547 + "vaudeville",
1548 + "vazio",
1549 + "veado",
1550 + "vedico",
1551 + "veemente",
1552 + "vegetativo",
1553 + "veio",
1554 + "veja",
1555 + "veludo",
1556 + "venusiano",
1557 + "verdade",
1558 + "verve",
1559 + "vestuario",
1560 + "vetusto",
1561 + "vexatorio",
1562 + "vezes",
1563 + "viavel",
1564 + "vibratorio",
1565 + "victor",
1566 + "vicunha",
1567 + "vidros",
1568 + "vietnamita",
1569 + "vigoroso",
1570 + "vilipendiar",
1571 + "vime",
1572 + "vintem",
1573 + "violoncelo",
1574 + "viquingue",
1575 + "virus",
1576 + "visualizar",
1577 + "vituperio",
1578 + "viuvo",
1579 + "vivo",
1580 + "vizir",
1581 + "voar",
1582 + "vociferar",
1583 + "vodu",
1584 + "vogar",
1585 + "voile",
1586 + "volver",
1587 + "vomito",
1588 + "vontade",
1589 + "vortice",
1590 + "vosso",
1591 + "voto",
1592 + "vovozinha",
1593 + "voyeuse",
1594 + "vozes",
1595 + "vulva",
1596 + "vupt",
1597 + "western",
1598 + "xadrez",
1599 + "xale",
1600 + "xampu",
1601 + "xango",
1602 + "xarope",
1603 + "xaual",
1604 + "xavante",
1605 + "xaxim",
1606 + "xenonio",
1607 + "xepa",
1608 + "xerox",
1609 + "xicara",
1610 + "xifopago",
1611 + "xiita",
1612 + "xilogravura",
1613 + "xinxim",
1614 + "xistoso",
1615 + "xixi",
1616 + "xodo",
1617 + "xogum",
1618 + "xucro",
1619 + "zabumba",
1620 + "zagueiro",
1621 + "zambiano",
1622 + "zanzar",
1623 + "zarpar",
1624 + "zebu",
1625 + "zefiro",
1626 + "zeloso",
1627 + "zenite",
1628 + "zumbi"
1629 + ];
1630 +}
\ No newline at end of file
cw_haven/lib/mnemonics/russian.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class RussianMnemonics {
2 + static const words = [
3 + "абажур",
4 + "абзац",
5 + "абонент",
6 + "абрикос",
7 + "абсурд",
8 + "авангард",
9 + "август",
10 + "авиация",
11 + "авоська",
12 + "автор",
13 + "агат",
14 + "агент",
15 + "агитатор",
16 + "агнец",
17 + "агония",
18 + "агрегат",
19 + "адвокат",
20 + "адмирал",
21 + "адрес",
22 + "ажиотаж",
23 + "азарт",
24 + "азбука",
25 + "азот",
26 + "аист",
27 + "айсберг",
28 + "академия",
29 + "аквариум",
30 + "аккорд",
31 + "акробат",
32 + "аксиома",
33 + "актер",
34 + "акула",
35 + "акция",
36 + "алгоритм",
37 + "алебарда",
38 + "аллея",
39 + "алмаз",
40 + "алтарь",
41 + "алфавит",
42 + "алхимик",
43 + "алый",
44 + "альбом",
45 + "алюминий",
46 + "амбар",
47 + "аметист",
48 + "амнезия",
49 + "ампула",
50 + "амфора",
51 + "анализ",
52 + "ангел",
53 + "анекдот",
54 + "анимация",
55 + "анкета",
56 + "аномалия",
57 + "ансамбль",
58 + "антенна",
59 + "апатия",
60 + "апельсин",
61 + "апофеоз",
62 + "аппарат",
63 + "апрель",
64 + "аптека",
65 + "арабский",
66 + "арбуз",
67 + "аргумент",
68 + "арест",
69 + "ария",
70 + "арка",
71 + "армия",
72 + "аромат",
73 + "арсенал",
74 + "артист",
75 + "архив",
76 + "аршин",
77 + "асбест",
78 + "аскетизм",
79 + "аспект",
80 + "ассорти",
81 + "астроном",
82 + "асфальт",
83 + "атака",
84 + "ателье",
85 + "атлас",
86 + "атом",
87 + "атрибут",
88 + "аудитор",
89 + "аукцион",
90 + "аура",
91 + "афера",
92 + "афиша",
93 + "ахинея",
94 + "ацетон",
95 + "аэропорт",
96 + "бабушка",
97 + "багаж",
98 + "бадья",
99 + "база",
100 + "баклажан",
101 + "балкон",
102 + "бампер",
103 + "банк",
104 + "барон",
105 + "бассейн",
106 + "батарея",
107 + "бахрома",
108 + "башня",
109 + "баян",
110 + "бегство",
111 + "бедро",
112 + "бездна",
113 + "бекон",
114 + "белый",
115 + "бензин",
116 + "берег",
117 + "беседа",
118 + "бетонный",
119 + "биатлон",
120 + "библия",
121 + "бивень",
122 + "бигуди",
123 + "бидон",
124 + "бизнес",
125 + "бикини",
126 + "билет",
127 + "бинокль",
128 + "биология",
129 + "биржа",
130 + "бисер",
131 + "битва",
132 + "бицепс",
133 + "благо",
134 + "бледный",
135 + "близкий",
136 + "блок",
137 + "блуждать",
138 + "блюдо",
139 + "бляха",
140 + "бобер",
141 + "богатый",
142 + "бодрый",
143 + "боевой",
144 + "бокал",
145 + "большой",
146 + "борьба",
147 + "босой",
148 + "ботинок",
149 + "боцман",
150 + "бочка",
151 + "боярин",
152 + "брать",
153 + "бревно",
154 + "бригада",
155 + "бросать",
156 + "брызги",
157 + "брюки",
158 + "бублик",
159 + "бугор",
160 + "будущее",
161 + "буква",
162 + "бульвар",
163 + "бумага",
164 + "бунт",
165 + "бурный",
166 + "бусы",
167 + "бутылка",
168 + "буфет",
169 + "бухта",
170 + "бушлат",
171 + "бывалый",
172 + "быль",
173 + "быстрый",
174 + "быть",
175 + "бюджет",
176 + "бюро",
177 + "бюст",
178 + "вагон",
179 + "важный",
180 + "ваза",
181 + "вакцина",
182 + "валюта",
183 + "вампир",
184 + "ванная",
185 + "вариант",
186 + "вассал",
187 + "вата",
188 + "вафля",
189 + "вахта",
190 + "вдова",
191 + "вдыхать",
192 + "ведущий",
193 + "веер",
194 + "вежливый",
195 + "везти",
196 + "веко",
197 + "великий",
198 + "вена",
199 + "верить",
200 + "веселый",
201 + "ветер",
202 + "вечер",
203 + "вешать",
204 + "вещь",
205 + "веяние",
206 + "взаимный",
207 + "взбучка",
208 + "взвод",
209 + "взгляд",
210 + "вздыхать",
211 + "взлетать",
212 + "взмах",
213 + "взнос",
214 + "взор",
215 + "взрыв",
216 + "взывать",
217 + "взятка",
218 + "вибрация",
219 + "визит",
220 + "вилка",
221 + "вино",
222 + "вирус",
223 + "висеть",
224 + "витрина",
225 + "вихрь",
226 + "вишневый",
227 + "включать",
228 + "вкус",
229 + "власть",
230 + "влечь",
231 + "влияние",
232 + "влюблять",
233 + "внешний",
234 + "внимание",
235 + "внук",
236 + "внятный",
237 + "вода",
238 + "воевать",
239 + "вождь",
240 + "воздух",
241 + "войти",
242 + "вокзал",
243 + "волос",
244 + "вопрос",
245 + "ворота",
246 + "восток",
247 + "впадать",
248 + "впускать",
249 + "врач",
250 + "время",
251 + "вручать",
252 + "всадник",
253 + "всеобщий",
254 + "вспышка",
255 + "встреча",
256 + "вторник",
257 + "вулкан",
258 + "вурдалак",
259 + "входить",
260 + "въезд",
261 + "выбор",
262 + "вывод",
263 + "выгодный",
264 + "выделять",
265 + "выезжать",
266 + "выживать",
267 + "вызывать",
268 + "выигрыш",
269 + "вылезать",
270 + "выносить",
271 + "выпивать",
272 + "высокий",
273 + "выходить",
274 + "вычет",
275 + "вышка",
276 + "выяснять",
277 + "вязать",
278 + "вялый",
279 + "гавань",
280 + "гадать",
281 + "газета",
282 + "гаишник",
283 + "галстук",
284 + "гамма",
285 + "гарантия",
286 + "гастроли",
287 + "гвардия",
288 + "гвоздь",
289 + "гектар",
290 + "гель",
291 + "генерал",
292 + "геолог",
293 + "герой",
294 + "гешефт",
295 + "гибель",
296 + "гигант",
297 + "гильза",
298 + "гимн",
299 + "гипотеза",
300 + "гитара",
301 + "глаз",
302 + "глина",
303 + "глоток",
304 + "глубокий",
305 + "глыба",
306 + "глядеть",
307 + "гнать",
308 + "гнев",
309 + "гнить",
310 + "гном",
311 + "гнуть",
312 + "говорить",
313 + "годовой",
314 + "голова",
315 + "гонка",
316 + "город",
317 + "гость",
318 + "готовый",
319 + "граница",
320 + "грех",
321 + "гриб",
322 + "громкий",
323 + "группа",
324 + "грызть",
325 + "грязный",
326 + "губа",
327 + "гудеть",
328 + "гулять",
329 + "гуманный",
330 + "густой",
331 + "гуща",
332 + "давать",
333 + "далекий",
334 + "дама",
335 + "данные",
336 + "дарить",
337 + "дать",
338 + "дача",
339 + "дверь",
340 + "движение",
341 + "двор",
342 + "дебют",
343 + "девушка",
344 + "дедушка",
345 + "дежурный",
346 + "дезертир",
347 + "действие",
348 + "декабрь",
349 + "дело",
350 + "демократ",
351 + "день",
352 + "депутат",
353 + "держать",
354 + "десяток",
355 + "детский",
356 + "дефицит",
357 + "дешевый",
358 + "деятель",
359 + "джаз",
360 + "джинсы",
361 + "джунгли",
362 + "диалог",
363 + "диван",
364 + "диета",
365 + "дизайн",
366 + "дикий",
367 + "динамика",
368 + "диплом",
369 + "директор",
370 + "диск",
371 + "дитя",
372 + "дичь",
373 + "длинный",
374 + "дневник",
375 + "добрый",
376 + "доверие",
377 + "договор",
378 + "дождь",
379 + "доза",
380 + "документ",
381 + "должен",
382 + "домашний",
383 + "допрос",
384 + "дорога",
385 + "доход",
386 + "доцент",
387 + "дочь",
388 + "дощатый",
389 + "драка",
390 + "древний",
391 + "дрожать",
392 + "друг",
393 + "дрянь",
394 + "дубовый",
395 + "дуга",
396 + "дудка",
397 + "дукат",
398 + "дуло",
399 + "думать",
400 + "дупло",
401 + "дурак",
402 + "дуть",
403 + "духи",
404 + "душа",
405 + "дуэт",
406 + "дымить",
407 + "дыня",
408 + "дыра",
409 + "дыханье",
410 + "дышать",
411 + "дьявол",
412 + "дюжина",
413 + "дюйм",
414 + "дюна",
415 + "дядя",
416 + "дятел",
417 + "егерь",
418 + "единый",
419 + "едкий",
420 + "ежевика",
421 + "ежик",
422 + "езда",
423 + "елка",
424 + "емкость",
425 + "ерунда",
426 + "ехать",
427 + "жадный",
428 + "жажда",
429 + "жалеть",
430 + "жанр",
431 + "жара",
432 + "жать",
433 + "жгучий",
434 + "ждать",
435 + "жевать",
436 + "желание",
437 + "жемчуг",
438 + "женщина",
439 + "жертва",
440 + "жесткий",
441 + "жечь",
442 + "живой",
443 + "жидкость",
444 + "жизнь",
445 + "жилье",
446 + "жирный",
447 + "житель",
448 + "журнал",
449 + "жюри",
450 + "забывать",
451 + "завод",
452 + "загадка",
453 + "задача",
454 + "зажечь",
455 + "зайти",
456 + "закон",
457 + "замечать",
458 + "занимать",
459 + "западный",
460 + "зарплата",
461 + "засыпать",
462 + "затрата",
463 + "захват",
464 + "зацепка",
465 + "зачет",
466 + "защита",
467 + "заявка",
468 + "звать",
469 + "звезда",
470 + "звонить",
471 + "звук",
472 + "здание",
473 + "здешний",
474 + "здоровье",
475 + "зебра",
476 + "зевать",
477 + "зеленый",
478 + "земля",
479 + "зенит",
480 + "зеркало",
481 + "зефир",
482 + "зигзаг",
483 + "зима",
484 + "зиять",
485 + "злак",
486 + "злой",
487 + "змея",
488 + "знать",
489 + "зной",
490 + "зодчий",
491 + "золотой",
492 + "зомби",
493 + "зона",
494 + "зоопарк",
495 + "зоркий",
496 + "зрачок",
497 + "зрение",
498 + "зритель",
499 + "зубной",
500 + "зыбкий",
501 + "зять",
502 + "игла",
503 + "иголка",
504 + "играть",
505 + "идея",
506 + "идиот",
507 + "идол",
508 + "идти",
509 + "иерархия",
510 + "избрать",
511 + "известие",
512 + "изгонять",
513 + "издание",
514 + "излагать",
515 + "изменять",
516 + "износ",
517 + "изоляция",
518 + "изрядный",
519 + "изучать",
520 + "изымать",
521 + "изящный",
522 + "икона",
523 + "икра",
524 + "иллюзия",
525 + "имбирь",
526 + "иметь",
527 + "имидж",
528 + "иммунный",
529 + "империя",
530 + "инвестор",
531 + "индивид",
532 + "инерция",
533 + "инженер",
534 + "иномарка",
535 + "институт",
536 + "интерес",
537 + "инфекция",
538 + "инцидент",
539 + "ипподром",
540 + "ирис",
541 + "ирония",
542 + "искать",
543 + "история",
544 + "исходить",
545 + "исчезать",
546 + "итог",
547 + "июль",
548 + "июнь",
549 + "кабинет",
550 + "кавалер",
551 + "кадр",
552 + "казарма",
553 + "кайф",
554 + "кактус",
555 + "калитка",
556 + "камень",
557 + "канал",
558 + "капитан",
559 + "картина",
560 + "касса",
561 + "катер",
562 + "кафе",
563 + "качество",
564 + "каша",
565 + "каюта",
566 + "квартира",
567 + "квинтет",
568 + "квота",
569 + "кедр",
570 + "кекс",
571 + "кенгуру",
572 + "кепка",
573 + "керосин",
574 + "кетчуп",
575 + "кефир",
576 + "кибитка",
577 + "кивнуть",
578 + "кидать",
579 + "километр",
580 + "кино",
581 + "киоск",
582 + "кипеть",
583 + "кирпич",
584 + "кисть",
585 + "китаец",
586 + "класс",
587 + "клетка",
588 + "клиент",
589 + "клоун",
590 + "клуб",
591 + "клык",
592 + "ключ",
593 + "клятва",
594 + "книга",
595 + "кнопка",
596 + "кнут",
597 + "князь",
598 + "кобура",
599 + "ковер",
600 + "коготь",
601 + "кодекс",
602 + "кожа",
603 + "козел",
604 + "койка",
605 + "коктейль",
606 + "колено",
607 + "компания",
608 + "конец",
609 + "копейка",
610 + "короткий",
611 + "костюм",
612 + "котел",
613 + "кофе",
614 + "кошка",
615 + "красный",
616 + "кресло",
617 + "кричать",
618 + "кровь",
619 + "крупный",
620 + "крыша",
621 + "крючок",
622 + "кубок",
623 + "кувшин",
624 + "кудрявый",
625 + "кузов",
626 + "кукла",
627 + "культура",
628 + "кумир",
629 + "купить",
630 + "курс",
631 + "кусок",
632 + "кухня",
633 + "куча",
634 + "кушать",
635 + "кювет",
636 + "лабиринт",
637 + "лавка",
638 + "лагерь",
639 + "ладонь",
640 + "лазерный",
641 + "лайнер",
642 + "лакей",
643 + "лампа",
644 + "ландшафт",
645 + "лапа",
646 + "ларек",
647 + "ласковый",
648 + "лауреат",
649 + "лачуга",
650 + "лаять",
651 + "лгать",
652 + "лебедь",
653 + "левый",
654 + "легкий",
655 + "ледяной",
656 + "лежать",
657 + "лекция",
658 + "лента",
659 + "лепесток",
660 + "лесной",
661 + "лето",
662 + "лечь",
663 + "леший",
664 + "лживый",
665 + "либерал",
666 + "ливень",
667 + "лига",
668 + "лидер",
669 + "ликовать",
670 + "лиловый",
671 + "лимон",
672 + "линия",
673 + "липа",
674 + "лирика",
675 + "лист",
676 + "литр",
677 + "лифт",
678 + "лихой",
679 + "лицо",
680 + "личный",
681 + "лишний",
682 + "лобовой",
683 + "ловить",
684 + "логика",
685 + "лодка",
686 + "ложка",
687 + "лозунг",
688 + "локоть",
689 + "ломать",
690 + "лоно",
691 + "лопата",
692 + "лорд",
693 + "лось",
694 + "лоток",
695 + "лохматый",
696 + "лошадь",
697 + "лужа",
698 + "лукавый",
699 + "луна",
700 + "лупить",
701 + "лучший",
702 + "лыжный",
703 + "лысый",
704 + "львиный",
705 + "льгота",
706 + "льдина",
707 + "любить",
708 + "людской",
709 + "люстра",
710 + "лютый",
711 + "лягушка",
712 + "магазин",
713 + "мадам",
714 + "мазать",
715 + "майор",
716 + "максимум",
717 + "мальчик",
718 + "манера",
719 + "март",
720 + "масса",
721 + "мать",
722 + "мафия",
723 + "махать",
724 + "мачта",
725 + "машина",
726 + "маэстро",
727 + "маяк",
728 + "мгла",
729 + "мебель",
730 + "медведь",
731 + "мелкий",
732 + "мемуары",
733 + "менять",
734 + "мера",
735 + "место",
736 + "метод",
737 + "механизм",
738 + "мечтать",
739 + "мешать",
740 + "миграция",
741 + "мизинец",
742 + "микрофон",
743 + "миллион",
744 + "минута",
745 + "мировой",
746 + "миссия",
747 + "митинг",
748 + "мишень",
749 + "младший",
750 + "мнение",
751 + "мнимый",
752 + "могила",
753 + "модель",
754 + "мозг",
755 + "мойка",
756 + "мокрый",
757 + "молодой",
758 + "момент",
759 + "монах",
760 + "море",
761 + "мост",
762 + "мотор",
763 + "мохнатый",
764 + "мочь",
765 + "мошенник",
766 + "мощный",
767 + "мрачный",
768 + "мстить",
769 + "мудрый",
770 + "мужчина",
771 + "музыка",
772 + "мука",
773 + "мумия",
774 + "мундир",
775 + "муравей",
776 + "мусор",
777 + "мутный",
778 + "муфта",
779 + "муха",
780 + "мучить",
781 + "мушкетер",
782 + "мыло",
783 + "мысль",
784 + "мыть",
785 + "мычать",
786 + "мышь",
787 + "мэтр",
788 + "мюзикл",
789 + "мягкий",
790 + "мякиш",
791 + "мясо",
792 + "мятый",
793 + "мячик",
794 + "набор",
795 + "навык",
796 + "нагрузка",
797 + "надежда",
798 + "наемный",
799 + "нажать",
800 + "называть",
801 + "наивный",
802 + "накрыть",
803 + "налог",
804 + "намерен",
805 + "наносить",
806 + "написать",
807 + "народ",
808 + "натура",
809 + "наука",
810 + "нация",
811 + "начать",
812 + "небо",
813 + "невеста",
814 + "негодяй",
815 + "неделя",
816 + "нежный",
817 + "незнание",
818 + "нелепый",
819 + "немалый",
820 + "неправда",
821 + "нервный",
822 + "нести",
823 + "нефть",
824 + "нехватка",
825 + "нечистый",
826 + "неясный",
827 + "нива",
828 + "нижний",
829 + "низкий",
830 + "никель",
831 + "нирвана",
832 + "нить",
833 + "ничья",
834 + "ниша",
835 + "нищий",
836 + "новый",
837 + "нога",
838 + "ножницы",
839 + "ноздря",
840 + "ноль",
841 + "номер",
842 + "норма",
843 + "нота",
844 + "ночь",
845 + "ноша",
846 + "ноябрь",
847 + "нрав",
848 + "нужный",
849 + "нутро",
850 + "нынешний",
851 + "нырнуть",
852 + "ныть",
853 + "нюанс",
854 + "нюхать",
855 + "няня",
856 + "оазис",
857 + "обаяние",
858 + "обвинять",
859 + "обгонять",
860 + "обещать",
861 + "обжигать",
862 + "обзор",
863 + "обида",
864 + "область",
865 + "обмен",
866 + "обнимать",
867 + "оборона",
868 + "образ",
869 + "обучение",
870 + "обходить",
871 + "обширный",
872 + "общий",
873 + "объект",
874 + "обычный",
875 + "обязать",
876 + "овальный",
877 + "овес",
878 + "овощи",
879 + "овраг",
880 + "овца",
881 + "овчарка",
882 + "огненный",
883 + "огонь",
884 + "огромный",
885 + "огурец",
886 + "одежда",
887 + "одинокий",
888 + "одобрить",
889 + "ожидать",
890 + "ожог",
891 + "озарение",
892 + "озеро",
893 + "означать",
894 + "оказать",
895 + "океан",
896 + "оклад",
897 + "окно",
898 + "округ",
899 + "октябрь",
900 + "окурок",
901 + "олень",
902 + "опасный",
903 + "операция",
904 + "описать",
905 + "оплата",
906 + "опора",
907 + "оппонент",
908 + "опрос",
909 + "оптимизм",
910 + "опускать",
911 + "опыт",
912 + "орать",
913 + "орбита",
914 + "орган",
915 + "орден",
916 + "орел",
917 + "оригинал",
918 + "оркестр",
919 + "орнамент",
920 + "оружие",
921 + "осадок",
922 + "освещать",
923 + "осень",
924 + "осина",
925 + "осколок",
926 + "осмотр",
927 + "основной",
928 + "особый",
929 + "осуждать",
930 + "отбор",
931 + "отвечать",
932 + "отдать",
933 + "отец",
934 + "отзыв",
935 + "открытие",
936 + "отмечать",
937 + "относить",
938 + "отпуск",
939 + "отрасль",
940 + "отставка",
941 + "оттенок",
942 + "отходить",
943 + "отчет",
944 + "отъезд",
945 + "офицер",
946 + "охапка",
947 + "охота",
948 + "охрана",
949 + "оценка",
950 + "очаг",
951 + "очередь",
952 + "очищать",
953 + "очки",
954 + "ошейник",
955 + "ошибка",
956 + "ощущение",
957 + "павильон",
958 + "падать",
959 + "паек",
960 + "пакет",
961 + "палец",
962 + "память",
963 + "панель",
964 + "папка",
965 + "партия",
966 + "паспорт",
967 + "патрон",
968 + "пауза",
969 + "пафос",
970 + "пахнуть",
971 + "пациент",
972 + "пачка",
973 + "пашня",
974 + "певец",
975 + "педагог",
976 + "пейзаж",
977 + "пельмень",
978 + "пенсия",
979 + "пепел",
980 + "период",
981 + "песня",
982 + "петля",
983 + "пехота",
984 + "печать",
985 + "пешеход",
986 + "пещера",
987 + "пианист",
988 + "пиво",
989 + "пиджак",
990 + "пиковый",
991 + "пилот",
992 + "пионер",
993 + "пирог",
994 + "писать",
995 + "пить",
996 + "пицца",
997 + "пишущий",
998 + "пища",
999 + "план",
1000 + "плечо",
1001 + "плита",
1002 + "плохой",
1003 + "плыть",
1004 + "плюс",
1005 + "пляж",
1006 + "победа",
1007 + "повод",
1008 + "погода",
1009 + "подумать",
1010 + "поехать",
1011 + "пожимать",
1012 + "позиция",
1013 + "поиск",
1014 + "покой",
1015 + "получать",
1016 + "помнить",
1017 + "пони",
1018 + "поощрять",
1019 + "попадать",
1020 + "порядок",
1021 + "пост",
1022 + "поток",
1023 + "похожий",
1024 + "поцелуй",
1025 + "почва",
1026 + "пощечина",
1027 + "поэт",
1028 + "пояснить",
1029 + "право",
1030 + "предмет",
1031 + "проблема",
1032 + "пруд",
1033 + "прыгать",
1034 + "прямой",
1035 + "психолог",
1036 + "птица",
1037 + "публика",
1038 + "пугать",
1039 + "пудра",
1040 + "пузырь",
1041 + "пуля",
1042 + "пункт",
1043 + "пурга",
1044 + "пустой",
1045 + "путь",
1046 + "пухлый",
1047 + "пучок",
1048 + "пушистый",
1049 + "пчела",
1050 + "пшеница",
1051 + "пыль",
1052 + "пытка",
1053 + "пыхтеть",
1054 + "пышный",
1055 + "пьеса",
1056 + "пьяный",
1057 + "пятно",
1058 + "работа",
1059 + "равный",
1060 + "радость",
1061 + "развитие",
1062 + "район",
1063 + "ракета",
1064 + "рамка",
1065 + "ранний",
1066 + "рапорт",
1067 + "рассказ",
1068 + "раунд",
1069 + "рация",
1070 + "рвать",
1071 + "реальный",
1072 + "ребенок",
1073 + "реветь",
1074 + "регион",
1075 + "редакция",
1076 + "реестр",
1077 + "режим",
1078 + "резкий",
1079 + "рейтинг",
1080 + "река",
1081 + "религия",
1082 + "ремонт",
1083 + "рента",
1084 + "реплика",
1085 + "ресурс",
1086 + "реформа",
1087 + "рецепт",
1088 + "речь",
1089 + "решение",
1090 + "ржавый",
1091 + "рисунок",
1092 + "ритм",
1093 + "рифма",
1094 + "робкий",
1095 + "ровный",
1096 + "рогатый",
1097 + "родитель",
1098 + "рождение",
1099 + "розовый",
1100 + "роковой",
1101 + "роль",
1102 + "роман",
1103 + "ронять",
1104 + "рост",
1105 + "рота",
1106 + "роща",
1107 + "рояль",
1108 + "рубль",
1109 + "ругать",
1110 + "руда",
1111 + "ружье",
1112 + "руины",
1113 + "рука",
1114 + "руль",
1115 + "румяный",
1116 + "русский",
1117 + "ручка",
1118 + "рыба",
1119 + "рывок",
1120 + "рыдать",
1121 + "рыжий",
1122 + "рынок",
1123 + "рысь",
1124 + "рыть",
1125 + "рыхлый",
1126 + "рыцарь",
1127 + "рычаг",
1128 + "рюкзак",
1129 + "рюмка",
1130 + "рябой",
1131 + "рядовой",
1132 + "сабля",
1133 + "садовый",
1134 + "сажать",
1135 + "салон",
1136 + "самолет",
1137 + "сани",
1138 + "сапог",
1139 + "сарай",
1140 + "сатира",
1141 + "сауна",
1142 + "сахар",
1143 + "сбегать",
1144 + "сбивать",
1145 + "сбор",
1146 + "сбыт",
1147 + "свадьба",
1148 + "свет",
1149 + "свидание",
1150 + "свобода",
1151 + "связь",
1152 + "сгорать",
1153 + "сдвигать",
1154 + "сеанс",
1155 + "северный",
1156 + "сегмент",
1157 + "седой",
1158 + "сезон",
1159 + "сейф",
1160 + "секунда",
1161 + "сельский",
1162 + "семья",
1163 + "сентябрь",
1164 + "сердце",
1165 + "сеть",
1166 + "сечение",
1167 + "сеять",
1168 + "сигнал",
1169 + "сидеть",
1170 + "сизый",
1171 + "сила",
1172 + "символ",
1173 + "синий",
1174 + "сирота",
1175 + "система",
1176 + "ситуация",
1177 + "сиять",
1178 + "сказать",
1179 + "скважина",
1180 + "скелет",
1181 + "скидка",
1182 + "склад",
1183 + "скорый",
1184 + "скрывать",
1185 + "скучный",
1186 + "слава",
1187 + "слеза",
1188 + "слияние",
1189 + "слово",
1190 + "случай",
1191 + "слышать",
1192 + "слюна",
1193 + "смех",
1194 + "смирение",
1195 + "смотреть",
1196 + "смутный",
1197 + "смысл",
1198 + "смятение",
1199 + "снаряд",
1200 + "снег",
1201 + "снижение",
1202 + "сносить",
1203 + "снять",
1204 + "событие",
1205 + "совет",
1206 + "согласие",
1207 + "сожалеть",
1208 + "сойти",
1209 + "сокол",
1210 + "солнце",
1211 + "сомнение",
1212 + "сонный",
1213 + "сообщать",
1214 + "соперник",
1215 + "сорт",
1216 + "состав",
1217 + "сотня",
1218 + "соус",
1219 + "социолог",
1220 + "сочинять",
1221 + "союз",
1222 + "спать",
1223 + "спешить",
1224 + "спина",
1225 + "сплошной",
1226 + "способ",
1227 + "спутник",
1228 + "средство",
1229 + "срок",
1230 + "срывать",
1231 + "стать",
1232 + "ствол",
1233 + "стена",
1234 + "стихи",
1235 + "сторона",
1236 + "страна",
1237 + "студент",
1238 + "стыд",
1239 + "субъект",
1240 + "сувенир",
1241 + "сугроб",
1242 + "судьба",
1243 + "суета",
1244 + "суждение",
1245 + "сукно",
1246 + "сулить",
1247 + "сумма",
1248 + "сунуть",
1249 + "супруг",
1250 + "суровый",
1251 + "сустав",
1252 + "суть",
1253 + "сухой",
1254 + "суша",
1255 + "существо",
1256 + "сфера",
1257 + "схема",
1258 + "сцена",
1259 + "счастье",
1260 + "счет",
1261 + "считать",
1262 + "сшивать",
1263 + "съезд",
1264 + "сынок",
1265 + "сыпать",
1266 + "сырье",
1267 + "сытый",
1268 + "сыщик",
1269 + "сюжет",
1270 + "сюрприз",
1271 + "таблица",
1272 + "таежный",
1273 + "таинство",
1274 + "тайна",
1275 + "такси",
1276 + "талант",
1277 + "таможня",
1278 + "танец",
1279 + "тарелка",
1280 + "таскать",
1281 + "тахта",
1282 + "тачка",
1283 + "таять",
1284 + "тварь",
1285 + "твердый",
1286 + "творить",
1287 + "театр",
1288 + "тезис",
1289 + "текст",
1290 + "тело",
1291 + "тема",
1292 + "тень",
1293 + "теория",
1294 + "теплый",
1295 + "терять",
1296 + "тесный",
1297 + "тетя",
1298 + "техника",
1299 + "течение",
1300 + "тигр",
1301 + "типичный",
1302 + "тираж",
1303 + "титул",
1304 + "тихий",
1305 + "тишина",
1306 + "ткань",
1307 + "товарищ",
1308 + "толпа",
1309 + "тонкий",
1310 + "топливо",
1311 + "торговля",
1312 + "тоска",
1313 + "точка",
1314 + "тощий",
1315 + "традиция",
1316 + "тревога",
1317 + "трибуна",
1318 + "трогать",
1319 + "труд",
1320 + "трюк",
1321 + "тряпка",
1322 + "туалет",
1323 + "тугой",
1324 + "туловище",
1325 + "туман",
1326 + "тундра",
1327 + "тупой",
1328 + "турнир",
1329 + "тусклый",
1330 + "туфля",
1331 + "туча",
1332 + "туша",
1333 + "тыкать",
1334 + "тысяча",
1335 + "тьма",
1336 + "тюльпан",
1337 + "тюрьма",
1338 + "тяга",
1339 + "тяжелый",
1340 + "тянуть",
1341 + "убеждать",
1342 + "убирать",
1343 + "убогий",
1344 + "убыток",
1345 + "уважение",
1346 + "уверять",
1347 + "увлекать",
1348 + "угнать",
1349 + "угол",
1350 + "угроза",
1351 + "удар",
1352 + "удивлять",
1353 + "удобный",
1354 + "уезд",
1355 + "ужас",
1356 + "ужин",
1357 + "узел",
1358 + "узкий",
1359 + "узнавать",
1360 + "узор",
1361 + "уйма",
1362 + "уклон",
1363 + "укол",
1364 + "уксус",
1365 + "улетать",
1366 + "улица",
1367 + "улучшать",
1368 + "улыбка",
1369 + "уметь",
1370 + "умиление",
1371 + "умный",
1372 + "умолять",
1373 + "умысел",
1374 + "унижать",
1375 + "уносить",
1376 + "уныние",
1377 + "упасть",
1378 + "уплата",
1379 + "упор",
1380 + "упрекать",
1381 + "упускать",
1382 + "уран",
1383 + "урна",
1384 + "уровень",
1385 + "усадьба",
1386 + "усердие",
1387 + "усилие",
1388 + "ускорять",
1389 + "условие",
1390 + "усмешка",
1391 + "уснуть",
1392 + "успеть",
1393 + "усыпать",
1394 + "утешать",
1395 + "утка",
1396 + "уточнять",
1397 + "утро",
1398 + "утюг",
1399 + "уходить",
1400 + "уцелеть",
1401 + "участие",
1402 + "ученый",
1403 + "учитель",
1404 + "ушко",
1405 + "ущерб",
1406 + "уютный",
1407 + "уяснять",
1408 + "фабрика",
1409 + "фаворит",
1410 + "фаза",
1411 + "файл",
1412 + "факт",
1413 + "фамилия",
1414 + "фантазия",
1415 + "фара",
1416 + "фасад",
1417 + "февраль",
1418 + "фельдшер",
1419 + "феномен",
1420 + "ферма",
1421 + "фигура",
1422 + "физика",
1423 + "фильм",
1424 + "финал",
1425 + "фирма",
1426 + "фишка",
1427 + "флаг",
1428 + "флейта",
1429 + "флот",
1430 + "фокус",
1431 + "фольклор",
1432 + "фонд",
1433 + "форма",
1434 + "фото",
1435 + "фраза",
1436 + "фреска",
1437 + "фронт",
1438 + "фрукт",
1439 + "функция",
1440 + "фуражка",
1441 + "футбол",
1442 + "фыркать",
1443 + "халат",
1444 + "хамство",
1445 + "хаос",
1446 + "характер",
1447 + "хата",
1448 + "хватать",
1449 + "хвост",
1450 + "хижина",
1451 + "хилый",
1452 + "химия",
1453 + "хирург",
1454 + "хитрый",
1455 + "хищник",
1456 + "хлам",
1457 + "хлеб",
1458 + "хлопать",
1459 + "хмурый",
1460 + "ходить",
1461 + "хозяин",
1462 + "хоккей",
1463 + "холодный",
1464 + "хороший",
1465 + "хотеть",
1466 + "хохотать",
1467 + "храм",
1468 + "хрен",
1469 + "хриплый",
1470 + "хроника",
1471 + "хрупкий",
1472 + "художник",
1473 + "хулиган",
1474 + "хутор",
1475 + "царь",
1476 + "цвет",
1477 + "цель",
1478 + "цемент",
1479 + "центр",
1480 + "цепь",
1481 + "церковь",
1482 + "цикл",
1483 + "цилиндр",
1484 + "циничный",
1485 + "цирк",
1486 + "цистерна",
1487 + "цитата",
1488 + "цифра",
1489 + "цыпленок",
1490 + "чадо",
1491 + "чайник",
1492 + "часть",
1493 + "чашка",
1494 + "человек",
1495 + "чемодан",
1496 + "чепуха",
1497 + "черный",
1498 + "честь",
1499 + "четкий",
1500 + "чехол",
1501 + "чиновник",
1502 + "число",
1503 + "читать",
1504 + "членство",
1505 + "чреватый",
1506 + "чтение",
1507 + "чувство",
1508 + "чугунный",
1509 + "чудо",
1510 + "чужой",
1511 + "чукча",
1512 + "чулок",
1513 + "чума",
1514 + "чуткий",
1515 + "чучело",
1516 + "чушь",
1517 + "шаблон",
1518 + "шагать",
1519 + "шайка",
1520 + "шакал",
1521 + "шалаш",
1522 + "шампунь",
1523 + "шанс",
1524 + "шапка",
1525 + "шарик",
1526 + "шасси",
1527 + "шатер",
1528 + "шахта",
1529 + "шашлык",
1530 + "швейный",
1531 + "швырять",
1532 + "шевелить",
1533 + "шедевр",
1534 + "шейка",
1535 + "шелковый",
1536 + "шептать",
1537 + "шерсть",
1538 + "шестерка",
1539 + "шикарный",
1540 + "шинель",
1541 + "шипеть",
1542 + "широкий",
1543 + "шить",
1544 + "шишка",
1545 + "шкаф",
1546 + "школа",
1547 + "шкура",
1548 + "шланг",
1549 + "шлем",
1550 + "шлюпка",
1551 + "шляпа",
1552 + "шнур",
1553 + "шоколад",
1554 + "шорох",
1555 + "шоссе",
1556 + "шофер",
1557 + "шпага",
1558 + "шпион",
1559 + "шприц",
1560 + "шрам",
1561 + "шрифт",
1562 + "штаб",
1563 + "штора",
1564 + "штраф",
1565 + "штука",
1566 + "штык",
1567 + "шуба",
1568 + "шуметь",
1569 + "шуршать",
1570 + "шутка",
1571 + "щадить",
1572 + "щедрый",
1573 + "щека",
1574 + "щель",
1575 + "щенок",
1576 + "щепка",
1577 + "щетка",
1578 + "щука",
1579 + "эволюция",
1580 + "эгоизм",
1581 + "экзамен",
1582 + "экипаж",
1583 + "экономия",
1584 + "экран",
1585 + "эксперт",
1586 + "элемент",
1587 + "элита",
1588 + "эмблема",
1589 + "эмигрант",
1590 + "эмоция",
1591 + "энергия",
1592 + "эпизод",
1593 + "эпоха",
1594 + "эскиз",
1595 + "эссе",
1596 + "эстрада",
1597 + "этап",
1598 + "этика",
1599 + "этюд",
1600 + "эфир",
1601 + "эффект",
1602 + "эшелон",
1603 + "юбилей",
1604 + "юбка",
1605 + "южный",
1606 + "юмор",
1607 + "юноша",
1608 + "юрист",
1609 + "яблоко",
1610 + "явление",
1611 + "ягода",
1612 + "ядерный",
1613 + "ядовитый",
1614 + "ядро",
1615 + "язва",
1616 + "язык",
1617 + "яйцо",
1618 + "якорь",
1619 + "январь",
1620 + "японец",
1621 + "яркий",
1622 + "ярмарка",
1623 + "ярость",
1624 + "ярус",
1625 + "ясный",
1626 + "яхта",
1627 + "ячейка",
1628 + "ящик"
1629 + ];
1630 +}
\ No newline at end of file
cw_haven/lib/mnemonics/spanish.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class SpanishMnemonics {
2 + static const words = [
3 + "ábaco",
4 + "abdomen",
5 + "abeja",
6 + "abierto",
7 + "abogado",
8 + "abono",
9 + "aborto",
10 + "abrazo",
11 + "abrir",
12 + "abuelo",
13 + "abuso",
14 + "acabar",
15 + "academia",
16 + "acceso",
17 + "acción",
18 + "aceite",
19 + "acelga",
20 + "acento",
21 + "aceptar",
22 + "ácido",
23 + "aclarar",
24 + "acné",
25 + "acoger",
26 + "acoso",
27 + "activo",
28 + "acto",
29 + "actriz",
30 + "actuar",
31 + "acudir",
32 + "acuerdo",
33 + "acusar",
34 + "adicto",
35 + "admitir",
36 + "adoptar",
37 + "adorno",
38 + "aduana",
39 + "adulto",
40 + "aéreo",
41 + "afectar",
42 + "afición",
43 + "afinar",
44 + "afirmar",
45 + "ágil",
46 + "agitar",
47 + "agonía",
48 + "agosto",
49 + "agotar",
50 + "agregar",
51 + "agrio",
52 + "agua",
53 + "agudo",
54 + "águila",
55 + "aguja",
56 + "ahogo",
57 + "ahorro",
58 + "aire",
59 + "aislar",
60 + "ajedrez",
61 + "ajeno",
62 + "ajuste",
63 + "alacrán",
64 + "alambre",
65 + "alarma",
66 + "alba",
67 + "álbum",
68 + "alcalde",
69 + "aldea",
70 + "alegre",
71 + "alejar",
72 + "alerta",
73 + "aleta",
74 + "alfiler",
75 + "alga",
76 + "algodón",
77 + "aliado",
78 + "aliento",
79 + "alivio",
80 + "alma",
81 + "almeja",
82 + "almíbar",
83 + "altar",
84 + "alteza",
85 + "altivo",
86 + "alto",
87 + "altura",
88 + "alumno",
89 + "alzar",
90 + "amable",
91 + "amante",
92 + "amapola",
93 + "amargo",
94 + "amasar",
95 + "ámbar",
96 + "ámbito",
97 + "ameno",
98 + "amigo",
99 + "amistad",
100 + "amor",
101 + "amparo",
102 + "amplio",
103 + "ancho",
104 + "anciano",
105 + "ancla",
106 + "andar",
107 + "andén",
108 + "anemia",
109 + "ángulo",
110 + "anillo",
111 + "ánimo",
112 + "anís",
113 + "anotar",
114 + "antena",
115 + "antiguo",
116 + "antojo",
117 + "anual",
118 + "anular",
119 + "anuncio",
120 + "añadir",
121 + "añejo",
122 + "año",
123 + "apagar",
124 + "aparato",
125 + "apetito",
126 + "apio",
127 + "aplicar",
128 + "apodo",
129 + "aporte",
130 + "apoyo",
131 + "aprender",
132 + "aprobar",
133 + "apuesta",
134 + "apuro",
135 + "arado",
136 + "araña",
137 + "arar",
138 + "árbitro",
139 + "árbol",
140 + "arbusto",
141 + "archivo",
142 + "arco",
143 + "arder",
144 + "ardilla",
145 + "arduo",
146 + "área",
147 + "árido",
148 + "aries",
149 + "armonía",
150 + "arnés",
151 + "aroma",
152 + "arpa",
153 + "arpón",
154 + "arreglo",
155 + "arroz",
156 + "arruga",
157 + "arte",
158 + "artista",
159 + "asa",
160 + "asado",
161 + "asalto",
162 + "ascenso",
163 + "asegurar",
164 + "aseo",
165 + "asesor",
166 + "asiento",
167 + "asilo",
168 + "asistir",
169 + "asno",
170 + "asombro",
171 + "áspero",
172 + "astilla",
173 + "astro",
174 + "astuto",
175 + "asumir",
176 + "asunto",
177 + "atajo",
178 + "ataque",
179 + "atar",
180 + "atento",
181 + "ateo",
182 + "ático",
183 + "atleta",
184 + "átomo",
185 + "atraer",
186 + "atroz",
187 + "atún",
188 + "audaz",
189 + "audio",
190 + "auge",
191 + "aula",
192 + "aumento",
193 + "ausente",
194 + "autor",
195 + "aval",
196 + "avance",
197 + "avaro",
198 + "ave",
199 + "avellana",
200 + "avena",
201 + "avestruz",
202 + "avión",
203 + "aviso",
204 + "ayer",
205 + "ayuda",
206 + "ayuno",
207 + "azafrán",
208 + "azar",
209 + "azote",
210 + "azúcar",
211 + "azufre",
212 + "azul",
213 + "baba",
214 + "babor",
215 + "bache",
216 + "bahía",
217 + "baile",
218 + "bajar",
219 + "balanza",
220 + "balcón",
221 + "balde",
222 + "bambú",
223 + "banco",
224 + "banda",
225 + "baño",
226 + "barba",
227 + "barco",
228 + "barniz",
229 + "barro",
230 + "báscula",
231 + "bastón",
232 + "basura",
233 + "batalla",
234 + "batería",
235 + "batir",
236 + "batuta",
237 + "baúl",
238 + "bazar",
239 + "bebé",
240 + "bebida",
241 + "bello",
242 + "besar",
243 + "beso",
244 + "bestia",
245 + "bicho",
246 + "bien",
247 + "bingo",
248 + "blanco",
249 + "bloque",
250 + "blusa",
251 + "boa",
252 + "bobina",
253 + "bobo",
254 + "boca",
255 + "bocina",
256 + "boda",
257 + "bodega",
258 + "boina",
259 + "bola",
260 + "bolero",
261 + "bolsa",
262 + "bomba",
263 + "bondad",
264 + "bonito",
265 + "bono",
266 + "bonsái",
267 + "borde",
268 + "borrar",
269 + "bosque",
270 + "bote",
271 + "botín",
272 + "bóveda",
273 + "bozal",
274 + "bravo",
275 + "brazo",
276 + "brecha",
277 + "breve",
278 + "brillo",
279 + "brinco",
280 + "brisa",
281 + "broca",
282 + "broma",
283 + "bronce",
284 + "brote",
285 + "bruja",
286 + "brusco",
287 + "bruto",
288 + "buceo",
289 + "bucle",
290 + "bueno",
291 + "buey",
292 + "bufanda",
293 + "bufón",
294 + "búho",
295 + "buitre",
296 + "bulto",
297 + "burbuja",
298 + "burla",
299 + "burro",
300 + "buscar",
301 + "butaca",
302 + "buzón",
303 + "caballo",
304 + "cabeza",
305 + "cabina",
306 + "cabra",
307 + "cacao",
308 + "cadáver",
309 + "cadena",
310 + "caer",
311 + "café",
312 + "caída",
313 + "caimán",
314 + "caja",
315 + "cajón",
316 + "cal",
317 + "calamar",
318 + "calcio",
319 + "caldo",
320 + "calidad",
321 + "calle",
322 + "calma",
323 + "calor",
324 + "calvo",
325 + "cama",
326 + "cambio",
327 + "camello",
328 + "camino",
329 + "campo",
330 + "cáncer",
331 + "candil",
332 + "canela",
333 + "canguro",
334 + "canica",
335 + "canto",
336 + "caña",
337 + "cañón",
338 + "caoba",
339 + "caos",
340 + "capaz",
341 + "capitán",
342 + "capote",
343 + "captar",
344 + "capucha",
345 + "cara",
346 + "carbón",
347 + "cárcel",
348 + "careta",
349 + "carga",
350 + "cariño",
351 + "carne",
352 + "carpeta",
353 + "carro",
354 + "carta",
355 + "casa",
356 + "casco",
357 + "casero",
358 + "caspa",
359 + "castor",
360 + "catorce",
361 + "catre",
362 + "caudal",
363 + "causa",
364 + "cazo",
365 + "cebolla",
366 + "ceder",
367 + "cedro",
368 + "celda",
369 + "célebre",
370 + "celoso",
371 + "célula",
372 + "cemento",
373 + "ceniza",
374 + "centro",
375 + "cerca",
376 + "cerdo",
377 + "cereza",
378 + "cero",
379 + "cerrar",
380 + "certeza",
381 + "césped",
382 + "cetro",
383 + "chacal",
384 + "chaleco",
385 + "champú",
386 + "chancla",
387 + "chapa",
388 + "charla",
389 + "chico",
390 + "chiste",
391 + "chivo",
392 + "choque",
393 + "choza",
394 + "chuleta",
395 + "chupar",
396 + "ciclón",
397 + "ciego",
398 + "cielo",
399 + "cien",
400 + "cierto",
401 + "cifra",
402 + "cigarro",
403 + "cima",
404 + "cinco",
405 + "cine",
406 + "cinta",
407 + "ciprés",
408 + "circo",
409 + "ciruela",
410 + "cisne",
411 + "cita",
412 + "ciudad",
413 + "clamor",
414 + "clan",
415 + "claro",
416 + "clase",
417 + "clave",
418 + "cliente",
419 + "clima",
420 + "clínica",
421 + "cobre",
422 + "cocción",
423 + "cochino",
424 + "cocina",
425 + "coco",
426 + "código",
427 + "codo",
428 + "cofre",
429 + "coger",
430 + "cohete",
431 + "cojín",
432 + "cojo",
433 + "cola",
434 + "colcha",
435 + "colegio",
436 + "colgar",
437 + "colina",
438 + "collar",
439 + "colmo",
440 + "columna",
441 + "combate",
442 + "comer",
443 + "comida",
444 + "cómodo",
445 + "compra",
446 + "conde",
447 + "conejo",
448 + "conga",
449 + "conocer",
450 + "consejo",
451 + "contar",
452 + "copa",
453 + "copia",
454 + "corazón",
455 + "corbata",
456 + "corcho",
457 + "cordón",
458 + "corona",
459 + "correr",
460 + "coser",
461 + "cosmos",
462 + "costa",
463 + "cráneo",
464 + "cráter",
465 + "crear",
466 + "crecer",
467 + "creído",
468 + "crema",
469 + "cría",
470 + "crimen",
471 + "cripta",
472 + "crisis",
473 + "cromo",
474 + "crónica",
475 + "croqueta",
476 + "crudo",
477 + "cruz",
478 + "cuadro",
479 + "cuarto",
480 + "cuatro",
481 + "cubo",
482 + "cubrir",
483 + "cuchara",
484 + "cuello",
485 + "cuento",
486 + "cuerda",
487 + "cuesta",
488 + "cueva",
489 + "cuidar",
490 + "culebra",
491 + "culpa",
492 + "culto",
493 + "cumbre",
494 + "cumplir",
495 + "cuna",
496 + "cuneta",
497 + "cuota",
498 + "cupón",
499 + "cúpula",
500 + "curar",
501 + "curioso",
502 + "curso",
503 + "curva",
504 + "cutis",
505 + "dama",
506 + "danza",
507 + "dar",
508 + "dardo",
509 + "dátil",
510 + "deber",
511 + "débil",
512 + "década",
513 + "decir",
514 + "dedo",
515 + "defensa",
516 + "definir",
517 + "dejar",
518 + "delfín",
519 + "delgado",
520 + "delito",
521 + "demora",
522 + "denso",
523 + "dental",
524 + "deporte",
525 + "derecho",
526 + "derrota",
527 + "desayuno",
528 + "deseo",
529 + "desfile",
530 + "desnudo",
531 + "destino",
532 + "desvío",
533 + "detalle",
534 + "detener",
535 + "deuda",
536 + "día",
537 + "diablo",
538 + "diadema",
539 + "diamante",
540 + "diana",
541 + "diario",
542 + "dibujo",
543 + "dictar",
544 + "diente",
545 + "dieta",
546 + "diez",
547 + "difícil",
548 + "digno",
549 + "dilema",
550 + "diluir",
551 + "dinero",
552 + "directo",
553 + "dirigir",
554 + "disco",
555 + "diseño",
556 + "disfraz",
557 + "diva",
558 + "divino",
559 + "doble",
560 + "doce",
561 + "dolor",
562 + "domingo",
563 + "don",
564 + "donar",
565 + "dorado",
566 + "dormir",
567 + "dorso",
568 + "dos",
569 + "dosis",
570 + "dragón",
571 + "droga",
572 + "ducha",
573 + "duda",
574 + "duelo",
575 + "dueño",
576 + "dulce",
577 + "dúo",
578 + "duque",
579 + "durar",
580 + "dureza",
581 + "duro",
582 + "ébano",
583 + "ebrio",
584 + "echar",
585 + "eco",
586 + "ecuador",
587 + "edad",
588 + "edición",
589 + "edificio",
590 + "editor",
591 + "educar",
592 + "efecto",
593 + "eficaz",
594 + "eje",
595 + "ejemplo",
596 + "elefante",
597 + "elegir",
598 + "elemento",
599 + "elevar",
600 + "elipse",
601 + "élite",
602 + "elixir",
603 + "elogio",
604 + "eludir",
605 + "embudo",
606 + "emitir",
607 + "emoción",
608 + "empate",
609 + "empeño",
610 + "empleo",
611 + "empresa",
612 + "enano",
613 + "encargo",
614 + "enchufe",
615 + "encía",
616 + "enemigo",
617 + "enero",
618 + "enfado",
619 + "enfermo",
620 + "engaño",
621 + "enigma",
622 + "enlace",
623 + "enorme",
624 + "enredo",
625 + "ensayo",
626 + "enseñar",
627 + "entero",
628 + "entrar",
629 + "envase",
630 + "envío",
631 + "época",
632 + "equipo",
633 + "erizo",
634 + "escala",
635 + "escena",
636 + "escolar",
637 + "escribir",
638 + "escudo",
639 + "esencia",
640 + "esfera",
641 + "esfuerzo",
642 + "espada",
643 + "espejo",
644 + "espía",
645 + "esposa",
646 + "espuma",
647 + "esquí",
648 + "estar",
649 + "este",
650 + "estilo",
651 + "estufa",
652 + "etapa",
653 + "eterno",
654 + "ética",
655 + "etnia",
656 + "evadir",
657 + "evaluar",
658 + "evento",
659 + "evitar",
660 + "exacto",
661 + "examen",
662 + "exceso",
663 + "excusa",
664 + "exento",
665 + "exigir",
666 + "exilio",
667 + "existir",
668 + "éxito",
669 + "experto",
670 + "explicar",
671 + "exponer",
672 + "extremo",
673 + "fábrica",
674 + "fábula",
675 + "fachada",
676 + "fácil",
677 + "factor",
678 + "faena",
679 + "faja",
680 + "falda",
681 + "fallo",
682 + "falso",
683 + "faltar",
684 + "fama",
685 + "familia",
686 + "famoso",
687 + "faraón",
688 + "farmacia",
689 + "farol",
690 + "farsa",
691 + "fase",
692 + "fatiga",
693 + "fauna",
694 + "favor",
695 + "fax",
696 + "febrero",
697 + "fecha",
698 + "feliz",
699 + "feo",
700 + "feria",
701 + "feroz",
702 + "fértil",
703 + "fervor",
704 + "festín",
705 + "fiable",
706 + "fianza",
707 + "fiar",
708 + "fibra",
709 + "ficción",
710 + "ficha",
711 + "fideo",
712 + "fiebre",
713 + "fiel",
714 + "fiera",
715 + "fiesta",
716 + "figura",
717 + "fijar",
718 + "fijo",
719 + "fila",
720 + "filete",
721 + "filial",
722 + "filtro",
723 + "fin",
724 + "finca",
725 + "fingir",
726 + "finito",
727 + "firma",
728 + "flaco",
729 + "flauta",
730 + "flecha",
731 + "flor",
732 + "flota",
733 + "fluir",
734 + "flujo",
735 + "flúor",
736 + "fobia",
737 + "foca",
738 + "fogata",
739 + "fogón",
740 + "folio",
741 + "folleto",
742 + "fondo",
743 + "forma",
744 + "forro",
745 + "fortuna",
746 + "forzar",
747 + "fosa",
748 + "foto",
749 + "fracaso",
750 + "frágil",
751 + "franja",
752 + "frase",
753 + "fraude",
754 + "freír",
755 + "freno",
756 + "fresa",
757 + "frío",
758 + "frito",
759 + "fruta",
760 + "fuego",
761 + "fuente",
762 + "fuerza",
763 + "fuga",
764 + "fumar",
765 + "función",
766 + "funda",
767 + "furgón",
768 + "furia",
769 + "fusil",
770 + "fútbol",
771 + "futuro",
772 + "gacela",
773 + "gafas",
774 + "gaita",
775 + "gajo",
776 + "gala",
777 + "galería",
778 + "gallo",
779 + "gamba",
780 + "ganar",
781 + "gancho",
782 + "ganga",
783 + "ganso",
784 + "garaje",
785 + "garza",
786 + "gasolina",
787 + "gastar",
788 + "gato",
789 + "gavilán",
790 + "gemelo",
791 + "gemir",
792 + "gen",
793 + "género",
794 + "genio",
795 + "gente",
796 + "geranio",
797 + "gerente",
798 + "germen",
799 + "gesto",
800 + "gigante",
801 + "gimnasio",
802 + "girar",
803 + "giro",
804 + "glaciar",
805 + "globo",
806 + "gloria",
807 + "gol",
808 + "golfo",
809 + "goloso",
810 + "golpe",
811 + "goma",
812 + "gordo",
813 + "gorila",
814 + "gorra",
815 + "gota",
816 + "goteo",
817 + "gozar",
818 + "grada",
819 + "gráfico",
820 + "grano",
821 + "grasa",
822 + "gratis",
823 + "grave",
824 + "grieta",
825 + "grillo",
826 + "gripe",
827 + "gris",
828 + "grito",
829 + "grosor",
830 + "grúa",
831 + "grueso",
832 + "grumo",
833 + "grupo",
834 + "guante",
835 + "guapo",
836 + "guardia",
837 + "guerra",
838 + "guía",
839 + "guiño",
840 + "guion",
841 + "guiso",
842 + "guitarra",
843 + "gusano",
844 + "gustar",
845 + "haber",
846 + "hábil",
847 + "hablar",
848 + "hacer",
849 + "hacha",
850 + "hada",
851 + "hallar",
852 + "hamaca",
853 + "harina",
854 + "haz",
855 + "hazaña",
856 + "hebilla",
857 + "hebra",
858 + "hecho",
859 + "helado",
860 + "helio",
861 + "hembra",
862 + "herir",
863 + "hermano",
864 + "héroe",
865 + "hervir",
866 + "hielo",
867 + "hierro",
868 + "hígado",
869 + "higiene",
870 + "hijo",
871 + "himno",
872 + "historia",
873 + "hocico",
874 + "hogar",
875 + "hoguera",
876 + "hoja",
877 + "hombre",
878 + "hongo",
879 + "honor",
880 + "honra",
881 + "hora",
882 + "hormiga",
883 + "horno",
884 + "hostil",
885 + "hoyo",
886 + "hueco",
887 + "huelga",
888 + "huerta",
889 + "hueso",
890 + "huevo",
891 + "huida",
892 + "huir",
893 + "humano",
894 + "húmedo",
895 + "humilde",
896 + "humo",
897 + "hundir",
898 + "huracán",
899 + "hurto",
900 + "icono",
901 + "ideal",
902 + "idioma",
903 + "ídolo",
904 + "iglesia",
905 + "iglú",
906 + "igual",
907 + "ilegal",
908 + "ilusión",
909 + "imagen",
910 + "imán",
911 + "imitar",
912 + "impar",
913 + "imperio",
914 + "imponer",
915 + "impulso",
916 + "incapaz",
917 + "índice",
918 + "inerte",
919 + "infiel",
920 + "informe",
921 + "ingenio",
922 + "inicio",
923 + "inmenso",
924 + "inmune",
925 + "innato",
926 + "insecto",
927 + "instante",
928 + "interés",
929 + "íntimo",
930 + "intuir",
931 + "inútil",
932 + "invierno",
933 + "ira",
934 + "iris",
935 + "ironía",
936 + "isla",
937 + "islote",
938 + "jabalí",
939 + "jabón",
940 + "jamón",
941 + "jarabe",
942 + "jardín",
943 + "jarra",
944 + "jaula",
945 + "jazmín",
946 + "jefe",
947 + "jeringa",
948 + "jinete",
949 + "jornada",
950 + "joroba",
951 + "joven",
952 + "joya",
953 + "juerga",
954 + "jueves",
955 + "juez",
956 + "jugador",
957 + "jugo",
958 + "juguete",
959 + "juicio",
960 + "junco",
961 + "jungla",
962 + "junio",
963 + "juntar",
964 + "júpiter",
965 + "jurar",
966 + "justo",
967 + "juvenil",
968 + "juzgar",
969 + "kilo",
970 + "koala",
971 + "labio",
972 + "lacio",
973 + "lacra",
974 + "lado",
975 + "ladrón",
976 + "lagarto",
977 + "lágrima",
978 + "laguna",
979 + "laico",
980 + "lamer",
981 + "lámina",
982 + "lámpara",
983 + "lana",
984 + "lancha",
985 + "langosta",
986 + "lanza",
987 + "lápiz",
988 + "largo",
989 + "larva",
990 + "lástima",
991 + "lata",
992 + "látex",
993 + "latir",
994 + "laurel",
995 + "lavar",
996 + "lazo",
997 + "leal",
998 + "lección",
999 + "leche",
1000 + "lector",
1001 + "leer",
1002 + "legión",
1003 + "legumbre",
1004 + "lejano",
1005 + "lengua",
1006 + "lento",
1007 + "leña",
1008 + "león",
1009 + "leopardo",
1010 + "lesión",
1011 + "letal",
1012 + "letra",
1013 + "leve",
1014 + "leyenda",
1015 + "libertad",
1016 + "libro",
1017 + "licor",
1018 + "líder",
1019 + "lidiar",
1020 + "lienzo",
1021 + "liga",
1022 + "ligero",
1023 + "lima",
1024 + "límite",
1025 + "limón",
1026 + "limpio",
1027 + "lince",
1028 + "lindo",
1029 + "línea",
1030 + "lingote",
1031 + "lino",
1032 + "linterna",
1033 + "líquido",
1034 + "liso",
1035 + "lista",
1036 + "litera",
1037 + "litio",
1038 + "litro",
1039 + "llaga",
1040 + "llama",
1041 + "llanto",
1042 + "llave",
1043 + "llegar",
1044 + "llenar",
1045 + "llevar",
1046 + "llorar",
1047 + "llover",
1048 + "lluvia",
1049 + "lobo",
1050 + "loción",
1051 + "loco",
1052 + "locura",
1053 + "lógica",
1054 + "logro",
1055 + "lombriz",
1056 + "lomo",
1057 + "lonja",
1058 + "lote",
1059 + "lucha",
1060 + "lucir",
1061 + "lugar",
1062 + "lujo",
1063 + "luna",
1064 + "lunes",
1065 + "lupa",
1066 + "lustro",
1067 + "luto",
1068 + "luz",
1069 + "maceta",
1070 + "macho",
1071 + "madera",
1072 + "madre",
1073 + "maduro",
1074 + "maestro",
1075 + "mafia",
1076 + "magia",
1077 + "mago",
1078 + "maíz",
1079 + "maldad",
1080 + "maleta",
1081 + "malla",
1082 + "malo",
1083 + "mamá",
1084 + "mambo",
1085 + "mamut",
1086 + "manco",
1087 + "mando",
1088 + "manejar",
1089 + "manga",
1090 + "maniquí",
1091 + "manjar",
1092 + "mano",
1093 + "manso",
1094 + "manta",
1095 + "mañana",
1096 + "mapa",
1097 + "máquina",
1098 + "mar",
1099 + "marco",
1100 + "marea",
1101 + "marfil",
1102 + "margen",
1103 + "marido",
1104 + "mármol",
1105 + "marrón",
1106 + "martes",
1107 + "marzo",
1108 + "masa",
1109 + "máscara",
1110 + "masivo",
1111 + "matar",
1112 + "materia",
1113 + "matiz",
1114 + "matriz",
1115 + "máximo",
1116 + "mayor",
1117 + "mazorca",
1118 + "mecha",
1119 + "medalla",
1120 + "medio",
1121 + "médula",
1122 + "mejilla",
1123 + "mejor",
1124 + "melena",
1125 + "melón",
1126 + "memoria",
1127 + "menor",
1128 + "mensaje",
1129 + "mente",
1130 + "menú",
1131 + "mercado",
1132 + "merengue",
1133 + "mérito",
1134 + "mes",
1135 + "mesón",
1136 + "meta",
1137 + "meter",
1138 + "método",
1139 + "metro",
1140 + "mezcla",
1141 + "miedo",
1142 + "miel",
1143 + "miembro",
1144 + "miga",
1145 + "mil",
1146 + "milagro",
1147 + "militar",
1148 + "millón",
1149 + "mimo",
1150 + "mina",
1151 + "minero",
1152 + "mínimo",
1153 + "minuto",
1154 + "miope",
1155 + "mirar",
1156 + "misa",
1157 + "miseria",
1158 + "misil",
1159 + "mismo",
1160 + "mitad",
1161 + "mito",
1162 + "mochila",
1163 + "moción",
1164 + "moda",
1165 + "modelo",
1166 + "moho",
1167 + "mojar",
1168 + "molde",
1169 + "moler",
1170 + "molino",
1171 + "momento",
1172 + "momia",
1173 + "monarca",
1174 + "moneda",
1175 + "monja",
1176 + "monto",
1177 + "moño",
1178 + "morada",
1179 + "morder",
1180 + "moreno",
1181 + "morir",
1182 + "morro",
1183 + "morsa",
1184 + "mortal",
1185 + "mosca",
1186 + "mostrar",
1187 + "motivo",
1188 + "mover",
1189 + "móvil",
1190 + "mozo",
1191 + "mucho",
1192 + "mudar",
1193 + "mueble",
1194 + "muela",
1195 + "muerte",
1196 + "muestra",
1197 + "mugre",
1198 + "mujer",
1199 + "mula",
1200 + "muleta",
1201 + "multa",
1202 + "mundo",
1203 + "muñeca",
1204 + "mural",
1205 + "muro",
1206 + "músculo",
1207 + "museo",
1208 + "musgo",
1209 + "música",
1210 + "muslo",
1211 + "nácar",
1212 + "nación",
1213 + "nadar",
1214 + "naipe",
1215 + "naranja",
1216 + "nariz",
1217 + "narrar",
1218 + "nasal",
1219 + "natal",
1220 + "nativo",
1221 + "natural",
1222 + "náusea",
1223 + "naval",
1224 + "nave",
1225 + "navidad",
1226 + "necio",
1227 + "néctar",
1228 + "negar",
1229 + "negocio",
1230 + "negro",
1231 + "neón",
1232 + "nervio",
1233 + "neto",
1234 + "neutro",
1235 + "nevar",
1236 + "nevera",
1237 + "nicho",
1238 + "nido",
1239 + "niebla",
1240 + "nieto",
1241 + "niñez",
1242 + "niño",
1243 + "nítido",
1244 + "nivel",
1245 + "nobleza",
1246 + "noche",
1247 + "nómina",
1248 + "noria",
1249 + "norma",
1250 + "norte",
1251 + "nota",
1252 + "noticia",
1253 + "novato",
1254 + "novela",
1255 + "novio",
1256 + "nube",
1257 + "nuca",
1258 + "núcleo",
1259 + "nudillo",
1260 + "nudo",
1261 + "nuera",
1262 + "nueve",
1263 + "nuez",
1264 + "nulo",
1265 + "número",
1266 + "nutria",
1267 + "oasis",
1268 + "obeso",
1269 + "obispo",
1270 + "objeto",
1271 + "obra",
1272 + "obrero",
1273 + "observar",
1274 + "obtener",
1275 + "obvio",
1276 + "oca",
1277 + "ocaso",
1278 + "océano",
1279 + "ochenta",
1280 + "ocho",
1281 + "ocio",
1282 + "ocre",
1283 + "octavo",
1284 + "octubre",
1285 + "oculto",
1286 + "ocupar",
1287 + "ocurrir",
1288 + "odiar",
1289 + "odio",
1290 + "odisea",
1291 + "oeste",
1292 + "ofensa",
1293 + "oferta",
1294 + "oficio",
1295 + "ofrecer",
1296 + "ogro",
1297 + "oído",
1298 + "oír",
1299 + "ojo",
1300 + "ola",
1301 + "oleada",
1302 + "olfato",
1303 + "olivo",
1304 + "olla",
1305 + "olmo",
1306 + "olor",
1307 + "olvido",
1308 + "ombligo",
1309 + "onda",
1310 + "onza",
1311 + "opaco",
1312 + "opción",
1313 + "ópera",
1314 + "opinar",
1315 + "oponer",
1316 + "optar",
1317 + "óptica",
1318 + "opuesto",
1319 + "oración",
1320 + "orador",
1321 + "oral",
1322 + "órbita",
1323 + "orca",
1324 + "orden",
1325 + "oreja",
1326 + "órgano",
1327 + "orgía",
1328 + "orgullo",
1329 + "oriente",
1330 + "origen",
1331 + "orilla",
1332 + "oro",
1333 + "orquesta",
1334 + "oruga",
1335 + "osadía",
1336 + "oscuro",
1337 + "osezno",
1338 + "oso",
1339 + "ostra",
1340 + "otoño",
1341 + "otro",
1342 + "oveja",
1343 + "óvulo",
1344 + "óxido",
1345 + "oxígeno",
1346 + "oyente",
1347 + "ozono",
1348 + "pacto",
1349 + "padre",
1350 + "paella",
1351 + "página",
1352 + "pago",
1353 + "país",
1354 + "pájaro",
1355 + "palabra",
1356 + "palco",
1357 + "paleta",
1358 + "pálido",
1359 + "palma",
1360 + "paloma",
1361 + "palpar",
1362 + "pan",
1363 + "panal",
1364 + "pánico",
1365 + "pantera",
1366 + "pañuelo",
1367 + "papá",
1368 + "papel",
1369 + "papilla",
1370 + "paquete",
1371 + "parar",
1372 + "parcela",
1373 + "pared",
1374 + "parir",
1375 + "paro",
1376 + "párpado",
1377 + "parque",
1378 + "párrafo",
1379 + "parte",
1380 + "pasar",
1381 + "paseo",
1382 + "pasión",
1383 + "paso",
1384 + "pasta",
1385 + "pata",
1386 + "patio",
1387 + "patria",
1388 + "pausa",
1389 + "pauta",
1390 + "pavo",
1391 + "payaso",
1392 + "peatón",
1393 + "pecado",
1394 + "pecera",
1395 + "pecho",
1396 + "pedal",
1397 + "pedir",
1398 + "pegar",
1399 + "peine",
1400 + "pelar",
1401 + "peldaño",
1402 + "pelea",
1403 + "peligro",
1404 + "pellejo",
1405 + "pelo",
1406 + "peluca",
1407 + "pena",
1408 + "pensar",
1409 + "peñón",
1410 + "peón",
1411 + "peor",
1412 + "pepino",
1413 + "pequeño",
1414 + "pera",
1415 + "percha",
1416 + "perder",
1417 + "pereza",
1418 + "perfil",
1419 + "perico",
1420 + "perla",
1421 + "permiso",
1422 + "perro",
1423 + "persona",
1424 + "pesa",
1425 + "pesca",
1426 + "pésimo",
1427 + "pestaña",
1428 + "pétalo",
1429 + "petróleo",
1430 + "pez",
1431 + "pezuña",
1432 + "picar",
1433 + "pichón",
1434 + "pie",
1435 + "piedra",
1436 + "pierna",
1437 + "pieza",
1438 + "pijama",
1439 + "pilar",
1440 + "piloto",
1441 + "pimienta",
1442 + "pino",
1443 + "pintor",
1444 + "pinza",
1445 + "piña",
1446 + "piojo",
1447 + "pipa",
1448 + "pirata",
1449 + "pisar",
1450 + "piscina",
1451 + "piso",
1452 + "pista",
1453 + "pitón",
1454 + "pizca",
1455 + "placa",
1456 + "plan",
1457 + "plata",
1458 + "playa",
1459 + "plaza",
1460 + "pleito",
1461 + "pleno",
1462 + "plomo",
1463 + "pluma",
1464 + "plural",
1465 + "pobre",
1466 + "poco",
1467 + "poder",
1468 + "podio",
1469 + "poema",
1470 + "poesía",
1471 + "poeta",
1472 + "polen",
1473 + "policía",
1474 + "pollo",
1475 + "polvo",
1476 + "pomada",
1477 + "pomelo",
1478 + "pomo",
1479 + "pompa",
1480 + "poner",
1481 + "porción",
1482 + "portal",
1483 + "posada",
1484 + "poseer",
1485 + "posible",
1486 + "poste",
1487 + "potencia",
1488 + "potro",
1489 + "pozo",
1490 + "prado",
1491 + "precoz",
1492 + "pregunta",
1493 + "premio",
1494 + "prensa",
1495 + "preso",
1496 + "previo",
1497 + "primo",
1498 + "príncipe",
1499 + "prisión",
1500 + "privar",
1501 + "proa",
1502 + "probar",
1503 + "proceso",
1504 + "producto",
1505 + "proeza",
1506 + "profesor",
1507 + "programa",
1508 + "prole",
1509 + "promesa",
1510 + "pronto",
1511 + "propio",
1512 + "próximo",
1513 + "prueba",
1514 + "público",
1515 + "puchero",
1516 + "pudor",
1517 + "pueblo",
1518 + "puerta",
1519 + "puesto",
1520 + "pulga",
1521 + "pulir",
1522 + "pulmón",
1523 + "pulpo",
1524 + "pulso",
1525 + "puma",
1526 + "punto",
1527 + "puñal",
1528 + "puño",
1529 + "pupa",
1530 + "pupila",
1531 + "puré",
1532 + "quedar",
1533 + "queja",
1534 + "quemar",
1535 + "querer",
1536 + "queso",
1537 + "quieto",
1538 + "química",
1539 + "quince",
1540 + "quitar",
1541 + "rábano",
1542 + "rabia",
1543 + "rabo",
1544 + "ración",
1545 + "radical",
1546 + "raíz",
1547 + "rama",
1548 + "rampa",
1549 + "rancho",
1550 + "rango",
1551 + "rapaz",
1552 + "rápido",
1553 + "rapto",
1554 + "rasgo",
1555 + "raspa",
1556 + "rato",
1557 + "rayo",
1558 + "raza",
1559 + "razón",
1560 + "reacción",
1561 + "realidad",
1562 + "rebaño",
1563 + "rebote",
1564 + "recaer",
1565 + "receta",
1566 + "rechazo",
1567 + "recoger",
1568 + "recreo",
1569 + "recto",
1570 + "recurso",
1571 + "red",
1572 + "redondo",
1573 + "reducir",
1574 + "reflejo",
1575 + "reforma",
1576 + "refrán",
1577 + "refugio",
1578 + "regalo",
1579 + "regir",
1580 + "regla",
1581 + "regreso",
1582 + "rehén",
1583 + "reino",
1584 + "reír",
1585 + "reja",
1586 + "relato",
1587 + "relevo",
1588 + "relieve",
1589 + "relleno",
1590 + "reloj",
1591 + "remar",
1592 + "remedio",
1593 + "remo",
1594 + "rencor",
1595 + "rendir",
1596 + "renta",
1597 + "reparto",
1598 + "repetir",
1599 + "reposo",
1600 + "reptil",
1601 + "res",
1602 + "rescate",
1603 + "resina",
1604 + "respeto",
1605 + "resto",
1606 + "resumen",
1607 + "retiro",
1608 + "retorno",
1609 + "retrato",
1610 + "reunir",
1611 + "revés",
1612 + "revista",
1613 + "rey",
1614 + "rezar",
1615 + "rico",
1616 + "riego",
1617 + "rienda",
1618 + "riesgo",
1619 + "rifa",
1620 + "rígido",
1621 + "rigor",
1622 + "rincón",
1623 + "riñón",
1624 + "río",
1625 + "riqueza",
1626 + "risa",
1627 + "ritmo",
1628 + "rito"
1629 + ];
1630 +}
\ No newline at end of file
cw_haven/lib/pending_haven_transaction.dart new
+48
@@ -0,0 +1,48 @@
1 +import 'package:cw_haven/api/structs/pending_transaction.dart';
2 +import 'package:cw_haven/api/transaction_history.dart'
3 + as haven_transaction_history;
4 +import 'package:cw_core/crypto_currency.dart';
5 +import 'package:cake_wallet/core/amount_converter.dart';
6 +import 'package:cw_core/pending_transaction.dart';
7 +
8 +class DoubleSpendException implements Exception {
9 + DoubleSpendException();
10 +
11 + @override
12 + String toString() =>
13 + 'This transaction cannot be committed. This can be due to many reasons including the wallet not being synced, there is not enough XMR in your available balance, or previous transactions are not yet fully processed.';
14 +}
15 +
16 +class PendingHavenTransaction with PendingTransaction {
17 + PendingHavenTransaction(this.pendingTransactionDescription, this.cryptoCurrency);
18 +
19 + final PendingTransactionDescription pendingTransactionDescription;
20 + final CryptoCurrency cryptoCurrency;
21 +
22 + @override
23 + String get id => pendingTransactionDescription.hash;
24 +
25 + @override
26 + String get amountFormatted => AmountConverter.amountIntToString(
27 + cryptoCurrency, pendingTransactionDescription.amount);
28 +
29 + @override
30 + String get feeFormatted => AmountConverter.amountIntToString(
31 + cryptoCurrency, pendingTransactionDescription.fee);
32 +
33 + @override
34 + Future<void> commit() async {
35 + try {
36 + haven_transaction_history.commitTransactionFromPointerAddress(
37 + address: pendingTransactionDescription.pointerAddress);
38 + } catch (e) {
39 + final message = e.toString();
40 +
41 + if (message.contains('Reason: double spend')) {
42 + throw DoubleSpendException();
43 + }
44 +
45 + rethrow;
46 + }
47 + }
48 +}
cw_haven/lib/update_haven_rate.dart new
+15
@@ -0,0 +1,15 @@
1 +//import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
2 +import 'package:cw_core/crypto_currency.dart';
3 +import 'package:cw_core/monero_amount_format.dart';
4 +import 'package:cw_haven/balance_list.dart';
5 +
6 +//Future<void> updateHavenRate(FiatConversionStore fiatConversionStore) async {
7 +// final rate = getRate();
8 +// final base = rate.firstWhere((row) => row.getAssetType() == 'XUSD', orElse: () => null);
9 +// rate.forEach((row) {
10 +// final cur = CryptoCurrency.fromString(row.getAssetType());
11 +// final baseRate = moneroAmountToDouble(amount: base.getRate());
12 +// final rowRate = moneroAmountToDouble(amount: row.getRate());
13 +// fiatConversionStore.prices[cur] = baseRate * rowRate;
14 +// });
15 +//}
\ No newline at end of file
cw_haven/pubspec.lock new
+609
@@ -0,0 +1,609 @@
1 +# Generated by pub
2 +# See https://dart.dev/tools/pub/glossary#lockfile
3 +packages:
4 + _fe_analyzer_shared:
5 + dependency: transitive
6 + description:
7 + name: _fe_analyzer_shared
8 + url: "https://pub.dartlang.org"
9 + source: hosted
10 + version: "14.0.0"
11 + analyzer:
12 + dependency: transitive
13 + description:
14 + name: analyzer
15 + url: "https://pub.dartlang.org"
16 + source: hosted
17 + version: "0.41.2"
18 + args:
19 + dependency: transitive
20 + description:
21 + name: args
22 + url: "https://pub.dartlang.org"
23 + source: hosted
24 + version: "1.6.0"
25 + asn1lib:
26 + dependency: transitive
27 + description:
28 + name: asn1lib
29 + url: "https://pub.dartlang.org"
30 + source: hosted
31 + version: "0.8.1"
32 + async:
33 + dependency: transitive
34 + description:
35 + name: async
36 + url: "https://pub.dartlang.org"
37 + source: hosted
38 + version: "2.5.0"
39 + boolean_selector:
40 + dependency: transitive
41 + description:
42 + name: boolean_selector
43 + url: "https://pub.dartlang.org"
44 + source: hosted
45 + version: "2.1.0"
46 + build:
47 + dependency: transitive
48 + description:
49 + name: build
50 + url: "https://pub.dartlang.org"
51 + source: hosted
52 + version: "1.6.2"
53 + build_config:
54 + dependency: transitive
55 + description:
56 + name: build_config
57 + url: "https://pub.dartlang.org"
58 + source: hosted
59 + version: "0.4.6"
60 + build_daemon:
61 + dependency: transitive
62 + description:
63 + name: build_daemon
64 + url: "https://pub.dartlang.org"
65 + source: hosted
66 + version: "2.1.10"
67 + build_resolvers:
68 + dependency: "direct dev"
69 + description:
70 + name: build_resolvers
71 + url: "https://pub.dartlang.org"
72 + source: hosted
73 + version: "1.5.3"
74 + build_runner:
75 + dependency: "direct dev"
76 + description:
77 + name: build_runner
78 + url: "https://pub.dartlang.org"
79 + source: hosted
80 + version: "1.11.5"
81 + build_runner_core:
82 + dependency: transitive
83 + description:
84 + name: build_runner_core
85 + url: "https://pub.dartlang.org"
86 + source: hosted
87 + version: "6.1.10"
88 + built_collection:
89 + dependency: transitive
90 + description:
91 + name: built_collection
92 + url: "https://pub.dartlang.org"
93 + source: hosted
94 + version: "5.1.1"
95 + built_value:
96 + dependency: transitive
97 + description:
98 + name: built_value
99 + url: "https://pub.dartlang.org"
100 + source: hosted
101 + version: "8.1.4"
102 + characters:
103 + dependency: transitive
104 + description:
105 + name: characters
106 + url: "https://pub.dartlang.org"
107 + source: hosted
108 + version: "1.1.0"
109 + charcode:
110 + dependency: transitive
111 + description:
112 + name: charcode
113 + url: "https://pub.dartlang.org"
114 + source: hosted
115 + version: "1.2.0"
116 + checked_yaml:
117 + dependency: transitive
118 + description:
119 + name: checked_yaml
120 + url: "https://pub.dartlang.org"
121 + source: hosted
122 + version: "1.0.4"
123 + cli_util:
124 + dependency: transitive
125 + description:
126 + name: cli_util
127 + url: "https://pub.dartlang.org"
128 + source: hosted
129 + version: "0.3.5"
130 + clock:
131 + dependency: transitive
132 + description:
133 + name: clock
134 + url: "https://pub.dartlang.org"
135 + source: hosted
136 + version: "1.1.0"
137 + code_builder:
138 + dependency: transitive
139 + description:
140 + name: code_builder
141 + url: "https://pub.dartlang.org"
142 + source: hosted
143 + version: "3.7.0"
144 + collection:
145 + dependency: transitive
146 + description:
147 + name: collection
148 + url: "https://pub.dartlang.org"
149 + source: hosted
150 + version: "1.15.0"
151 + convert:
152 + dependency: transitive
153 + description:
154 + name: convert
155 + url: "https://pub.dartlang.org"
156 + source: hosted
157 + version: "2.1.1"
158 + crypto:
159 + dependency: transitive
160 + description:
161 + name: crypto
162 + url: "https://pub.dartlang.org"
163 + source: hosted
164 + version: "2.1.5"
165 + cw_core:
166 + dependency: "direct main"
167 + description:
168 + path: "../cw_core"
169 + relative: true
170 + source: path
171 + version: "0.0.1"
172 + cw_monero:
173 + dependency: "direct main"
174 + description:
175 + path: "../cw_monero"
176 + relative: true
177 + source: path
178 + version: "0.0.1"
179 + dart_style:
180 + dependency: transitive
181 + description:
182 + name: dart_style
183 + url: "https://pub.dartlang.org"
184 + source: hosted
185 + version: "1.3.12"
186 + dartx:
187 + dependency: transitive
188 + description:
189 + name: dartx
190 + url: "https://pub.dartlang.org"
191 + source: hosted
192 + version: "0.5.0"
193 + encrypt:
194 + dependency: transitive
195 + description:
196 + name: encrypt
197 + url: "https://pub.dartlang.org"
198 + source: hosted
199 + version: "4.1.0"
200 + fake_async:
201 + dependency: transitive
202 + description:
203 + name: fake_async
204 + url: "https://pub.dartlang.org"
205 + source: hosted
206 + version: "1.2.0"
207 + ffi:
208 + dependency: "direct main"
209 + description:
210 + name: ffi
211 + url: "https://pub.dartlang.org"
212 + source: hosted
213 + version: "0.1.3"
214 + file:
215 + dependency: transitive
216 + description:
217 + name: file
218 + url: "https://pub.dartlang.org"
219 + source: hosted
220 + version: "6.1.2"
221 + fixnum:
222 + dependency: transitive
223 + description:
224 + name: fixnum
225 + url: "https://pub.dartlang.org"
226 + source: hosted
227 + version: "1.0.0"
228 + flutter:
229 + dependency: "direct main"
230 + description: flutter
231 + source: sdk
232 + version: "0.0.0"
233 + flutter_mobx:
234 + dependency: "direct main"
235 + description:
236 + name: flutter_mobx
237 + url: "https://pub.dartlang.org"
238 + source: hosted
239 + version: "1.1.0+2"
240 + flutter_test:
241 + dependency: "direct dev"
242 + description: flutter
243 + source: sdk
244 + version: "0.0.0"
245 + glob:
246 + dependency: transitive
247 + description:
248 + name: glob
249 + url: "https://pub.dartlang.org"
250 + source: hosted
251 + version: "2.0.1"
252 + graphs:
253 + dependency: transitive
254 + description:
255 + name: graphs
256 + url: "https://pub.dartlang.org"
257 + source: hosted
258 + version: "0.2.0"
259 + hive:
260 + dependency: transitive
261 + description:
262 + name: hive
263 + url: "https://pub.dartlang.org"
264 + source: hosted
265 + version: "1.4.4+1"
266 + hive_generator:
267 + dependency: "direct dev"
268 + description:
269 + name: hive_generator
270 + url: "https://pub.dartlang.org"
271 + source: hosted
272 + version: "0.8.2"
273 + http:
274 + dependency: "direct main"
275 + description:
276 + name: http
277 + url: "https://pub.dartlang.org"
278 + source: hosted
279 + version: "0.12.2"
280 + http_multi_server:
281 + dependency: transitive
282 + description:
283 + name: http_multi_server
284 + url: "https://pub.dartlang.org"
285 + source: hosted
286 + version: "2.2.0"
287 + http_parser:
288 + dependency: transitive
289 + description:
290 + name: http_parser
291 + url: "https://pub.dartlang.org"
292 + source: hosted
293 + version: "3.1.4"
294 + intl:
295 + dependency: "direct main"
296 + description:
297 + name: intl
298 + url: "https://pub.dartlang.org"
299 + source: hosted
300 + version: "0.17.0"
301 + io:
302 + dependency: transitive
303 + description:
304 + name: io
305 + url: "https://pub.dartlang.org"
306 + source: hosted
307 + version: "0.3.5"
308 + js:
309 + dependency: transitive
310 + description:
311 + name: js
312 + url: "https://pub.dartlang.org"
313 + source: hosted
314 + version: "0.6.3"
315 + json_annotation:
316 + dependency: transitive
317 + description:
318 + name: json_annotation
319 + url: "https://pub.dartlang.org"
320 + source: hosted
321 + version: "4.0.1"
322 + logging:
323 + dependency: transitive
324 + description:
325 + name: logging
326 + url: "https://pub.dartlang.org"
327 + source: hosted
328 + version: "1.0.2"
329 + matcher:
330 + dependency: transitive
331 + description:
332 + name: matcher
333 + url: "https://pub.dartlang.org"
334 + source: hosted
335 + version: "0.12.10"
336 + meta:
337 + dependency: transitive
338 + description:
339 + name: meta
340 + url: "https://pub.dartlang.org"
341 + source: hosted
342 + version: "1.3.0"
343 + mime:
344 + dependency: transitive
345 + description:
346 + name: mime
347 + url: "https://pub.dartlang.org"
348 + source: hosted
349 + version: "1.0.1"
350 + mobx:
351 + dependency: "direct main"
352 + description:
353 + name: mobx
354 + url: "https://pub.dartlang.org"
355 + source: hosted
356 + version: "1.2.1+4"
357 + mobx_codegen:
358 + dependency: "direct dev"
359 + description:
360 + name: mobx_codegen
361 + url: "https://pub.dartlang.org"
362 + source: hosted
363 + version: "1.1.2"
364 + package_config:
365 + dependency: transitive
366 + description:
367 + name: package_config
368 + url: "https://pub.dartlang.org"
369 + source: hosted
370 + version: "1.9.3"
371 + path:
372 + dependency: transitive
373 + description:
374 + name: path
375 + url: "https://pub.dartlang.org"
376 + source: hosted
377 + version: "1.8.0"
378 + path_provider:
379 + dependency: "direct main"
380 + description:
381 + name: path_provider
382 + url: "https://pub.dartlang.org"
383 + source: hosted
384 + version: "1.6.28"
385 + path_provider_linux:
386 + dependency: transitive
387 + description:
388 + name: path_provider_linux
389 + url: "https://pub.dartlang.org"
390 + source: hosted
391 + version: "0.0.1+2"
392 + path_provider_macos:
393 + dependency: transitive
394 + description:
395 + name: path_provider_macos
396 + url: "https://pub.dartlang.org"
397 + source: hosted
398 + version: "0.0.4+8"
399 + path_provider_platform_interface:
400 + dependency: transitive
401 + description:
402 + name: path_provider_platform_interface
403 + url: "https://pub.dartlang.org"
404 + source: hosted
405 + version: "1.0.4"
406 + path_provider_windows:
407 + dependency: transitive
408 + description:
409 + name: path_provider_windows
410 + url: "https://pub.dartlang.org"
411 + source: hosted
412 + version: "0.0.4+3"
413 + pedantic:
414 + dependency: transitive
415 + description:
416 + name: pedantic
417 + url: "https://pub.dartlang.org"
418 + source: hosted
419 + version: "1.11.1"
420 + platform:
421 + dependency: transitive
422 + description:
423 + name: platform
424 + url: "https://pub.dartlang.org"
425 + source: hosted
426 + version: "3.0.2"
427 + plugin_platform_interface:
428 + dependency: transitive
429 + description:
430 + name: plugin_platform_interface
431 + url: "https://pub.dartlang.org"
432 + source: hosted
433 + version: "1.0.3"
434 + pointycastle:
435 + dependency: transitive
436 + description:
437 + name: pointycastle
438 + url: "https://pub.dartlang.org"
439 + source: hosted
440 + version: "2.0.1"
441 + pool:
442 + dependency: transitive
443 + description:
444 + name: pool
445 + url: "https://pub.dartlang.org"
446 + source: hosted
447 + version: "1.5.0"
448 + process:
449 + dependency: transitive
450 + description:
451 + name: process
452 + url: "https://pub.dartlang.org"
453 + source: hosted
454 + version: "4.2.3"
455 + pub_semver:
456 + dependency: transitive
457 + description:
458 + name: pub_semver
459 + url: "https://pub.dartlang.org"
460 + source: hosted
461 + version: "2.1.0"
462 + pubspec_parse:
463 + dependency: transitive
464 + description:
465 + name: pubspec_parse
466 + url: "https://pub.dartlang.org"
467 + source: hosted
468 + version: "0.1.8"
469 + shelf:
470 + dependency: transitive
471 + description:
472 + name: shelf
473 + url: "https://pub.dartlang.org"
474 + source: hosted
475 + version: "0.7.9"
476 + shelf_web_socket:
477 + dependency: transitive
478 + description:
479 + name: shelf_web_socket
480 + url: "https://pub.dartlang.org"
481 + source: hosted
482 + version: "0.2.4+1"
483 + sky_engine:
484 + dependency: transitive
485 + description: flutter
486 + source: sdk
487 + version: "0.0.99"
488 + source_gen:
489 + dependency: transitive
490 + description:
491 + name: source_gen
492 + url: "https://pub.dartlang.org"
493 + source: hosted
494 + version: "0.9.10+3"
495 + source_span:
496 + dependency: transitive
497 + description:
498 + name: source_span
499 + url: "https://pub.dartlang.org"
500 + source: hosted
501 + version: "1.8.0"
502 + stack_trace:
503 + dependency: transitive
504 + description:
505 + name: stack_trace
506 + url: "https://pub.dartlang.org"
507 + source: hosted
508 + version: "1.10.0"
509 + stream_channel:
510 + dependency: transitive
511 + description:
512 + name: stream_channel
513 + url: "https://pub.dartlang.org"
514 + source: hosted
515 + version: "2.1.0"
516 + stream_transform:
517 + dependency: transitive
518 + description:
519 + name: stream_transform
520 + url: "https://pub.dartlang.org"
521 + source: hosted
522 + version: "2.0.0"
523 + string_scanner:
524 + dependency: transitive
525 + description:
526 + name: string_scanner
527 + url: "https://pub.dartlang.org"
528 + source: hosted
529 + version: "1.1.0"
530 + term_glyph:
531 + dependency: transitive
532 + description:
533 + name: term_glyph
534 + url: "https://pub.dartlang.org"
535 + source: hosted
536 + version: "1.2.0"
537 + test_api:
538 + dependency: transitive
539 + description:
540 + name: test_api
541 + url: "https://pub.dartlang.org"
542 + source: hosted
543 + version: "0.2.19"
544 + time:
545 + dependency: transitive
546 + description:
547 + name: time
548 + url: "https://pub.dartlang.org"
549 + source: hosted
550 + version: "1.4.1"
551 + timing:
552 + dependency: transitive
553 + description:
554 + name: timing
555 + url: "https://pub.dartlang.org"
556 + source: hosted
557 + version: "0.1.1+3"
558 + typed_data:
559 + dependency: transitive
560 + description:
561 + name: typed_data
562 + url: "https://pub.dartlang.org"
563 + source: hosted
564 + version: "1.3.0"
565 + vector_math:
566 + dependency: transitive
567 + description:
568 + name: vector_math
569 + url: "https://pub.dartlang.org"
570 + source: hosted
571 + version: "2.1.0"
572 + watcher:
573 + dependency: transitive
574 + description:
575 + name: watcher
576 + url: "https://pub.dartlang.org"
577 + source: hosted
578 + version: "1.0.0"
579 + web_socket_channel:
580 + dependency: transitive
581 + description:
582 + name: web_socket_channel
583 + url: "https://pub.dartlang.org"
584 + source: hosted
585 + version: "1.2.0"
586 + win32:
587 + dependency: transitive
588 + description:
589 + name: win32
590 + url: "https://pub.dartlang.org"
591 + source: hosted
592 + version: "1.7.4+1"
593 + xdg_directories:
594 + dependency: transitive
595 + description:
596 + name: xdg_directories
597 + url: "https://pub.dartlang.org"
598 + source: hosted
599 + version: "0.1.2"
600 + yaml:
601 + dependency: transitive
602 + description:
603 + name: yaml
604 + url: "https://pub.dartlang.org"
605 + source: hosted
606 + version: "3.1.0"
607 +sdks:
608 + dart: ">=2.12.0 <3.0.0"
609 + flutter: ">=1.20.0"
cw_haven/pubspec.yaml new
+78
@@ -0,0 +1,78 @@
1 +name: cw_haven
2 +description: A new flutter plugin project.
3 +version: 0.0.1
4 +publish_to: none
5 +author: Cake Wallet
6 +homepage: https://cakewallet.com
7 +
8 +environment:
9 + sdk: ">=2.7.0 <3.0.0"
10 + flutter: ">=1.20.0"
11 +
12 +dependencies:
13 + flutter:
14 + sdk: flutter
15 + ffi: ^0.1.3
16 + path_provider: ^1.4.0
17 + http: ^0.12.0+2
18 + mobx: ^1.2.1+2
19 + flutter_mobx: ^1.1.0+2
20 + intl: ^0.17.0
21 + cw_core:
22 + path: ../cw_core
23 +
24 +dev_dependencies:
25 + flutter_test:
26 + sdk: flutter
27 + build_runner: ^1.10.3
28 + build_resolvers: ^1.3.10
29 + mobx_codegen: ^1.1.0+1
30 + hive_generator: ^0.8.1
31 +
32 +# For information on the generic Dart part of this file, see the
33 +# following page: https://dart.dev/tools/pub/pubspec
34 +
35 +# The following section is specific to Flutter.
36 +flutter:
37 + # This section identifies this Flutter project as a plugin project.
38 + # The 'pluginClass' and Android 'package' identifiers should not ordinarily
39 + # be modified. They are used by the tooling to maintain consistency when
40 + # adding or updating assets for this project.
41 + plugin:
42 + platforms:
43 + android:
44 + package: com.cakewallet.cw_haven
45 + pluginClass: CwHavenPlugin
46 + ios:
47 + pluginClass: CwHavenPlugin
48 +
49 + # To add assets to your plugin package, add an assets section, like this:
50 + # assets:
51 + # - images/a_dot_burr.jpeg
52 + # - images/a_dot_ham.jpeg
53 + #
54 + # For details regarding assets in packages, see
55 + # https://flutter.dev/assets-and-images/#from-packages
56 + #
57 + # An image asset can refer to one or more resolution-specific "variants", see
58 + # https://flutter.dev/assets-and-images/#resolution-aware.
59 +
60 + # To add custom fonts to your plugin package, add a fonts section here,
61 + # in this "flutter" section. Each entry in this list should have a
62 + # "family" key with the font family name, and a "fonts" key with a
63 + # list giving the asset and other descriptors for the font. For
64 + # example:
65 + # fonts:
66 + # - family: Schyler
67 + # fonts:
68 + # - asset: fonts/Schyler-Regular.ttf
69 + # - asset: fonts/Schyler-Italic.ttf
70 + # style: italic
71 + # - family: Trajan Pro
72 + # fonts:
73 + # - asset: fonts/TrajanPro.ttf
74 + # - asset: fonts/TrajanPro_Bold.ttf
75 + # weight: 700
76 + #
77 + # For details regarding fonts in packages, see
78 + # https://flutter.dev/custom-fonts/#from-packages
cw_monero/android/CMakeLists.txt
-2
@@ -7,8 +7,6 @@ add_library( cw_monero
7
8 find_library( log-lib log )
9
10 -set(CMAKE_BUILD_TYPE Debug)
11 -
10 set(EXTERNAL_LIBS_DIR ${CMAKE_SOURCE_DIR}/../ios/External/android)
11
12 ############
cw_monero/android/build.gradle
+3 -5
@@ -38,12 +38,10 @@ android {
38 disable 'InvalidPackage'
39 }
40 externalNativeBuild {
41 - // Encapsulates your CMake build configurations.
42 - cmake {
43 - // Provides a relative path to your CMake build script.
44 - path "CMakeLists.txt"
41 + cmake {
42 + path "CMakeLists.txt"
43 + }
44 }
46 - }
45 }
46
47 dependencies {
cw_monero/ios/cw_monero.podspec
+21 -20
@@ -12,43 +12,44 @@ Pod::Spec.new do |s|
12 s.author = { 'CakeWallet' => 'support@cakewallet.com' }
13 s.source = { :path => '.' }
14 s.source_files = 'Classes/**/*'
15 - s.public_header_files = 'Classes/**/*.h, Classes/*.h, External/ios/libs/monero/include/src/**/*.h, External/ios/libs/monero/include/contrib/**/*.h, External/ios/libs/monero/include/External/ios/**/*.h'
15 + s.public_header_files = 'Classes/**/*.h, Classes/*.h, External/ios/libs/monero/include/External/ios/**/*.h'
16 s.dependency 'Flutter'
17 + s.dependency 'cw_shared_external'
18 s.platform = :ios, '10.0'
19 s.swift_version = '4.0'
20 s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS' => 'arm64', 'ENABLE_BITCODE' => 'NO' }
21 s.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/Classes/*.h" }
22
23 s.subspec 'OpenSSL' do |openssl|
23 - openssl.preserve_paths = 'External/ios/include/*.h'
24 - openssl.vendored_libraries = 'External/ios/lib/libcrypto.a', 'External/ios/lib/libssl.a'
24 + openssl.preserve_paths = '../../../../../cw_shared_external/ios/External/ios/include/**/*.h'
25 + openssl.vendored_libraries = '../../../../../cw_shared_external/ios/External/ios/lib/libcrypto.a', '../../../../../cw_shared_external/ios/External/ios/lib/libssl.a'
26 openssl.libraries = 'ssl', 'crypto'
27 openssl.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
28 end
29
29 - s.subspec 'Monero' do |monero|
30 - monero.preserve_paths = 'External/ios/include/**/*.h'
31 - monero.vendored_libraries = 'External/ios/lib/libeasylogging.a', 'External/ios/lib/libepee.a', 'External/ios/lib/liblmdb.a', 'External/ios/lib/librandomx.a', 'External/ios/lib/libunbound.a', 'External/ios/lib/libwallet_merged.a', 'libcryptonote_basic.a', 'libcryptonote_format_utils_basic.a'
32 - monero.libraries = 'easylogging', 'epee', 'unbound', 'wallet_merged', 'lmdb', 'randomx', 'cryptonote_basic', 'cryptonote_format_utils_basic'
33 - monero.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include" }
30 + s.subspec 'Sodium' do |sodium|
31 + sodium.preserve_paths = '../../../../../cw_shared_external/ios/External/ios/include/**/*.h'
32 + sodium.vendored_libraries = '../../../../../cw_shared_external/ios/External/ios/lib/libsodium.a'
33 + sodium.libraries = 'sodium'
34 + sodium.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
35 end
36
37 s.subspec 'Boost' do |boost|
37 - boost.preserve_paths = 'External/ios/include/**/*.h', 'External/ios/include/**/*.h'
38 - boost.vendored_libraries = 'External/ios/lib/libboost_chrono.a', 'External/ios/lib/libboost_date_time.a', 'External/ios/lib/libboost_filesystem.a', 'External/ios/lib/libboost_graph.a', 'External/ios/lib/libboost_locale.a', 'External/ios/lib/libboost_program_options.a', 'External/ios/lib/libboost_random.a', 'External/ios/lib/libboost_regex.a', 'External/ios/lib/libboost_serialization.a', 'External/ios/lib/libboost_system.a', 'External/ios/lib/libboost_thread.a', 'External/ios/lib/libboost_wserialization.a'
39 - boost.libraries = 'boost_wserialization', 'boost_thread', 'boost_system', 'boost_serialization', 'boost_regex', 'boost_random', 'boost_program_options', 'boost_locale', 'boost_graph', 'boost_filesystem', 'boost_date_time', 'boost_chrono'
38 + boost.preserve_paths = '../../../../../cw_shared_external/ios/External/ios/include/**/*.h',
39 + boost.vendored_libraries = '../../../../../cw_shared_external/ios/External/ios/lib/libboost.a',
40 + boost.libraries = 'boost'
41 boost.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
42 end
43
43 - s.subspec 'Sodium' do |sodium|
44 - sodium.preserve_paths = 'External/ios/include/**/*.h'
45 - sodium.vendored_libraries = 'External/ios/lib/libsodium.a'
46 - sodium.libraries = 'sodium'
47 - sodium.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
44 + s.subspec 'Monero' do |monero|
45 + monero.preserve_paths = 'External/ios/include/**/*.h'
46 + monero.vendored_libraries = 'External/ios/lib/libmonero.a'
47 + monero.libraries = 'monero'
48 + monero.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include" }
49 end
50
50 - s.subspec 'lmdb' do |lmdb|
51 - lmdb.vendored_libraries = 'External/ios/lib/liblmdb.a'
52 - lmdb.libraries = 'lmdb'
53 - end
51 + # s.subspec 'lmdb' do |lmdb|
52 + # lmdb.vendored_libraries = 'External/ios/lib/liblmdb.a'
53 + # lmdb.libraries = 'lmdb'
54 + # end
55 end
cw_monero/lib/monero_account_list.dart
+4 -2
@@ -1,5 +1,5 @@
1 import 'package:mobx/mobx.dart';
2 -import 'package:cw_monero/account.dart';
2 +import 'package:cw_core/account.dart';
3 import 'package:cw_monero/api/account_list.dart' as account_list;
4
5 part 'monero_account_list.g.dart';
@@ -44,7 +44,9 @@ abstract class MoneroAccountListBase with Store {
44
45 List<Account> getAll() => account_list
46 .getAllAccount()
47 - .map((accountRow) => Account.fromRow(accountRow))
47 + .map((accountRow) => Account(
48 + id: accountRow.getId(),
49 + label: accountRow.getLabel()))
50 .toList();
51
52 Future addAccount({String label}) async {
cw_monero/lib/monero_subaddress_list.dart
+8 -2
@@ -2,7 +2,7 @@ import 'package:cw_monero/api/structs/subaddress_row.dart';
2 import 'package:flutter/services.dart';
3 import 'package:mobx/mobx.dart';
4 import 'package:cw_monero/api/subaddress_list.dart' as subaddress_list;
5 -import 'package:cw_monero/subaddress.dart';
5 +import 'package:cw_core/subaddress.dart';
6
7 part 'monero_subaddress_list.g.dart';
8
@@ -49,7 +49,13 @@ abstract class MoneroSubaddressListBase with Store {
49 }
50
51 return subaddresses
52 - .map((subaddressRow) => Subaddress.fromRow(subaddressRow))
52 + .map((subaddressRow) => Subaddress(
53 + id: subaddressRow.getId(),
54 + address: subaddressRow.getAddress(),
55 + label: subaddressRow.getId() == 0 &&
56 + subaddressRow.getLabel().toLowerCase() == 'Primary account'.toLowerCase()
57 + ? 'Primary address'
58 + : subaddressRow.getLabel()))
59 .toList();
60 }
61
cw_monero/lib/monero_transaction_creation_credentials.dart
+1 -3
@@ -1,6 +1,4 @@
1 -//import 'package:cake_wallet/entities/transaction_creation_credentials.dart';
2 -import 'package:cw_monero/monero_transaction_priority.dart';
3 -//import 'package:cake_wallet/view_model/send/output.dart';
1 +import 'package:cw_core/monero_transaction_priority.dart';
2 import 'package:cw_core/output_info.dart';
3
4 class MoneroTransactionCreationCredentials {
cw_monero/lib/monero_transaction_info.dart
+1 -1
@@ -1,5 +1,5 @@
1 import 'package:cw_core/transaction_info.dart';
2 -import 'package:cw_monero/monero_amount_format.dart';
2 +import 'package:cw_core/monero_amount_format.dart';
3 import 'package:cw_monero/api/structs/transaction_info_row.dart';
4 import 'package:cw_core/parseBoolFromString.dart';
5 import 'package:cw_core/transaction_direction.dart';
cw_monero/lib/monero_wallet.dart
+29 -21
@@ -1,10 +1,10 @@
1 import 'dart:async';
2 import 'package:cw_core/transaction_priority.dart';
3 -import 'package:cw_monero/monero_amount_format.dart';
3 +import 'package:cw_core/monero_amount_format.dart';
4 import 'package:cw_monero/monero_transaction_creation_exception.dart';
5 import 'package:cw_monero/monero_transaction_info.dart';
6 import 'package:cw_monero/monero_wallet_addresses.dart';
7 -import 'package:cw_monero/monero_wallet_utils.dart';
7 +import 'package:cw_core/monero_wallet_utils.dart';
8 import 'package:cw_monero/api/structs/pending_transaction.dart';
9 import 'package:flutter/foundation.dart';
10 import 'package:mobx/mobx.dart';
@@ -16,16 +16,17 @@ import 'package:cw_monero/api/transaction_history.dart' as transaction_history;
16 import 'package:cw_monero/api/monero_output.dart';
17 import 'package:cw_monero/monero_transaction_creation_credentials.dart';
18 import 'package:cw_monero/pending_monero_transaction.dart';
19 -import 'package:cw_monero/monero_wallet_keys.dart';
20 -import 'package:cw_monero/monero_balance.dart';
19 +import 'package:cw_core/monero_wallet_keys.dart';
20 +import 'package:cw_core/monero_balance.dart';
21 import 'package:cw_monero/monero_transaction_history.dart';
22 -import 'package:cw_monero/account.dart';
22 +import 'package:cw_core/account.dart';
23 import 'package:cw_core/pending_transaction.dart';
24 import 'package:cw_core/wallet_base.dart';
25 import 'package:cw_core/sync_status.dart';
26 import 'package:cw_core/wallet_info.dart';
27 import 'package:cw_core/node.dart';
28 -import 'package:cw_monero/monero_transaction_priority.dart';
28 +import 'package:cw_core/monero_transaction_priority.dart';
29 +import 'package:cw_core/crypto_currency.dart';
30
31 part 'monero_wallet.g.dart';
32
@@ -38,18 +39,23 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
39 MoneroWalletBase({WalletInfo walletInfo})
40 : super(walletInfo) {
41 transactionHistory = MoneroTransactionHistory();
41 - balance = MoneroBalance(
42 - fullBalance: monero_wallet.getFullBalance(accountIndex: 0),
43 - unlockedBalance: monero_wallet.getFullBalance(accountIndex: 0));
42 + balance = ObservableMap<CryptoCurrency, MoneroBalance>.of({
43 + CryptoCurrency.xmr: MoneroBalance(
44 + fullBalance: monero_wallet.getFullBalance(accountIndex: 0),
45 + unlockedBalance: monero_wallet.getFullBalance(accountIndex: 0))
46 + });
47 _isTransactionUpdating = false;
48 _hasSyncAfterStartup = false;
49 walletAddresses = MoneroWalletAddresses(walletInfo);
50 _onAccountChangeReaction = reaction((_) => walletAddresses.account,
51 (Account account) {
49 - balance = MoneroBalance(
50 - fullBalance: monero_wallet.getFullBalance(accountIndex: account.id),
51 - unlockedBalance:
52 - monero_wallet.getUnlockedBalance(accountIndex: account.id));
52 + balance = ObservableMap<CryptoCurrency, MoneroBalance>.of(
53 + <CryptoCurrency, MoneroBalance>{
54 + currency: MoneroBalance(
55 + fullBalance: monero_wallet.getFullBalance(accountIndex: account.id),
56 + unlockedBalance:
57 + monero_wallet.getUnlockedBalance(accountIndex: account.id))
58 + });
59 walletAddresses.updateSubaddressList(accountIndex: account.id);
60 });
61 }
@@ -65,7 +71,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
71
72 @override
73 @observable
68 - MoneroBalance balance;
74 + ObservableMap<CryptoCurrency, MoneroBalance> balance;
75
76 @override
77 String get seed => monero_wallet.getSeed();
@@ -85,10 +91,12 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
91
92 Future<void> init() async {
93 await walletAddresses.init();
88 - balance = MoneroBalance(
89 - fullBalance: monero_wallet.getFullBalance(accountIndex: walletAddresses.account.id),
90 - unlockedBalance:
91 - monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account.id));
94 + balance = ObservableMap<CryptoCurrency, MoneroBalance>.of(
95 + <CryptoCurrency, MoneroBalance>{
96 + currency: MoneroBalance(
97 + fullBalance: monero_wallet.getFullBalance(accountIndex: walletAddresses.account.id),
98 + unlockedBalance: monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account.id))
99 + });
100 _setListeners();
101 await updateTransactions();
102
@@ -355,9 +363,9 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
363 final unlockedBalance = _getUnlockedBalance();
364 final fullBalance = _getFullBalance();
365
358 - if (balance.fullBalance != fullBalance ||
359 - balance.unlockedBalance != unlockedBalance) {
360 - balance = MoneroBalance(
366 + if (balance[currency].fullBalance != fullBalance ||
367 + balance[currency].unlockedBalance != unlockedBalance) {
368 + balance[currency] = MoneroBalance(
369 fullBalance: fullBalance, unlockedBalance: unlockedBalance);
370 }
371 }
cw_monero/lib/monero_wallet_addresses.dart
+2 -2
@@ -1,9 +1,9 @@
1 import 'package:cw_core/wallet_addresses.dart';
2 import 'package:cw_core/wallet_info.dart';
3 -import 'package:cw_monero/account.dart';
3 +import 'package:cw_core/account.dart';
4 import 'package:cw_monero/monero_account_list.dart';
5 import 'package:cw_monero/monero_subaddress_list.dart';
6 -import 'package:cw_monero/subaddress.dart';
6 +import 'package:cw_core/subaddress.dart';
7 import 'package:mobx/mobx.dart';
8
9 part 'monero_wallet_addresses.g.dart';
cw_monero/lib/monero_wallet_service.dart
+1 -1
@@ -1,6 +1,6 @@
1 import 'dart:io';
2 import 'package:cw_core/wallet_base.dart';
3 -import 'package:cw_monero/monero_wallet_utils.dart';
3 +import 'package:cw_core/monero_wallet_utils.dart';
4 import 'package:hive/hive.dart';
5 import 'package:cw_monero/api/wallet_manager.dart' as monero_wallet_manager;
6 import 'package:cw_monero/api/wallet.dart' as monero_wallet;
cw_monero/lib/subaddress.dart deleted
-22
@@ -1,22 +0,0 @@
1 -import 'package:cw_monero/api/structs/subaddress_row.dart';
2 -
3 -class Subaddress {
4 - Subaddress({this.id, this.address, this.label});
5 -
6 - Subaddress.fromMap(Map map)
7 - : this.id = map['id'] == null ? 0 : int.parse(map['id'] as String),
8 - this.address = (map['address'] ?? '') as String,
9 - this.label = (map['label'] ?? '') as String;
10 -
11 - Subaddress.fromRow(SubaddressRow row)
12 - : this.id = row.getId(),
13 - this.address = row.getAddress(),
14 - this.label = row.getId() == 0 &&
15 - row.getLabel().toLowerCase() == 'Primary account'.toLowerCase()
16 - ? 'Primary address'
17 - : row.getLabel();
18 -
19 - final int id;
20 - final String address;
21 - final String label;
22 -}
cw_shared_external/.gitignore new
+7
@@ -0,0 +1,7 @@
1 +.DS_Store
2 +.dart_tool/
3 +
4 +.packages
5 +.pub/
6 +
7 +build/
cw_shared_external/.metadata new
+10
@@ -0,0 +1,10 @@
1 +# This file tracks properties of this Flutter project.
2 +# Used by Flutter tool to assess capabilities and perform upgrades etc.
3 +#
4 +# This file should be version controlled and should not be manually edited.
5 +
6 +version:
7 + revision: 4d7946a68d26794349189cf21b3f68cc6fe61dcb
8 + channel: stable
9 +
10 +project_type: plugin
cw_shared_external/LICENSE new
+1
@@ -0,0 +1 @@
1 +TODO: Add your license here.
cw_shared_external/README.md new
+7
@@ -0,0 +1,7 @@
1 +# cw_shared_external
2 +
3 +Part of Cake Wallet. Shared external libraries for cw_monero and cw_haven.
4 +Libraries:
5 +- Boost
6 +- OpenSSL
7 +- Sodium
\ No newline at end of file
cw_shared_external/android/.gitignore new
+8
@@ -0,0 +1,8 @@
1 +*.iml
2 +.gradle
3 +/local.properties
4 +/.idea/workspace.xml
5 +/.idea/libraries
6 +.DS_Store
7 +/build
8 +/captures
cw_shared_external/android/build.gradle new
+40
@@ -0,0 +1,40 @@
1 +group 'com.cakewallet.cw_shared_external'
2 +version '1.0-SNAPSHOT'
3 +
4 +buildscript {
5 + ext.kotlin_version = '1.3.50'
6 + repositories {
7 + google()
8 + jcenter()
9 + }
10 +
11 + dependencies {
12 + classpath 'com.android.tools.build:gradle:4.1.0'
13 + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
14 + }
15 +}
16 +
17 +rootProject.allprojects {
18 + repositories {
19 + google()
20 + jcenter()
21 + }
22 +}
23 +
24 +apply plugin: 'com.android.library'
25 +apply plugin: 'kotlin-android'
26 +
27 +android {
28 + compileSdkVersion 30
29 +
30 + sourceSets {
31 + main.java.srcDirs += 'src/main/kotlin'
32 + }
33 + defaultConfig {
34 + minSdkVersion 16
35 + }
36 +}
37 +
38 +dependencies {
39 + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
40 +}
cw_shared_external/android/gradle.properties new
+3
@@ -0,0 +1,3 @@
1 +org.gradle.jvmargs=-Xmx1536M
2 +android.useAndroidX=true
3 +android.enableJetifier=true
cw_shared_external/android/gradle/wrapper/gradle-wrapper.properties new
+5
@@ -0,0 +1,5 @@
1 +distributionBase=GRADLE_USER_HOME
2 +distributionPath=wrapper/dists
3 +zipStoreBase=GRADLE_USER_HOME
4 +zipStorePath=wrapper/dists
5 +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
cw_shared_external/android/settings.gradle new
+1
@@ -0,0 +1 @@
1 +rootProject.name = 'cw_shared_external'
cw_shared_external/android/src/main/AndroidManifest.xml new
+3
@@ -0,0 +1,3 @@
1 +<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2 + package="com.cakewallet.cw_shared_external">
3 +</manifest>
cw_shared_external/android/src/main/kotlin/com/cakewallet/cw_shared_external/CwSharedExternalPlugin.kt new
+36
@@ -0,0 +1,36 @@
1 +package com.cakewallet.cw_shared_external
2 +
3 +import androidx.annotation.NonNull
4 +
5 +import io.flutter.embedding.engine.plugins.FlutterPlugin
6 +import io.flutter.plugin.common.MethodCall
7 +import io.flutter.plugin.common.MethodChannel
8 +import io.flutter.plugin.common.MethodChannel.MethodCallHandler
9 +import io.flutter.plugin.common.MethodChannel.Result
10 +import io.flutter.plugin.common.PluginRegistry.Registrar
11 +
12 +/** CwSharedExternalPlugin */
13 +class CwSharedExternalPlugin: FlutterPlugin, MethodCallHandler {
14 + /// The MethodChannel that will the communication between Flutter and native Android
15 + ///
16 + /// This local reference serves to register the plugin with the Flutter Engine and unregister it
17 + /// when the Flutter Engine is detached from the Activity
18 + private lateinit var channel : MethodChannel
19 +
20 + override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
21 + channel = MethodChannel(flutterPluginBinding.binaryMessenger, "cw_shared_external")
22 + channel.setMethodCallHandler(this)
23 + }
24 +
25 + override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
26 + if (call.method == "getPlatformVersion") {
27 + result.success("Android ${android.os.Build.VERSION.RELEASE}")
28 + } else {
29 + result.notImplemented()
30 + }
31 + }
32 +
33 + override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
34 + channel.setMethodCallHandler(null)
35 + }
36 +}
cw_shared_external/ios/.gitignore new
+37
@@ -0,0 +1,37 @@
1 +.idea/
2 +.vagrant/
3 +.sconsign.dblite
4 +.svn/
5 +
6 +.DS_Store
7 +*.swp
8 +profile
9 +
10 +DerivedData/
11 +build/
12 +GeneratedPluginRegistrant.h
13 +GeneratedPluginRegistrant.m
14 +
15 +.generated/
16 +
17 +*.pbxuser
18 +*.mode1v3
19 +*.mode2v3
20 +*.perspectivev3
21 +
22 +!default.pbxuser
23 +!default.mode1v3
24 +!default.mode2v3
25 +!default.perspectivev3
26 +
27 +xcuserdata
28 +
29 +*.moved-aside
30 +
31 +*.pyc
32 +*sync/
33 +Icon?
34 +.tags*
35 +
36 +/Flutter/Generated.xcconfig
37 +/Flutter/flutter_export_environment.sh
\ No newline at end of file
cw_shared_external/ios/Assets/.gitkeep
cw_shared_external/ios/Classes/CwSharedExternalPlugin.h new
+4
@@ -0,0 +1,4 @@
1 +#import <Flutter/Flutter.h>
2 +
3 +@interface CwSharedExternalPlugin : NSObject<FlutterPlugin>
4 +@end
cw_shared_external/ios/Classes/CwSharedExternalPlugin.m new
+15
@@ -0,0 +1,15 @@
1 +#import "CwSharedExternalPlugin.h"
2 +#if __has_include(<cw_shared_external/cw_shared_external-Swift.h>)
3 +#import <cw_shared_external/cw_shared_external-Swift.h>
4 +#else
5 +// Support project import fallback if the generated compatibility header
6 +// is not copied when this plugin is created as a library.
7 +// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816
8 +#import "cw_shared_external-Swift.h"
9 +#endif
10 +
11 +@implementation CwSharedExternalPlugin
12 ++ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
13 + [SwiftCwSharedExternalPlugin registerWithRegistrar:registrar];
14 +}
15 +@end
cw_shared_external/ios/Classes/SwiftCwSharedExternalPlugin.swift new
+14
@@ -0,0 +1,14 @@
1 +import Flutter
2 +import UIKit
3 +
4 +public class SwiftCwSharedExternalPlugin: NSObject, FlutterPlugin {
5 + public static func register(with registrar: FlutterPluginRegistrar) {
6 + let channel = FlutterMethodChannel(name: "cw_shared_external", binaryMessenger: registrar.messenger())
7 + let instance = SwiftCwSharedExternalPlugin()
8 + registrar.addMethodCallDelegate(instance, channel: channel)
9 + }
10 +
11 + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
12 + result("iOS " + UIDevice.current.systemVersion)
13 + }
14 +}
cw_shared_external/ios/cw_shared_external.podspec new
+41
@@ -0,0 +1,41 @@
1 +#
2 +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
3 +# Run `pod lib lint cw_shared_external.podspec` to validate before publishing.
4 +#
5 +Pod::Spec.new do |s|
6 + s.name = 'cw_shared_external'
7 + s.version = '0.0.1'
8 + s.summary = 'Shared libraries for monero and haven.'
9 + s.description = 'Shared libraries for monero and haven.'
10 + s.homepage = 'http://cakewallet.com'
11 + s.license = { :file => '../LICENSE' }
12 + s.author = { 'Cake Wallet' => 'm@cakewallet.com' }
13 + s.source = { :path => '.' }
14 + s.source_files = 'Classes/**/*'
15 + s.dependency 'Flutter'
16 + s.platform = :ios, '10.0'
17 +
18 + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS' => 'arm64', 'ENABLE_BITCODE' => 'NO' }
19 + s.swift_version = '5.0'
20 +
21 + s.subspec 'OpenSSL' do |openssl|
22 + openssl.preserve_paths = 'External/ios/include/*.h'
23 + openssl.vendored_libraries = 'External/ios/lib/libcrypto.a', 'External/ios/lib/libssl.a'
24 + openssl.libraries = 'ssl', 'crypto'
25 + openssl.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
26 + end
27 +
28 + s.subspec 'Boost' do |boost|
29 + boost.preserve_paths = 'External/ios/include/**/*.h'
30 + boost.vendored_libraries = 'External/ios/lib/libboost.a',
31 + boost.libraries = 'boost'
32 + boost.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
33 + end
34 +
35 + s.subspec 'Sodium' do |sodium|
36 + sodium.preserve_paths = 'External/ios/include/**/*.h'
37 + sodium.vendored_libraries = 'External/ios/lib/libsodium.a'
38 + sodium.libraries = 'sodium'
39 + sodium.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
40 + end
41 +end
cw_shared_external/lib/cw_shared_external.dart new
+14
@@ -0,0 +1,14 @@
1 +
2 +import 'dart:async';
3 +
4 +import 'package:flutter/services.dart';
5 +
6 +class CwSharedExternal {
7 + static const MethodChannel _channel =
8 + const MethodChannel('cw_shared_external');
9 +
10 + static Future<String> get platformVersion async {
11 + final String version = await _channel.invokeMethod('getPlatformVersion');
12 + return version;
13 + }
14 +}
cw_shared_external/pubspec.lock new
+147
@@ -0,0 +1,147 @@
1 +# Generated by pub
2 +# See https://dart.dev/tools/pub/glossary#lockfile
3 +packages:
4 + async:
5 + dependency: transitive
6 + description:
7 + name: async
8 + url: "https://pub.dartlang.org"
9 + source: hosted
10 + version: "2.5.0"
11 + boolean_selector:
12 + dependency: transitive
13 + description:
14 + name: boolean_selector
15 + url: "https://pub.dartlang.org"
16 + source: hosted
17 + version: "2.1.0"
18 + characters:
19 + dependency: transitive
20 + description:
21 + name: characters
22 + url: "https://pub.dartlang.org"
23 + source: hosted
24 + version: "1.1.0"
25 + charcode:
26 + dependency: transitive
27 + description:
28 + name: charcode
29 + url: "https://pub.dartlang.org"
30 + source: hosted
31 + version: "1.2.0"
32 + clock:
33 + dependency: transitive
34 + description:
35 + name: clock
36 + url: "https://pub.dartlang.org"
37 + source: hosted
38 + version: "1.1.0"
39 + collection:
40 + dependency: transitive
41 + description:
42 + name: collection
43 + url: "https://pub.dartlang.org"
44 + source: hosted
45 + version: "1.15.0"
46 + fake_async:
47 + dependency: transitive
48 + description:
49 + name: fake_async
50 + url: "https://pub.dartlang.org"
51 + source: hosted
52 + version: "1.2.0"
53 + flutter:
54 + dependency: "direct main"
55 + description: flutter
56 + source: sdk
57 + version: "0.0.0"
58 + flutter_test:
59 + dependency: "direct dev"
60 + description: flutter
61 + source: sdk
62 + version: "0.0.0"
63 + matcher:
64 + dependency: transitive
65 + description:
66 + name: matcher
67 + url: "https://pub.dartlang.org"
68 + source: hosted
69 + version: "0.12.10"
70 + meta:
71 + dependency: transitive
72 + description:
73 + name: meta
74 + url: "https://pub.dartlang.org"
75 + source: hosted
76 + version: "1.3.0"
77 + path:
78 + dependency: transitive
79 + description:
80 + name: path
81 + url: "https://pub.dartlang.org"
82 + source: hosted
83 + version: "1.8.0"
84 + sky_engine:
85 + dependency: transitive
86 + description: flutter
87 + source: sdk
88 + version: "0.0.99"
89 + source_span:
90 + dependency: transitive
91 + description:
92 + name: source_span
93 + url: "https://pub.dartlang.org"
94 + source: hosted
95 + version: "1.8.0"
96 + stack_trace:
97 + dependency: transitive
98 + description:
99 + name: stack_trace
100 + url: "https://pub.dartlang.org"
101 + source: hosted
102 + version: "1.10.0"
103 + stream_channel:
104 + dependency: transitive
105 + description:
106 + name: stream_channel
107 + url: "https://pub.dartlang.org"
108 + source: hosted
109 + version: "2.1.0"
110 + string_scanner:
111 + dependency: transitive
112 + description:
113 + name: string_scanner
114 + url: "https://pub.dartlang.org"
115 + source: hosted
116 + version: "1.1.0"
117 + term_glyph:
118 + dependency: transitive
119 + description:
120 + name: term_glyph
121 + url: "https://pub.dartlang.org"
122 + source: hosted
123 + version: "1.2.0"
124 + test_api:
125 + dependency: transitive
126 + description:
127 + name: test_api
128 + url: "https://pub.dartlang.org"
129 + source: hosted
130 + version: "0.2.19"
131 + typed_data:
132 + dependency: transitive
133 + description:
134 + name: typed_data
135 + url: "https://pub.dartlang.org"
136 + source: hosted
137 + version: "1.3.0"
138 + vector_math:
139 + dependency: transitive
140 + description:
141 + name: vector_math
142 + url: "https://pub.dartlang.org"
143 + source: hosted
144 + version: "2.1.0"
145 +sdks:
146 + dart: ">=2.12.0-0.0 <3.0.0"
147 + flutter: ">=1.20.0"
cw_shared_external/pubspec.yaml new
+26
@@ -0,0 +1,26 @@
1 +name: cw_shared_external
2 +description: Shared external libraries for monero and haven
3 +version: 0.0.1
4 +author: Cake Walelt
5 +homepage: https://cakewallet.com
6 +
7 +environment:
8 + sdk: ">=2.7.0 <3.0.0"
9 + flutter: ">=1.20.0"
10 +
11 +dependencies:
12 + flutter:
13 + sdk: flutter
14 +
15 +dev_dependencies:
16 + flutter_test:
17 + sdk: flutter
18 +
19 +flutter:
20 + plugin:
21 + platforms:
22 + android:
23 + package: com.cakewallet.cw_shared_external
24 + pluginClass: CwSharedExternalPlugin
25 + ios:
26 + pluginClass: CwSharedExternalPlugin
\ No newline at end of file
ios/Podfile.lock
+44 -4
@@ -8,22 +8,54 @@ PODS:
8 - Flutter
9 - Reachability
10 - CryptoSwift (1.3.2)
11 + - cw_haven (0.0.1):
12 + - cw_haven/Boost (= 0.0.1)
13 + - cw_haven/Haven (= 0.0.1)
14 + - cw_haven/OpenSSL (= 0.0.1)
15 + - cw_haven/Sodium (= 0.0.1)
16 + - cw_shared_external
17 + - Flutter
18 + - cw_haven/Boost (0.0.1):
19 + - cw_shared_external
20 + - Flutter
21 + - cw_haven/Haven (0.0.1):
22 + - cw_shared_external
23 + - Flutter
24 + - cw_haven/OpenSSL (0.0.1):
25 + - cw_shared_external
26 + - Flutter
27 + - cw_haven/Sodium (0.0.1):
28 + - cw_shared_external
29 + - Flutter
30 - cw_monero (0.0.2):
31 - cw_monero/Boost (= 0.0.2)
13 - - cw_monero/lmdb (= 0.0.2)
32 - cw_monero/Monero (= 0.0.2)
33 - cw_monero/OpenSSL (= 0.0.2)
34 - cw_monero/Sodium (= 0.0.2)
35 + - cw_shared_external
36 - Flutter
37 - cw_monero/Boost (0.0.2):
19 - - Flutter
20 - - cw_monero/lmdb (0.0.2):
38 + - cw_shared_external
39 - Flutter
40 - cw_monero/Monero (0.0.2):
41 + - cw_shared_external
42 - Flutter
43 - cw_monero/OpenSSL (0.0.2):
44 + - cw_shared_external
45 - Flutter
46 - cw_monero/Sodium (0.0.2):
47 + - cw_shared_external
48 + - Flutter
49 + - cw_shared_external (0.0.1):
50 + - cw_shared_external/Boost (= 0.0.1)
51 + - cw_shared_external/OpenSSL (= 0.0.1)
52 + - cw_shared_external/Sodium (= 0.0.1)
53 + - Flutter
54 + - cw_shared_external/Boost (0.0.1):
55 + - Flutter
56 + - cw_shared_external/OpenSSL (0.0.1):
57 + - Flutter
58 + - cw_shared_external/Sodium (0.0.1):
59 - Flutter
60 - devicelocale (0.0.1):
61 - Flutter
@@ -99,7 +131,9 @@ DEPENDENCIES:
131 - barcode_scan (from `.symlinks/plugins/barcode_scan/ios`)
132 - connectivity (from `.symlinks/plugins/connectivity/ios`)
133 - CryptoSwift
134 + - cw_haven (from `.symlinks/plugins/cw_haven/ios`)
135 - cw_monero (from `.symlinks/plugins/cw_monero/ios`)
136 + - cw_shared_external (from `.symlinks/plugins/cw_shared_external/ios`)
137 - devicelocale (from `.symlinks/plugins/devicelocale/ios`)
138 - esys_flutter_share (from `.symlinks/plugins/esys_flutter_share/ios`)
139 - file_picker (from `.symlinks/plugins/file_picker/ios`)
@@ -134,8 +168,12 @@ EXTERNAL SOURCES:
168 :path: ".symlinks/plugins/barcode_scan/ios"
169 connectivity:
170 :path: ".symlinks/plugins/connectivity/ios"
171 + cw_haven:
172 + :path: ".symlinks/plugins/cw_haven/ios"
173 cw_monero:
174 :path: ".symlinks/plugins/cw_monero/ios"
175 + cw_shared_external:
176 + :path: ".symlinks/plugins/cw_shared_external/ios"
177 devicelocale:
178 :path: ".symlinks/plugins/devicelocale/ios"
179 esys_flutter_share:
@@ -170,7 +208,9 @@ SPEC CHECKSUMS:
208 BigInt: f668a80089607f521586bbe29513d708491ef2f7
209 connectivity: c4130b2985d4ef6fd26f9702e886bd5260681467
210 CryptoSwift: 093499be1a94b0cae36e6c26b70870668cb56060
173 - cw_monero: c79d5530b828b8013c1db421f1be8bab687f7b7e
211 + cw_haven: b3e54e1fbe7b8e6fda57a93206bc38f8e89b898a
212 + cw_monero: 88c5e7aa596c6848330750f5f8bcf05fb9c66375
213 + cw_shared_external: 2972d872b8917603478117c9957dfca611845a92
214 devicelocale: b22617f40038496deffba44747101255cee005b0
215 DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d
216 DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
ios/Runner.xcodeproj/project.pbxproj
+3 -3
@@ -366,7 +366,7 @@
366 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
367 CLANG_ENABLE_MODULES = YES;
368 CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
369 - CURRENT_PROJECT_VERSION = 68;
369 + CURRENT_PROJECT_VERSION = 3;
370 DEVELOPMENT_TEAM = 32J6BB6VUS;
371 ENABLE_BITCODE = NO;
372 EXCLUDED_SOURCE_FILE_NAMES = "";
@@ -510,7 +510,7 @@
510 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
511 CLANG_ENABLE_MODULES = YES;
512 CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
513 - CURRENT_PROJECT_VERSION = 68;
513 + CURRENT_PROJECT_VERSION = 3;
514 DEVELOPMENT_TEAM = 32J6BB6VUS;
515 ENABLE_BITCODE = NO;
516 EXCLUDED_SOURCE_FILE_NAMES = "";
@@ -546,7 +546,7 @@
546 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
547 CLANG_ENABLE_MODULES = YES;
548 CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
549 - CURRENT_PROJECT_VERSION = 68;
549 + CURRENT_PROJECT_VERSION = 3;
550 DEVELOPMENT_TEAM = 32J6BB6VUS;
551 ENABLE_BITCODE = NO;
552 EXCLUDED_SOURCE_FILE_NAMES = "";
ios/Runner/Runner.entitlements
+1 -4
@@ -1,8 +1,5 @@
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 <plist version="1.0">
4 -<dict>
5 - <key>aps-environment</key>
6 - <string>development</string>
7 -</dict>
4 +<dict/>
5 </plist>
lib/core/address_validator.dart
+32
@@ -46,6 +46,22 @@ class AddressValidator extends TextValidator {
46 return '[0-9a-zA-Z]';
47 case CryptoCurrency.xrp:
48 return '^[0-9a-zA-Z]{34}\$|^X[0-9a-zA-Z]{46}\$';
49 + case CryptoCurrency.xhv:
50 + case CryptoCurrency.xhv:
51 + case CryptoCurrency.xag:
52 + case CryptoCurrency.xau:
53 + case CryptoCurrency.xaud:
54 + case CryptoCurrency.xbtc:
55 + case CryptoCurrency.xcad:
56 + case CryptoCurrency.xchf:
57 + case CryptoCurrency.xcny:
58 + case CryptoCurrency.xeur:
59 + case CryptoCurrency.xgbp:
60 + case CryptoCurrency.xjpy:
61 + case CryptoCurrency.xnok:
62 + case CryptoCurrency.xnzd:
63 + case CryptoCurrency.xusd:
64 + return '[0-9a-zA-Z]';
65 default:
66 return '[0-9a-zA-Z]';
67 }
@@ -85,6 +101,22 @@ class AddressValidator extends TextValidator {
101 return [56];
102 case CryptoCurrency.xrp:
103 return null;
104 + case CryptoCurrency.xhv:
105 + case CryptoCurrency.xhv:
106 + case CryptoCurrency.xag:
107 + case CryptoCurrency.xau:
108 + case CryptoCurrency.xaud:
109 + case CryptoCurrency.xbtc:
110 + case CryptoCurrency.xcad:
111 + case CryptoCurrency.xchf:
112 + case CryptoCurrency.xcny:
113 + case CryptoCurrency.xeur:
114 + case CryptoCurrency.xgbp:
115 + case CryptoCurrency.xjpy:
116 + case CryptoCurrency.xnok:
117 + case CryptoCurrency.xnzd:
118 + case CryptoCurrency.xusd:
119 + return [98, 99, 106];
120 default:
121 return [];
122 }
lib/core/amount_converter.dart
+45
@@ -31,6 +31,21 @@ class AmountConverter {
31 return _ethereumAmountToDouble(amount);
32 case CryptoCurrency.ltc:
33 return _litecoinAmountToDouble(amount);
34 + case CryptoCurrency.xhv:
35 + case CryptoCurrency.xag:
36 + case CryptoCurrency.xau:
37 + case CryptoCurrency.xaud:
38 + case CryptoCurrency.xbtc:
39 + case CryptoCurrency.xcad:
40 + case CryptoCurrency.xchf:
41 + case CryptoCurrency.xcny:
42 + case CryptoCurrency.xeur:
43 + case CryptoCurrency.xgbp:
44 + case CryptoCurrency.xjpy:
45 + case CryptoCurrency.xnok:
46 + case CryptoCurrency.xnzd:
47 + case CryptoCurrency.xusd:
48 + return _moneroAmountToDouble(amount);
49 default:
50 return null;
51 }
@@ -40,6 +55,21 @@ class AmountConverter {
55 switch (cryptoCurrency) {
56 case CryptoCurrency.xmr:
57 return _moneroParseAmount(amount);
58 + case CryptoCurrency.xhv:
59 + case CryptoCurrency.xag:
60 + case CryptoCurrency.xau:
61 + case CryptoCurrency.xaud:
62 + case CryptoCurrency.xbtc:
63 + case CryptoCurrency.xcad:
64 + case CryptoCurrency.xchf:
65 + case CryptoCurrency.xcny:
66 + case CryptoCurrency.xeur:
67 + case CryptoCurrency.xgbp:
68 + case CryptoCurrency.xjpy:
69 + case CryptoCurrency.xnok:
70 + case CryptoCurrency.xnzd:
71 + case CryptoCurrency.xusd:
72 + return _moneroParseAmount(amount);
73 default:
74 return null;
75 }
@@ -51,6 +81,21 @@ class AmountConverter {
81 return _moneroAmountToString(amount);
82 case CryptoCurrency.btc:
83 return _bitcoinAmountToString(amount);
84 + case CryptoCurrency.xhv:
85 + case CryptoCurrency.xag:
86 + case CryptoCurrency.xau:
87 + case CryptoCurrency.xaud:
88 + case CryptoCurrency.xbtc:
89 + case CryptoCurrency.xcad:
90 + case CryptoCurrency.xchf:
91 + case CryptoCurrency.xcny:
92 + case CryptoCurrency.xeur:
93 + case CryptoCurrency.xgbp:
94 + case CryptoCurrency.xjpy:
95 + case CryptoCurrency.xnok:
96 + case CryptoCurrency.xnzd:
97 + case CryptoCurrency.xusd:
98 + return _moneroAmountToString(amount);
99 default:
100 return null;
101 }
lib/core/seed_validator.dart
+3
@@ -1,4 +1,5 @@
1 import 'package:cake_wallet/bitcoin/bitcoin.dart';
2 +import 'package:cake_wallet/haven/haven.dart';
3 import 'package:cake_wallet/core/validator.dart';
4 import 'package:cake_wallet/entities/mnemonic_item.dart';
5 import 'package:cw_core/wallet_type.dart';
@@ -21,6 +22,8 @@ class SeedValidator extends Validator<MnemonicItem> {
22 return getBitcoinWordList(language);
23 case WalletType.monero:
24 return monero.getMoneroWordList(language);
25 + case WalletType.haven:
26 + return haven.getMoneroWordList(language);
27 default:
28 return [];
29 }
lib/di.dart
+11 -3
@@ -2,6 +2,8 @@ import 'package:cake_wallet/core/yat_service.dart';
2 import 'package:cake_wallet/entities/parse_address_from_domain.dart';
3 import 'package:cake_wallet/entities/wake_lock.dart';
4 import 'package:cake_wallet/monero/monero.dart';
5 +import 'package:cake_wallet/haven/haven.dart';
6 +import 'package:cake_wallet/haven/haven.dart';
7 import 'package:cake_wallet/bitcoin/bitcoin.dart';
8 import 'package:cake_wallet/src/screens/dashboard/widgets/balance_page.dart';
9 import 'package:cw_core/unspent_coins_info.dart';
@@ -122,6 +124,7 @@ import 'package:cake_wallet/store/templates/exchange_template_store.dart';
124 import 'package:cake_wallet/entities/template.dart';
125 import 'package:cake_wallet/exchange/exchange_template.dart';
126 import 'package:cake_wallet/.secrets.g.dart' as secrets;
127 +import 'package:cake_wallet/src/screens/dashboard/widgets/address_page.dart';
128
129 final getIt = GetIt.instance;
130
@@ -312,6 +315,9 @@ Future setup(
315 getIt.registerFactory<DashboardPage>(() => DashboardPage( balancePage: getIt.get<BalancePage>(), walletViewModel: getIt.get<DashboardViewModel>(), addressListViewModel: getIt.get<WalletAddressListViewModel>()));
316 getIt.registerFactory<ReceivePage>(() => ReceivePage(
317 addressListViewModel: getIt.get<WalletAddressListViewModel>()));
318 + getIt.registerFactory<AddressPage>(() => AddressPage(
319 + addressListViewModel: getIt.get<WalletAddressListViewModel>(),
320 + walletViewModel: getIt.get<DashboardViewModel>()));
321
322 getIt.registerFactoryParam<WalletAddressEditOrCreateViewModel, dynamic, void>(
323 (dynamic item, _) => WalletAddressEditOrCreateViewModel(
@@ -344,8 +350,7 @@ Future setup(
350 getIt.registerFactory(() => WalletListViewModel(
351 _walletInfoSource,
352 getIt.get<AppStore>(),
347 - getIt.get<KeyService>(),
348 - getIt.get<WalletNewVM>(param1: WalletType.monero)));
353 + getIt.get<KeyService>()));
354
355 getIt.registerFactory(() =>
356 WalletListPage(walletListViewModel: getIt.get<WalletListViewModel>()));
@@ -353,7 +358,7 @@ Future setup(
358 getIt.registerFactory(() {
359 final wallet = getIt.get<AppStore>().wallet;
360
356 - if (wallet.type == WalletType.monero) {
361 + if (wallet.type == WalletType.monero || wallet.type == WalletType.haven) {
362 return MoneroAccountListViewModel(wallet);
363 }
364
@@ -383,6 +388,7 @@ Future setup(
388 AccountListItem, void>(
389 (AccountListItem account, _) => MoneroAccountEditOrCreateViewModel(
390 monero.getAccountList(getIt.get<AppStore>().wallet),
391 + haven.getAccountList(getIt.get<AppStore>().wallet),
392 wallet: getIt.get<AppStore>().wallet,
393 accountListItem: account));
394
@@ -469,6 +475,8 @@ Future setup(
475 getIt.registerFactoryParam<WalletService, WalletType, void>(
476 (WalletType param1, __) {
477 switch (param1) {
478 + case WalletType.haven:
479 + return haven.createHavenWalletService(_walletInfoSource);
480 case WalletType.monero:
481 return monero.createMoneroWalletService(_walletInfoSource);
482 case WalletType.bitcoin:
lib/entities/calculate_fiat_amount.dart
+12 -1
@@ -11,5 +11,16 @@ String calculateFiatAmount({double price, String cryptoAmount}) {
11 return '0.00';
12 }
13
14 - return result > 0.01 ? result.toStringAsFixed(2) : '< 0.01';
14 + var formatted = '';
15 + final parts = result.toString().split('.');
16 +
17 + if (parts.length >= 2) {
18 + if (parts[1].length > 2) {
19 + formatted = parts[0] + '.' + parts[1].substring(0, 2);
20 + } else {
21 + formatted = parts[0] + '.' + parts[1];
22 + }
23 + }
24 +
25 + return result > 0.01 ? formatted : '< 0.01';
26 }
lib/entities/default_settings_migration.dart
+43
@@ -22,6 +22,7 @@ import 'package:encrypt/encrypt.dart' as encrypt;
22 const newCakeWalletMoneroUri = 'xmr-node.cakewallet.com:18081';
23 const cakeWalletBitcoinElectrumUri = 'electrum.cakewallet.com:50002';
24 const cakeWalletLitecoinElectrumUri = 'ltc-electrum.cakewallet.com:50002';
25 +const havenDefaultNodeUri = 'vault.havenprotocol.org:443';
26
27 Future defaultSettingsMigration(
28 {@required int version,
@@ -120,6 +121,13 @@ Future defaultSettingsMigration(
121 await checkCurrentNodes(nodes, sharedPreferences);
122 break;
123
124 + case 16:
125 + await addHavenNodeList(nodes: nodes);
126 + await changeHavenCurrentNodeToDefault(
127 + sharedPreferences: sharedPreferences, nodes: nodes);
128 + await checkCurrentNodes(nodes, sharedPreferences);
129 + break;
130 +
131 default:
132 break;
133 }
@@ -182,6 +190,14 @@ Node getLitecoinDefaultElectrumServer({@required Box<Node> nodes}) {
190 orElse: () => null);
191 }
192
193 +Node getHavenDefaultNode({@required Box<Node> nodes}) {
194 + return nodes.values.firstWhere(
195 + (Node node) => node.uriRaw == havenDefaultNodeUri,
196 + orElse: () => null) ??
197 + nodes.values.firstWhere((node) => node.type == WalletType.haven,
198 + orElse: () => null);
199 +}
200 +
201 Node getMoneroDefaultNode({@required Box<Node> nodes}) {
202 final timeZone = DateTime.now().timeZoneOffset.inHours;
203 var nodeUri = '';
@@ -217,6 +233,15 @@ Future<void> changeLitecoinCurrentElectrumServerToDefault(
233 await sharedPreferences.setInt('current_node_id_ltc', serverId);
234 }
235
236 +Future<void> changeHavenCurrentNodeToDefault(
237 + {@required SharedPreferences sharedPreferences,
238 + @required Box<Node> nodes}) async {
239 + final node = getHavenDefaultNode(nodes: nodes);
240 + final nodeId = node?.key as int ?? 0;
241 +
242 + await sharedPreferences.setInt(PreferencesKey.currentHavenNodeIdKey, nodeId);
243 +}
244 +
245 Future<void> replaceDefaultNode(
246 {@required SharedPreferences sharedPreferences,
247 @required Box<Node> nodes}) async {
@@ -258,6 +283,11 @@ Future<void> addLitecoinElectrumServerList({@required Box<Node> nodes}) async {
283 await nodes.addAll(serverList);
284 }
285
286 +Future<void> addHavenNodeList({@required Box<Node> nodes}) async {
287 + final nodeList = await loadDefaultHavenNodes();
288 + await nodes.addAll(nodeList);
289 +}
290 +
291 Future<void> addAddressesForMoneroWallets(
292 Box<WalletInfo> walletInfoSource) async {
293 final moneroWalletsInfo =
@@ -347,6 +377,8 @@ Future<void> checkCurrentNodes(
377 sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);
378 final currentLitecoinElectrumSeverId = sharedPreferences
379 .getInt(PreferencesKey.currentLitecoinElectrumSererIdKey);
380 + final currentHavenNodeId = sharedPreferences
381 + .getInt(PreferencesKey.currentHavenNodeIdKey);
382 final currentMoneroNode = nodeSource.values.firstWhere(
383 (node) => node.key == currentMoneroNodeId,
384 orElse: () => null);
@@ -356,6 +388,9 @@ Future<void> checkCurrentNodes(
388 final currentLitecoinElectrumServer = nodeSource.values.firstWhere(
389 (node) => node.key == currentLitecoinElectrumSeverId,
390 orElse: () => null);
391 + final currentHavenNodeServer = nodeSource.values.firstWhere(
392 + (node) => node.key == currentHavenNodeId,
393 + orElse: () => null);
394
395 if (currentMoneroNode == null) {
396 final newCakeWalletNode =
@@ -382,6 +417,14 @@ Future<void> checkCurrentNodes(
417 PreferencesKey.currentLitecoinElectrumSererIdKey,
418 cakeWalletElectrum.key as int);
419 }
420 +
421 + if (currentHavenNodeServer == null) {
422 + final nodes = await loadDefaultHavenNodes();
423 + final node = nodes.first;
424 + await nodeSource.add(node);
425 + await sharedPreferences.setInt(
426 + PreferencesKey.currentHavenNodeIdKey, node.key as int);
427 + }
428 }
429
430 Future<void> resetBitcoinElectrumServer(
lib/entities/node_list.dart
+21 -1
@@ -54,12 +54,32 @@ Future<List<Node>> loadLitecoinElectrumServerList() async {
54 }).toList();
55 }
56
57 +Future<List<Node>> loadDefaultHavenNodes() async {
58 + final nodesRaw = await rootBundle.loadString('assets/haven_node_list.yml');
59 + final nodes = loadYaml(nodesRaw) as YamlList;
60 +
61 + return nodes.map((dynamic raw) {
62 + if (raw is Map) {
63 + final node = Node.fromMap(raw);
64 + node?.type = WalletType.haven;
65 +
66 + return node;
67 + }
68 +
69 + return null;
70 + }).toList();
71 +}
72 +
73 Future resetToDefault(Box<Node> nodeSource) async {
74 final moneroNodes = await loadDefaultNodes();
75 final bitcoinElectrumServerList = await loadBitcoinElectrumServerList();
76 final litecoinElectrumServerList = await loadLitecoinElectrumServerList();
77 + final havenNodes = await loadDefaultHavenNodes();
78 final nodes =
62 - moneroNodes + bitcoinElectrumServerList + litecoinElectrumServerList;
79 + moneroNodes +
80 + bitcoinElectrumServerList +
81 + litecoinElectrumServerList +
82 + havenNodes;
83
84 await nodeSource.clear();
85 await nodeSource.addAll(nodes);
lib/entities/preferences_key.dart
+1
@@ -4,6 +4,7 @@ class PreferencesKey {
4 static const currentNodeIdKey = 'current_node_id';
5 static const currentBitcoinElectrumSererIdKey = 'current_node_id_btc';
6 static const currentLitecoinElectrumSererIdKey = 'current_node_id_ltc';
7 + static const currentHavenNodeIdKey = 'current_node_id_xhv';
8 static const currentFiatCurrencyKey = 'current_fiat_currency';
9 static const currentTransactionPriorityKeyLegacy = 'current_fee_priority';
10 static const currentBalanceDisplayModeKey = 'current_balance_display_mode';
lib/entities/update_haven_rate.dart new
+21
@@ -0,0 +1,21 @@
1 +import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
2 +import 'package:cw_core/crypto_currency.dart';
3 +import 'package:cw_core/monero_amount_format.dart';
4 +import 'package:cw_haven/api/balance_list.dart';
5 +
6 +Future<void> updateHavenRate(FiatConversionStore fiatConversionStore) async {
7 + final rate = getRate();
8 + final base = rate.firstWhere((row) => row.getAssetType() == 'XUSD', orElse: () => null);
9 + rate.forEach((row) {
10 + final cur = CryptoCurrency.fromString(row.getAssetType());
11 + final baseRate = moneroAmountToDouble(amount: base.getRate());
12 + final rowRate = moneroAmountToDouble(amount: row.getRate());
13 +
14 + if (cur == CryptoCurrency.xusd) {
15 + fiatConversionStore.prices[cur] = 1.0;
16 + return;
17 + }
18 +
19 + fiatConversionStore.prices[cur] = baseRate / rowRate;
20 + });
21 +}
\ No newline at end of file
lib/haven/cw_haven.dart new
+298
@@ -0,0 +1,298 @@
1 +part of 'haven.dart';
2 +
3 +class CWHavenAccountList extends HavenAccountList {
4 + CWHavenAccountList(this._wallet);
5 + Object _wallet;
6 +
7 + @override
8 + @computed
9 + ObservableList<Account> get accounts {
10 + final havenWallet = _wallet as HavenWallet;
11 + final accounts = havenWallet.walletAddresses.accountList
12 + .accounts
13 + .map((acc) => Account(id: acc.id, label: acc.label))
14 + .toList();
15 + return ObservableList<Account>.of(accounts);
16 + }
17 +
18 + @override
19 + void update(Object wallet) {
20 + final havenWallet = wallet as HavenWallet;
21 + havenWallet.walletAddresses.accountList.update();
22 + }
23 +
24 + @override
25 + void refresh(Object wallet) {
26 + final havenWallet = wallet as HavenWallet;
27 + havenWallet.walletAddresses.accountList.refresh();
28 + }
29 +
30 + @override
31 + List<Account> getAll(Object wallet) {
32 + final havenWallet = wallet as HavenWallet;
33 + return havenWallet.walletAddresses.accountList
34 + .getAll()
35 + .map((acc) => Account(id: acc.id, label: acc.label))
36 + .toList();
37 + }
38 +
39 + @override
40 + Future<void> addAccount(Object wallet, {String label}) async {
41 + final havenWallet = wallet as HavenWallet;
42 + await havenWallet.walletAddresses.accountList.addAccount(label: label);
43 + }
44 +
45 + @override
46 + Future<void> setLabelAccount(Object wallet, {int accountIndex, String label}) async {
47 + final havenWallet = wallet as HavenWallet;
48 + await havenWallet.walletAddresses.accountList
49 + .setLabelAccount(
50 + accountIndex: accountIndex,
51 + label: label);
52 + }
53 +}
54 +
55 +class CWHavenSubaddressList extends MoneroSubaddressList {
56 + CWHavenSubaddressList(this._wallet);
57 + Object _wallet;
58 +
59 + @override
60 + @computed
61 + ObservableList<Subaddress> get subaddresses {
62 + final havenWallet = _wallet as HavenWallet;
63 + final subAddresses = havenWallet.walletAddresses.subaddressList
64 + .subaddresses
65 + .map((sub) => Subaddress(
66 + id: sub.id,
67 + address: sub.address,
68 + label: sub.label))
69 + .toList();
70 + return ObservableList<Subaddress>.of(subAddresses);
71 + }
72 +
73 + @override
74 + void update(Object wallet, {int accountIndex}) {
75 + final havenWallet = wallet as HavenWallet;
76 + havenWallet.walletAddresses.subaddressList.update(accountIndex: accountIndex);
77 + }
78 +
79 + @override
80 + void refresh(Object wallet, {int accountIndex}) {
81 + final havenWallet = wallet as HavenWallet;
82 + havenWallet.walletAddresses.subaddressList.refresh(accountIndex: accountIndex);
83 + }
84 +
85 + @override
86 + List<Subaddress> getAll(Object wallet) {
87 + final havenWallet = wallet as HavenWallet;
88 + return havenWallet.walletAddresses
89 + .subaddressList
90 + .getAll()
91 + .map((sub) => Subaddress(id: sub.id, label: sub.label, address: sub.address))
92 + .toList();
93 + }
94 +
95 + @override
96 + Future<void> addSubaddress(Object wallet, {int accountIndex, String label}) async {
97 + final havenWallet = wallet as HavenWallet;
98 + await havenWallet.walletAddresses.subaddressList
99 + .addSubaddress(
100 + accountIndex: accountIndex,
101 + label: label);
102 + }
103 +
104 + @override
105 + Future<void> setLabelSubaddress(Object wallet,
106 + {int accountIndex, int addressIndex, String label}) async {
107 + final havenWallet = wallet as HavenWallet;
108 + await havenWallet.walletAddresses.subaddressList
109 + .setLabelSubaddress(
110 + accountIndex: accountIndex,
111 + addressIndex: addressIndex,
112 + label: label);
113 + }
114 +}
115 +
116 +class CWHavenWalletDetails extends HavenWalletDetails {
117 + CWHavenWalletDetails(this._wallet);
118 + Object _wallet;
119 +
120 + @computed
121 + Account get account {
122 + final havenWallet = _wallet as HavenWallet;
123 + final acc = havenWallet.walletAddresses.account as monero_account.Account;
124 + return Account(id: acc.id, label: acc.label);
125 + }
126 +
127 + @computed
128 + HavenBalance get balance {
129 + final havenWallet = _wallet as HavenWallet;
130 + final balance = havenWallet.balance;
131 + return null;
132 + //return HavenBalance(
133 + // fullBalance: balance.fullBalance,
134 + // unlockedBalance: balance.unlockedBalance);
135 + }
136 +}
137 +
138 +class CWHaven extends Haven {
139 + HavenAccountList getAccountList(Object wallet) {
140 + return CWHavenAccountList(wallet);
141 + }
142 +
143 + MoneroSubaddressList getSubaddressList(Object wallet) {
144 + return CWHavenSubaddressList(wallet);
145 + }
146 +
147 + TransactionHistoryBase getTransactionHistory(Object wallet) {
148 + final havenWallet = wallet as HavenWallet;
149 + return havenWallet.transactionHistory;
150 + }
151 +
152 + HavenWalletDetails getMoneroWalletDetails(Object wallet) {
153 + return CWHavenWalletDetails(wallet);
154 + }
155 +
156 + int getHeigthByDate({DateTime date}) {
157 + return getMoneroHeigthByDate(date: date);
158 + }
159 +
160 + TransactionPriority getDefaultTransactionPriority() {
161 + return MoneroTransactionPriority.slow;
162 + }
163 +
164 + TransactionPriority deserializeMoneroTransactionPriority({int raw}) {
165 + return MoneroTransactionPriority.deserialize(raw: raw);
166 + }
167 +
168 + List<TransactionPriority> getTransactionPriorities() {
169 + return MoneroTransactionPriority.all;
170 + }
171 +
172 + List<String> getMoneroWordList(String language) {
173 + switch (language.toLowerCase()) {
174 + case 'english':
175 + return EnglishMnemonics.words;
176 + case 'chinese (simplified)':
177 + return ChineseSimplifiedMnemonics.words;
178 + case 'dutch':
179 + return DutchMnemonics.words;
180 + case 'german':
181 + return GermanMnemonics.words;
182 + case 'japanese':
183 + return JapaneseMnemonics.words;
184 + case 'portuguese':
185 + return PortugueseMnemonics.words;
186 + case 'russian':
187 + return RussianMnemonics.words;
188 + case 'spanish':
189 + return SpanishMnemonics.words;
190 + case 'french':
191 + return FrenchMnemonics.words;
192 + case 'italian':
193 + return ItalianMnemonics.words;
194 + default:
195 + return EnglishMnemonics.words;
196 + }
197 + }
198 +
199 + WalletCredentials createHavenRestoreWalletFromKeysCredentials({
200 + String name,
201 + String spendKey,
202 + String viewKey,
203 + String address,
204 + String password,
205 + String language,
206 + int height}) {
207 + return HavenRestoreWalletFromKeysCredentials(
208 + name: name,
209 + spendKey: spendKey,
210 + viewKey: viewKey,
211 + address: address,
212 + password: password,
213 + language: language,
214 + height: height);
215 + }
216 +
217 + WalletCredentials createHavenRestoreWalletFromSeedCredentials({String name, String password, int height, String mnemonic}) {
218 + return HavenRestoreWalletFromSeedCredentials(
219 + name: name,
220 + password: password,
221 + height: height,
222 + mnemonic: mnemonic);
223 + }
224 +
225 + WalletCredentials createHavenNewWalletCredentials({String name, String password, String language}) {
226 + return HavenNewWalletCredentials(
227 + name: name,
228 + password: password,
229 + language: language);
230 + }
231 +
232 + Map<String, String> getKeys(Object wallet) {
233 + final havenWallet = wallet as HavenWallet;
234 + final keys = havenWallet.keys;
235 + return <String, String>{
236 + 'privateSpendKey': keys.privateSpendKey,
237 + 'privateViewKey': keys.privateViewKey,
238 + 'publicSpendKey': keys.publicSpendKey,
239 + 'publicViewKey': keys.publicViewKey};
240 + }
241 +
242 + Object createHavenTransactionCreationCredentials({List<Output> outputs, TransactionPriority priority, String assetType}) {
243 + return HavenTransactionCreationCredentials(
244 + outputs: outputs.map((out) => OutputInfo(
245 + fiatAmount: out.fiatAmount,
246 + cryptoAmount: out.cryptoAmount,
247 + address: out.address,
248 + note: out.note,
249 + sendAll: out.sendAll,
250 + extractedAddress: out.extractedAddress,
251 + isParsedAddress: out.isParsedAddress,
252 + formattedCryptoAmount: out.formattedCryptoAmount))
253 + .toList(),
254 + priority: priority as MoneroTransactionPriority,
255 + assetType: assetType);
256 + }
257 +
258 + String formatterMoneroAmountToString({int amount}) {
259 + return moneroAmountToString(amount: amount);
260 + }
261 +
262 + double formatterMoneroAmountToDouble({int amount}) {
263 + return moneroAmountToDouble(amount: amount);
264 + }
265 +
266 + int formatterMoneroParseAmount({String amount}) {
267 + return moneroParseAmount(amount: amount);
268 + }
269 +
270 + Account getCurrentAccount(Object wallet) {
271 + final havenWallet = wallet as HavenWallet;
272 + final acc = havenWallet.walletAddresses.account as monero_account.Account;
273 + return Account(id: acc.id, label: acc.label);
274 + }
275 +
276 + void setCurrentAccount(Object wallet, int id, String label) {
277 + final havenWallet = wallet as HavenWallet;
278 + havenWallet.walletAddresses.account = monero_account.Account(id: id, label: label);
279 + }
280 +
281 + void onStartup() {
282 + monero_wallet_api.onStartup();
283 + }
284 +
285 + int getTransactionInfoAccountId(TransactionInfo tx) {
286 + final havenTransactionInfo = tx as HavenTransactionInfo;
287 + return havenTransactionInfo.accountIndex;
288 + }
289 +
290 + WalletService createHavenWalletService(Box<WalletInfo> walletInfoSource) {
291 + return HavenWalletService(walletInfoSource);
292 + }
293 +
294 + String getTransactionAddress(Object wallet, int accountIndex, int addressIndex) {
295 + final havenWallet = wallet as HavenWallet;
296 + return havenWallet.getTransactionAddress(accountIndex, addressIndex);
297 + }
298 +}
lib/haven/haven.dart new
+144
@@ -0,0 +1,144 @@
1 +import 'package:mobx/mobx.dart';
2 +import 'package:flutter/foundation.dart';
3 +import 'package:cw_core/wallet_credentials.dart';
4 +import 'package:cw_core/wallet_info.dart';
5 +import 'package:cw_core/transaction_priority.dart';
6 +import 'package:cw_core/transaction_history.dart';
7 +import 'package:cw_core/transaction_info.dart';
8 +import 'package:cw_core/balance.dart';
9 +import 'package:cw_core/output_info.dart';
10 +import 'package:cake_wallet/view_model/send/output.dart';
11 +import 'package:cw_core/wallet_service.dart';
12 +import 'package:hive/hive.dart';
13 +import 'package:cw_core/get_height_by_date.dart';
14 +import 'package:cw_core/monero_amount_format.dart';
15 +import 'package:cw_core/monero_transaction_priority.dart';
16 +import 'package:cw_haven/haven_wallet_service.dart';
17 +import 'package:cw_haven/haven_wallet.dart';
18 +import 'package:cw_haven/haven_transaction_info.dart';
19 +import 'package:cw_haven/haven_transaction_history.dart';
20 +import 'package:cw_core/account.dart' as monero_account;
21 +import 'package:cw_haven/api/wallet.dart' as monero_wallet_api;
22 +import 'package:cw_haven/mnemonics/english.dart';
23 +import 'package:cw_haven/mnemonics/chinese_simplified.dart';
24 +import 'package:cw_haven/mnemonics/dutch.dart';
25 +import 'package:cw_haven/mnemonics/german.dart';
26 +import 'package:cw_haven/mnemonics/japanese.dart';
27 +import 'package:cw_haven/mnemonics/russian.dart';
28 +import 'package:cw_haven/mnemonics/spanish.dart';
29 +import 'package:cw_haven/mnemonics/portuguese.dart';
30 +import 'package:cw_haven/mnemonics/french.dart';
31 +import 'package:cw_haven/mnemonics/italian.dart';
32 +import 'package:cw_haven/haven_transaction_creation_credentials.dart';
33 +
34 +part 'cw_haven.dart';
35 +
36 +Haven haven = CWHaven();
37 +
38 +class Account {
39 + Account({this.id, this.label});
40 + final int id;
41 + final String label;
42 +}
43 +
44 +class Subaddress {
45 + Subaddress({this.id, this.accountId, this.label, this.address});
46 + final int id;
47 + final int accountId;
48 + final String label;
49 + final String address;
50 +}
51 +
52 +class HavenBalance extends Balance {
53 + HavenBalance({@required this.fullBalance, @required this.unlockedBalance})
54 + : formattedFullBalance = haven.formatterMoneroAmountToString(amount: fullBalance),
55 + formattedUnlockedBalance =
56 + haven.formatterMoneroAmountToString(amount: unlockedBalance),
57 + super(unlockedBalance, fullBalance);
58 +
59 + HavenBalance.fromString(
60 + {@required this.formattedFullBalance,
61 + @required this.formattedUnlockedBalance})
62 + : fullBalance = haven.formatterMoneroParseAmount(amount: formattedFullBalance),
63 + unlockedBalance = haven.formatterMoneroParseAmount(amount: formattedUnlockedBalance),
64 + super(haven.formatterMoneroParseAmount(amount: formattedUnlockedBalance),
65 + haven.formatterMoneroParseAmount(amount: formattedFullBalance));
66 +
67 + final int fullBalance;
68 + final int unlockedBalance;
69 + final String formattedFullBalance;
70 + final String formattedUnlockedBalance;
71 +
72 + @override
73 + String get formattedAvailableBalance => formattedUnlockedBalance;
74 +
75 + @override
76 + String get formattedAdditionalBalance => formattedFullBalance;
77 +}
78 +
79 +abstract class HavenWalletDetails {
80 + @observable
81 + Account account;
82 +
83 + @observable
84 + HavenBalance balance;
85 +}
86 +
87 +abstract class Haven {
88 + HavenAccountList getAccountList(Object wallet);
89 +
90 + MoneroSubaddressList getSubaddressList(Object wallet);
91 +
92 + TransactionHistoryBase getTransactionHistory(Object wallet);
93 +
94 + HavenWalletDetails getMoneroWalletDetails(Object wallet);
95 +
96 + String getTransactionAddress(Object wallet, int accountIndex, int addressIndex);
97 +
98 + int getHeigthByDate({DateTime date});
99 + TransactionPriority getDefaultTransactionPriority();
100 + TransactionPriority deserializeMoneroTransactionPriority({int raw});
101 + List<TransactionPriority> getTransactionPriorities();
102 + List<String> getMoneroWordList(String language);
103 +
104 + WalletCredentials createHavenRestoreWalletFromKeysCredentials({
105 + String name,
106 + String spendKey,
107 + String viewKey,
108 + String address,
109 + String password,
110 + String language,
111 + int height});
112 + WalletCredentials createHavenRestoreWalletFromSeedCredentials({String name, String password, int height, String mnemonic});
113 + WalletCredentials createHavenNewWalletCredentials({String name, String password, String language});
114 + Map<String, String> getKeys(Object wallet);
115 + Object createHavenTransactionCreationCredentials({List<Output> outputs, TransactionPriority priority, String assetType});
116 + String formatterMoneroAmountToString({int amount});
117 + double formatterMoneroAmountToDouble({int amount});
118 + int formatterMoneroParseAmount({String amount});
119 + Account getCurrentAccount(Object wallet);
120 + void setCurrentAccount(Object wallet, int id, String label);
121 + void onStartup();
122 + int getTransactionInfoAccountId(TransactionInfo tx);
123 + WalletService createHavenWalletService(Box<WalletInfo> walletInfoSource);
124 +}
125 +
126 +abstract class MoneroSubaddressList {
127 + ObservableList<Subaddress> get subaddresses;
128 + void update(Object wallet, {int accountIndex});
129 + void refresh(Object wallet, {int accountIndex});
130 + List<Subaddress> getAll(Object wallet);
131 + Future<void> addSubaddress(Object wallet, {int accountIndex, String label});
132 + Future<void> setLabelSubaddress(Object wallet,
133 + {int accountIndex, int addressIndex, String label});
134 +}
135 +
136 +abstract class HavenAccountList {
137 + ObservableList<Account> get accounts;
138 + void update(Object wallet);
139 + void refresh(Object wallet);
140 + List<Account> getAll(Object wallet);
141 + Future<void> addAccount(Object wallet, {String label});
142 + Future<void> setLabelAccount(Object wallet, {int accountIndex, String label});
143 +}
144 +
\ No newline at end of file
lib/main.dart
+12 -1
@@ -112,6 +112,17 @@ Future<void> main() async {
112 if (!isMoneroOnly) {
113 unspentCoinsInfoSource = await Hive.openBox<UnspentCoinsInfo>(UnspentCoinsInfo.boxName);
114 }
115 +
116 + FlutterError.onError = (FlutterErrorDetails details) {
117 + runApp(MaterialApp(
118 + debugShowCheckedModeBanner: true,
119 + home: Scaffold(
120 + body: Container(
121 + margin: EdgeInsets.only(top: 50, left: 20, right: 20, bottom: 20),
122 + child: Text(
123 + 'Error:\n${details.stack.toString()}',
124 + style: TextStyle(fontSize: 22))))));
125 + };
126
127 await initialSetup(
128 sharedPreferences: await SharedPreferences.getInstance(),
@@ -126,7 +137,7 @@ Future<void> main() async {
137 exchangeTemplates: exchangeTemplates,
138 transactionDescriptions: transactionDescriptions,
139 secureStorage: secureStorage,
129 - initialMigrationVersion: 15);
140 + initialMigrationVersion: 16);
141 runApp(App());
142 } catch (e) {
143 runApp(MaterialApp(
lib/monero/cw_monero.dart
+6 -5
@@ -128,9 +128,10 @@ class CWMoneroWalletDetails extends MoneroWalletDetails {
128 MoneroBalance get balance {
129 final moneroWallet = _wallet as MoneroWallet;
130 final balance = moneroWallet.balance;
131 - return MoneroBalance(
132 - fullBalance: balance.fullBalance,
133 - unlockedBalance: balance.unlockedBalance);
131 + return MoneroBalance();
132 + //return MoneroBalance(
133 + // fullBalance: balance.fullBalance,
134 + // unlockedBalance: balance.unlockedBalance);
135 }
136 }
137
@@ -271,9 +272,9 @@ class CWMonero extends Monero {
272 return Account(id: acc.id, label: acc.label);
273 }
274
274 - void setCurrentAccount(Object wallet, Account account) {
275 + void setCurrentAccount(Object wallet, int id, String label) {
276 final moneroWallet = wallet as MoneroWallet;
276 - moneroWallet.walletAddresses.account = monero_account.Account(id: account.id, label: account.label);
277 + moneroWallet.walletAddresses.account = monero_account.Account(id: id, label: label);
278 }
279
280 void onStartup() {
lib/reactions/fiat_rate_update.dart
+14 -3
@@ -1,8 +1,10 @@
1 import 'dart:async';
2 import 'package:cake_wallet/core/fiat_conversion_service.dart';
3 +import 'package:cake_wallet/entities/update_haven_rate.dart';
4 import 'package:cake_wallet/store/app_store.dart';
5 import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
6 import 'package:cake_wallet/store/settings_store.dart';
7 +import 'package:cw_core/wallet_type.dart';
8
9 Timer _timer;
10
@@ -18,7 +20,16 @@ Future<void> startFiatRateUpdate(AppStore appStore, SettingsStore settingsStore,
20
21 _timer = Timer.periodic(
22 Duration(seconds: 30),
21 - (_) async => fiatConversionStore.prices[appStore.wallet.currency] =
22 - await FiatConversionService.fetchPrice(
23 - appStore.wallet.currency, settingsStore.fiatCurrency));
23 + (_) async {
24 + try {
25 + if (appStore.wallet.type == WalletType.haven) {
26 + await updateHavenRate(fiatConversionStore);
27 + } else {
28 + fiatConversionStore.prices[appStore.wallet.currency] = await FiatConversionService.fetchPrice(
29 + appStore.wallet.currency, settingsStore.fiatCurrency);
30 + }
31 + } catch(e) {
32 + print(e);
33 + }
34 + });
35 }
lib/reactions/on_current_wallet_change.dart
+8 -1
@@ -1,3 +1,5 @@
1 +import 'package:cake_wallet/entities/fiat_currency.dart';
2 +import 'package:cake_wallet/entities/update_haven_rate.dart';
3 import 'package:cw_core/transaction_history.dart';
4 import 'package:cw_core/balance.dart';
5 import 'package:cw_core/transaction_info.dart';
@@ -51,7 +53,7 @@ void startCurrentWalletChangeReaction(AppStore appStore,
53 wallet) async {
54 try {
55 final node = settingsStore.getCurrentNode(wallet.type);
54 - startWalletSyncStatusChangeReaction(wallet);
56 + startWalletSyncStatusChangeReaction(wallet, fiatConversionStore);
57 startCheckConnectionReaction(wallet, settingsStore);
58 await getIt
59 .get<SharedPreferences>()
@@ -60,6 +62,11 @@ void startCurrentWalletChangeReaction(AppStore appStore,
62 PreferencesKey.currentWalletType, serializeToInt(wallet.type));
63 await wallet.connectToNode(node: node);
64
65 + if (wallet.type == WalletType.haven) {
66 + settingsStore.fiatCurrency = FiatCurrency.usd;
67 + await updateHavenRate(fiatConversionStore);
68 + }
69 +
70 if (wallet.walletInfo.address?.isEmpty ?? true) {
71 wallet.walletInfo.address = wallet.walletAddresses.address;
72
lib/reactions/on_wallet_sync_status_change.dart
+9 -2
@@ -1,5 +1,8 @@
1 import 'package:cake_wallet/di.dart';
2 +import 'package:cake_wallet/entities/update_haven_rate.dart';
3 import 'package:cake_wallet/entities/wake_lock.dart';
4 +import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
5 +import 'package:cw_core/wallet_type.dart';
6 import 'package:mobx/mobx.dart';
7 import 'package:cw_core/transaction_history.dart';
8 import 'package:cw_core/wallet_base.dart';
@@ -12,14 +15,18 @@ ReactionDisposer _onWalletSyncStatusChangeReaction;
15
16 void startWalletSyncStatusChangeReaction(
17 WalletBase<Balance, TransactionHistoryBase<TransactionInfo>,
15 - TransactionInfo>
16 - wallet) {
18 + TransactionInfo> wallet,
19 + FiatConversionStore fiatConversionStore) {
20 final _wakeLock = getIt.get<WakeLock>();
21 _onWalletSyncStatusChangeReaction?.reaction?.dispose();
22 _onWalletSyncStatusChangeReaction =
23 reaction((_) => wallet.syncStatus, (SyncStatus status) async {
24 if (status is ConnectedSyncStatus) {
25 await wallet.startSync();
26 +
27 + if (wallet.type == WalletType.haven) {
28 + await updateHavenRate(fiatConversionStore);
29 + }
30 }
31 if (status is SyncingSyncStatus) {
32 await _wakeLock.enableWake();
lib/router.dart
+11 -5
@@ -68,6 +68,8 @@ import 'package:cake_wallet/src/screens/exchange_trade/exchange_trade_page.dart'
68 import 'package:flutter/services.dart';
69 import 'package:hive/hive.dart';
70 import 'package:cake_wallet/wallet_type_utils.dart';
71 +import 'package:cake_wallet/wallet_types.g.dart';
72 +import 'package:cake_wallet/src/screens/dashboard/widgets/address_page.dart';
73
74 RouteSettings currentRouteSettings;
75
@@ -82,11 +84,11 @@ Route<dynamic> createRoute(RouteSettings settings) {
84 return CupertinoPageRoute<void>(
85 builder: (_) => getIt.get<SetupPinCodePage>(
86 param1: (PinCodeState<PinCodeWidget> context, dynamic _) {
85 - if (isMoneroOnly) {
86 - Navigator.of(context.context).pushNamed(Routes.newWallet, arguments: WalletType.monero);
87 - } else {
88 - Navigator.of(context.context).pushNamed(Routes.newWalletType);
89 - }
87 + if (availableWalletTypes.length == 1) {
88 + Navigator.of(context.context).pushNamed(Routes.newWallet, arguments: availableWalletTypes.first);
89 + } else {
90 + Navigator.of(context.context).pushNamed(Routes.newWalletType);
91 + }
92 }),
93 fullscreenDialog: true);
94
@@ -216,6 +218,10 @@ Route<dynamic> createRoute(RouteSettings settings) {
218 return CupertinoPageRoute<void>(
219 fullscreenDialog: true, builder: (_) => getIt.get<ReceivePage>());
220
221 + case Routes.addressPage:
222 + return CupertinoPageRoute<void>(
223 + fullscreenDialog: true, builder: (_) => getIt.get<AddressPage>());
224 +
225 case Routes.transactionDetails:
226 return CupertinoPageRoute<void>(
227 fullscreenDialog: true,
lib/routes.dart
+1
@@ -59,4 +59,5 @@ class Routes {
59 static const unspentCoinsDetails = '/unspent_coins_details';
60 static const moneroRestoreWalletFromWelcome = '/monero_restore_wallet';
61 static const moneroNewWalletFromWelcome = '/monero_new_wallet';
62 + static const addressPage = '/address_page';
63 }
\ No newline at end of file
lib/src/screens/contact/contact_list_page.dart
+3
@@ -224,6 +224,9 @@ class ContactListPage extends BasePage {
224 case CryptoCurrency.xrp:
225 image = Image.asset('assets/images/xrp.png', height: 24, width: 24);
226 break;
227 + case CryptoCurrency.xhv:
228 + image = Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
229 + break;
230 default:
231 image = null;
232 }
lib/src/screens/dashboard/dashboard_page.dart
+105 -58
@@ -85,7 +85,7 @@ class DashboardPage extends BasePage {
85
86 final DashboardViewModel walletViewModel;
87 final WalletAddressListViewModel addressListViewModel;
88 - final controller = PageController(initialPage: 1);
88 + final controller = PageController(initialPage: 0);
89
90 var pages = <Widget>[];
91 bool _isEffectsInstalled = false;
@@ -101,21 +101,10 @@ class DashboardPage extends BasePage {
101 height: 24,
102 width: 24,
103 color: Theme.of(context).accentTextTheme.display3.backgroundColor);
104 - final exchangeImage = Image.asset('assets/images/transfer.png',
105 - height: 24,
106 - width: 24,
107 - color: Theme.of(context).accentTextTheme.display3.backgroundColor);
108 - final buyImage = Image.asset('assets/images/buy.png',
109 - height: 24,
110 - width: 24,
111 - color: Theme.of(context).accentTextTheme.display3.backgroundColor);
112 - final sellImage = Image.asset('assets/images/sell.png',
113 - height: 24,
114 - width: 24,
115 - color: Theme.of(context).accentTextTheme.display3.backgroundColor);
104 _setEffects(context);
105
106 return SafeArea(
107 + minimum: EdgeInsets.only(bottom: 24),
108 child: Column(
109 mainAxisSize: MainAxisSize.max,
110 children: <Widget>[
@@ -125,7 +114,7 @@ class DashboardPage extends BasePage {
114 itemCount: pages.length,
115 itemBuilder: (context, index) => pages[index])),
116 Padding(
128 - padding: EdgeInsets.only(bottom: 24),
117 + padding: EdgeInsets.only(bottom: 24, top: 10),
118 child: SmoothPageIndicator(
119 controller: controller,
120 count: pages.length,
@@ -140,48 +129,89 @@ class DashboardPage extends BasePage {
129 .display1
130 .backgroundColor),
131 )),
143 -
144 - ClipRect(
145 - child:Container(
146 - margin: const EdgeInsets.only(left: 16, right: 16, bottom: 38),
147 - child: Container(
148 - decoration: BoxDecoration(
149 - borderRadius: BorderRadius.circular(50.0),
150 - border: Border.all(color: currentTheme.type == ThemeType.bright ? Color.fromRGBO(255, 255, 255, 0.2): Colors.transparent, width: 1, ),
151 - color:Theme.of(context).textTheme.title.backgroundColor
152 - ),
153 - child: Container(
154 - padding: EdgeInsets.only(left: 32, right: 32, bottom: 14, top: 16),
155 - child: Row(
156 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
157 - children: <Widget>[
158 - if (!isMoneroOnly)
132 + Observer(builder: (_) {
133 + return ClipRect(
134 + child:Container(
135 + margin: const EdgeInsets.only(left: 16, right: 16),
136 + child: Container(
137 + decoration: BoxDecoration(
138 + borderRadius: BorderRadius.circular(50.0),
139 + border: Border.all(color: currentTheme.type == ThemeType.bright ? Color.fromRGBO(255, 255, 255, 0.2): Colors.transparent, width: 1, ),
140 + color:Theme.of(context).textTheme.title.backgroundColor),
141 + child: Container(
142 + padding: EdgeInsets.only(left: 32, right: 32),
143 + child: Row(
144 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
145 + children: <Widget>[
146 + if (walletViewModel.hasBuyAction)
147 + ActionButton(
148 + image: Image.asset('assets/images/buy.png',
149 + height: 24,
150 + width: 24,
151 + color: !walletViewModel.isEnabledBuyAction
152 + ? Theme.of(context)
153 + .accentTextTheme
154 + .display2
155 + .backgroundColor
156 + : Theme.of(context).accentTextTheme.display3.backgroundColor),
157 + title: S.of(context).buy,
158 + onClick: () async => await _onClickBuyButton(context),
159 + textColor: !walletViewModel.isEnabledBuyAction
160 + ? Theme.of(context)
161 + .accentTextTheme
162 + .display2
163 + .backgroundColor
164 + : null),
165 ActionButton(
160 - image: buyImage,
161 - title: S.of(context).buy,
162 - onClick: () async => await _onClickBuyButton(context),
163 - ),
164 - ActionButton(
165 - image: receiveImage,
166 - title: S.of(context).receive,
167 - route: Routes.receive),
168 - ActionButton(
169 - image: exchangeImage,
170 - title: S.of(context).exchange,
171 - route: Routes.exchange),
172 - ActionButton(
173 - image: sendImage,
174 - title: S.of(context).send,
175 - route: Routes.send),
176 - if (!isMoneroOnly)
166 + image: receiveImage,
167 + title: S.of(context).receive,
168 + route: Routes.addressPage),
169 + if (walletViewModel.hasExchangeAction)
170 + ActionButton(
171 + image: Image.asset('assets/images/transfer.png',
172 + height: 24,
173 + width: 24,
174 + color: !walletViewModel.isEnabledExchangeAction
175 + ? Theme.of(context)
176 + .accentTextTheme
177 + .display2
178 + .backgroundColor
179 + : Theme.of(context).accentTextTheme.display3.backgroundColor),
180 + title: S.of(context).exchange,
181 + onClick: () async => _onClickExchangeButton(context),
182 + textColor: !walletViewModel.isEnabledExchangeAction
183 + ? Theme.of(context)
184 + .accentTextTheme
185 + .display2
186 + .backgroundColor
187 + : null),
188 ActionButton(
178 - image: sellImage,
179 - title: S.of(context).sell,
180 - onClick: () async => await _onClickSellButton(context),
181 - ),
182 - ],
183 - ),),
184 - ),),),
189 + image: sendImage,
190 + title: S.of(context).send,
191 + route: Routes.send),
192 + if (walletViewModel.hasSellAction)
193 + ActionButton(
194 + image: Image.asset('assets/images/sell.png',
195 + height: 24,
196 + width: 24,
197 + color: !walletViewModel.isEnabledSellAction
198 + ? Theme.of(context)
199 + .accentTextTheme
200 + .display2
201 + .backgroundColor
202 + : Theme.of(context).accentTextTheme.display3.backgroundColor),
203 + title: S.of(context).sell,
204 + onClick: () async => await _onClickSellButton(context),
205 + textColor: !walletViewModel.isEnabledSellAction
206 + ? Theme.of(context)
207 + .accentTextTheme
208 + .display2
209 + .backgroundColor
210 + : null),
211 + ],
212 + ),),
213 + ),),);
214 + }),
215
216 ],
217 ));
@@ -192,9 +222,6 @@ class DashboardPage extends BasePage {
222 return;
223 }
224
195 - pages.add(AddressPage(
196 - addressListViewModel: addressListViewModel,
197 - walletViewModel: walletViewModel));
225 pages.add(balancePage);
226 pages.add(TransactionsPage(dashboardViewModel: walletViewModel));
227 _isEffectsInstalled = true;
@@ -289,4 +316,24 @@ class DashboardPage extends BasePage {
316 });
317 }
318 }
292 -}
\ No newline at end of file
319 +
320 + Future<void> _onClickExchangeButton(BuildContext context) async {
321 + final walletType = walletViewModel.type;
322 +
323 + switch (walletType) {
324 + case WalletType.haven:
325 + await showPopUp<void>(
326 + context: context,
327 + builder: (BuildContext context) {
328 + return AlertWithOneAction(
329 + alertTitle: 'Exchange',
330 + alertContent: 'Exchange for this asset is not supported yet.',
331 + buttonText: S.of(context).ok,
332 + buttonAction: () => Navigator.of(context).pop());
333 + });
334 + break;
335 + default:
336 + await Navigator.of(context).pushNamed(Routes.exchange);
337 + }
338 + }
339 +}
lib/src/screens/dashboard/widgets/action_button.dart
+10 -3
@@ -6,17 +6,25 @@ class ActionButton extends StatelessWidget {
6 @required this.title,
7 this.route,
8 this.onClick,
9 - this.alignment = Alignment.center});
9 + this.alignment = Alignment.center,
10 + this.textColor});
11
12 final Image image;
13 final String title;
14 final String route;
15 final Alignment alignment;
16 final void Function() onClick;
17 + final Color textColor;
18
19 @override
20 Widget build(BuildContext context) {
21 + var _textColor = textColor ?? Theme.of(context)
22 + .accentTextTheme
23 + .display3
24 + .backgroundColor;
25 +
26 return Container(
27 + padding: EdgeInsets.only(top: 14, bottom: 16, left: 10, right: 10),
28 alignment: alignment,
29 child: Column(
30 mainAxisSize: MainAxisSize.max,
@@ -42,8 +50,7 @@ class ActionButton extends StatelessWidget {
50 title,
51 style: TextStyle(
52 fontSize: 10,
45 - color: Theme.of(context).accentTextTheme.display3
46 - .backgroundColor),
53 + color: _textColor),
54 )
55 ],
56 ),
lib/src/screens/dashboard/widgets/address_page.dart
+60 -3
@@ -1,3 +1,4 @@
1 +import 'package:cake_wallet/src/screens/base_page.dart';
2 import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
3 import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
4 import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
@@ -15,7 +16,7 @@ import 'package:flutter_mobx/flutter_mobx.dart';
16 import 'package:keyboard_actions/keyboard_actions.dart';
17 import 'package:mobx/mobx.dart';
18
18 -class AddressPage extends StatelessWidget {
19 +class AddressPage extends BasePage {
20 AddressPage({@required this.addressListViewModel,
21 this.walletViewModel})
22 : _cryptoAmountFocus = FocusNode();
@@ -26,7 +27,64 @@ class AddressPage extends StatelessWidget {
27 final FocusNode _cryptoAmountFocus;
28
29 @override
29 - Widget build(BuildContext context) {
30 + String get title => S.current.receive;
31 +
32 + @override
33 + Color get backgroundLightColor => currentTheme.type == ThemeType.bright
34 + ? Colors.transparent : Colors.white;
35 +
36 + @override
37 + Color get backgroundDarkColor => Colors.transparent;
38 +
39 + @override
40 + bool get resizeToAvoidBottomInset => false;
41 +
42 + @override
43 + Widget leading(BuildContext context) {
44 + final _backButton = Icon(Icons.arrow_back_ios,
45 + color: Theme.of(context).accentTextTheme.display3.backgroundColor,
46 + size: 16,);
47 +
48 + return SizedBox(
49 + height: 37,
50 + width: 37,
51 + child: ButtonTheme(
52 + minWidth: double.minPositive,
53 + child: FlatButton(
54 + highlightColor: Colors.transparent,
55 + splashColor: Colors.transparent,
56 + padding: EdgeInsets.all(0),
57 + onPressed: () => onClose(context),
58 + child: _backButton),
59 + ),
60 + );
61 + }
62 +
63 + @override
64 + Widget middle(BuildContext context) {
65 + return Text(
66 + title,
67 + style: TextStyle(
68 + fontSize: 18.0,
69 + fontWeight: FontWeight.bold,
70 + fontFamily: 'Lato',
71 + color: Theme.of(context).accentTextTheme.display3.backgroundColor),
72 + );
73 + }
74 +
75 + @override
76 + Widget Function(BuildContext, Widget) get rootWrapper =>
77 + (BuildContext context, Widget scaffold) => Container(
78 + decoration: BoxDecoration(
79 + gradient: LinearGradient(colors: [
80 + Theme.of(context).accentColor,
81 + Theme.of(context).scaffoldBackgroundColor,
82 + Theme.of(context).primaryColor,
83 + ], begin: Alignment.topRight, end: Alignment.bottomLeft)),
84 + child: scaffold);
85 +
86 + @override
87 + Widget body(BuildContext context) {
88 autorun((_) async {
89 if (!walletViewModel.isOutdatedElectrumWallet
90 || !walletViewModel.settingsStore.shouldShowReceiveWarning) {
@@ -66,7 +124,6 @@ class AddressPage extends StatelessWidget {
124 )
125 ]),
126 child: Container(
69 - height: 1,
127 padding: EdgeInsets.fromLTRB(24, 24, 24, 32),
128 child: Column(
129 children: <Widget>[
lib/src/screens/dashboard/widgets/balance_page.dart
+140 -163
@@ -1,4 +1,5 @@
1 import 'package:cake_wallet/di.dart';
2 +import 'package:cake_wallet/src/widgets/standard_list.dart';
3 import 'package:cake_wallet/store/settings_store.dart';
4 import 'package:cake_wallet/themes/theme_base.dart';
5 import 'package:flutter/material.dart';
@@ -15,23 +16,21 @@ class BalancePage extends StatelessWidget{
16
17 Color get backgroundLightColor =>
18 settingsStore.currentTheme.type == ThemeType.bright ? Colors.transparent : Colors.white;
19 +
20 @override
21 Widget build(BuildContext context) {
22 return GestureDetector(
21 - onLongPress: () =>
22 - dashboardViewModel.balanceViewModel.isReversing =
23 - !dashboardViewModel.balanceViewModel.isReversing,
24 - onLongPressUp: () =>
25 - dashboardViewModel.balanceViewModel.isReversing =
26 - !dashboardViewModel.balanceViewModel.isReversing,
23 + onLongPress: () => dashboardViewModel.balanceViewModel.isReversing = !dashboardViewModel.balanceViewModel.isReversing,
24 + onLongPressUp: () => dashboardViewModel.balanceViewModel.isReversing = !dashboardViewModel.balanceViewModel.isReversing,
25 + child: SingleChildScrollView(
26 child: Column(
27 + crossAxisAlignment: CrossAxisAlignment.start,
28 children: [
29 SizedBox(height: 56),
30 Container(
31 - alignment: Alignment.topLeft,
31 margin: const EdgeInsets.only(left: 24, bottom: 16),
32 child: Observer(builder: (_) {
34 - return AutoSizeText(
33 + return Text(
34 dashboardViewModel.balanceViewModel.asset,
35 style: TextStyle(
36 fontSize: 24,
@@ -44,162 +43,140 @@ class BalancePage extends StatelessWidget{
43 height: 1),
44 maxLines: 1,
45 textAlign: TextAlign.center);
47 - })),
48 -
49 - Container(
50 - margin: const EdgeInsets.only(left: 16, right: 16),
51 - decoration: BoxDecoration(
52 - borderRadius: BorderRadius.circular(30.0),
53 - border: Border.all(color: settingsStore.currentTheme.type == ThemeType.bright ? Color.fromRGBO(255, 255, 255, 0.2): Colors.transparent, width: 1, ),
54 - color:Theme.of(context).textTheme.title.backgroundColor
55 - ),
56 - child: Container(
57 - margin: const EdgeInsets.only(top: 24, left: 24, right: 24, bottom: 24),
58 - child: Row(
59 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
60 - crossAxisAlignment: CrossAxisAlignment.start,
61 - children: [
62 - Column(
63 - crossAxisAlignment: CrossAxisAlignment.start,
64 - children: [
65 - SizedBox(height: 8,),
66 - Observer(builder: (_) {
67 - return Column(
68 - children: [
69 - Text(
70 - '${dashboardViewModel.balanceViewModel.availableBalanceLabel}',
71 - textAlign: TextAlign.center,
72 - style: TextStyle(
73 - fontSize: 12,
74 - fontFamily: 'Lato',
75 - fontWeight: FontWeight.w500,
76 - color: Theme.of(context)
77 - .accentTextTheme
78 - .display2
79 - .backgroundColor,
80 - height: 1),
81 - )
82 - ],
83 - );
84 - }),
85 - SizedBox(height: 8,),
86 - Observer(builder: (_) {
87 - return AutoSizeText(
88 - dashboardViewModel.balanceViewModel.availableBalance,
89 - style: TextStyle(
90 - fontSize: 24,
91 - fontFamily: 'Lato',
92 -
93 - fontWeight: FontWeight.w900,
94 - color: Theme.of(context)
95 - .accentTextTheme
96 - .display3
97 - .backgroundColor,
98 - height: 1),
99 - maxLines: 1,
100 - textAlign: TextAlign.center);
101 - }),
102 - SizedBox(height: 4,),
103 - Observer(builder: (_) {
104 - return Column(
105 - children: [
106 - Text(
107 - '${dashboardViewModel.balanceViewModel.availableFiatBalance.toString()}',
108 - textAlign: TextAlign.center,
109 - style: TextStyle(
110 - fontSize: 16,
111 - fontFamily: 'Lato',
112 - fontWeight: FontWeight.w500,
113 - color: Theme.of(context)
114 - .accentTextTheme
115 - .display3
116 - .backgroundColor,
117 - height: 1),
118 - )
119 - ],
120 - );
121 - }),
122 - SizedBox(height: 26),
123 - Observer(builder: (_) {
124 - return Column(
125 - children: [
126 - Text(
127 - '${dashboardViewModel.balanceViewModel.additionalBalanceLabel}',
128 - textAlign: TextAlign.center,
129 - style: TextStyle(
130 - fontSize: 12,
131 - fontFamily: 'Lato',
132 - fontWeight: FontWeight.w500,
133 - color: Theme.of(context)
134 - .accentTextTheme
135 - .display2
136 - .backgroundColor,
137 - height: 1),
138 - )
139 - ],
140 - );
141 - }),
142 - SizedBox(height: 8),
143 - Observer(builder: (_) {
144 - return AutoSizeText(
145 - dashboardViewModel.balanceViewModel.additionalBalance
146 - .toString(),
147 - style: TextStyle(
148 - fontSize: 24,
149 - fontFamily: 'Lato',
150 - fontWeight: FontWeight.w900,
151 - color: Theme.of(context)
152 - .accentTextTheme
153 - .display3
154 - .backgroundColor,
155 - height: 1),
156 - maxLines: 1,
157 - textAlign: TextAlign.center);
158 - }),
159 - SizedBox(height: 4,),
160 - Observer(builder: (_) {
161 - return Column(
162 - children: [
163 - Text(
164 - '${dashboardViewModel.balanceViewModel.additionalFiatBalance.toString()}',
165 - textAlign: TextAlign.center,
166 - style: TextStyle(
167 - fontSize: 16,
168 - fontFamily: 'Lato',
169 - fontWeight: FontWeight.w500,
170 - color: Theme.of(context)
171 - .accentTextTheme
172 - .display3
173 - .backgroundColor,
174 - height: 1),
175 - )
176 - ],
177 - );
178 - }),
179 - ],
180 - ),
181 - Observer(builder: (_) {
182 - return Text(
183 - dashboardViewModel.balanceViewModel.currency.toString(),
184 - style: TextStyle(
185 - fontSize: 28,
186 - fontFamily: 'Lato',
187 - fontWeight: FontWeight.w800,
188 - color: Theme.of(context)
189 - .accentTextTheme
190 - .display3
191 - .backgroundColor,
192 - height: 1),
193 - );
194 - }),
195 - ],
196 - ),
197 - ),
198 - ),
199 -
200 - ],
46 + })),
47 + Observer(builder: (_) {
48 + return ListView.separated(
49 + physics: NeverScrollableScrollPhysics(),
50 + shrinkWrap: true,
51 + separatorBuilder: (_, __) => Container(padding: EdgeInsets.only(bottom: 8)),
52 + itemCount: dashboardViewModel.balanceViewModel.formattedBalances.length,
53 + itemBuilder: (__, index) {
54 + final balance = dashboardViewModel.balanceViewModel.formattedBalances.elementAt(index);
55 + return buildBalanceRow(context,
56 + availableBalanceLabel: '${dashboardViewModel.balanceViewModel.availableBalanceLabel}',
57 + availableBalance: balance.availableBalance,
58 + availableFiatBalance: balance.fiatAvailableBalance,
59 + additionalBalanceLabel: '${dashboardViewModel.balanceViewModel.additionalBalanceLabel}',
60 + additionalBalance: balance.additionalBalance,
61 + additionalFiatBalance: balance.fiatAdditionalBalance,
62 + currency: balance.formattedAssetTitle);
63 + });
64 + })
65 + ])));
66 + }
67 +
68 + Widget buildBalanceRow(BuildContext context,
69 + {String availableBalanceLabel,
70 + String availableBalance,
71 + String availableFiatBalance,
72 + String additionalBalanceLabel,
73 + String additionalBalance,
74 + String additionalFiatBalance,
75 + String currency}) {
76 + return Container(
77 + margin: const EdgeInsets.only(left: 16, right: 16),
78 + decoration: BoxDecoration(
79 + borderRadius: BorderRadius.circular(30.0),
80 + border: Border.all(color: settingsStore.currentTheme.type == ThemeType.bright ? Color.fromRGBO(255, 255, 255, 0.2): Colors.transparent, width: 1, ),
81 + color:Theme.of(context).textTheme.title.backgroundColor
82 ),
202 -
83 + child: Container(
84 + margin: const EdgeInsets.only(top: 16, left: 24, right: 24, bottom: 24),
85 + child: Column(
86 + crossAxisAlignment: CrossAxisAlignment.start,
87 + children: [
88 + SizedBox(height: 4,),
89 + Text('${availableBalanceLabel}',
90 + textAlign: TextAlign.center,
91 + style: TextStyle(
92 + fontSize: 12,
93 + fontFamily: 'Lato',
94 + fontWeight: FontWeight.w400,
95 + color: Theme.of(context)
96 + .accentTextTheme
97 + .display2
98 + .backgroundColor,
99 + height: 1)),
100 + SizedBox(height: 5),
101 + Row(
102 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
103 + children: [
104 + AutoSizeText(
105 + availableBalance,
106 + style: TextStyle(
107 + fontSize: 24,
108 + fontFamily: 'Lato',
109 + fontWeight: FontWeight.w900,
110 + color: Theme.of(context)
111 + .accentTextTheme
112 + .display3
113 + .backgroundColor,
114 + height: 1),
115 + maxLines: 1,
116 + textAlign: TextAlign.center),
117 + Text(currency,
118 + style: TextStyle(
119 + fontSize: 28,
120 + fontFamily: 'Lato',
121 + fontWeight: FontWeight.w800,
122 + color: Theme.of(context)
123 + .accentTextTheme
124 + .display3
125 + .backgroundColor,
126 + height: 1)),
127 + ]),
128 + SizedBox(height: 4,),
129 + Text('${availableFiatBalance}',
130 + textAlign: TextAlign.center,
131 + style: TextStyle(
132 + fontSize: 16,
133 + fontFamily: 'Lato',
134 + fontWeight: FontWeight.w500,
135 + color: Theme.of(context)
136 + .accentTextTheme
137 + .display3
138 + .backgroundColor,
139 + height: 1)),
140 + SizedBox(height: 26),
141 + Text('${additionalBalanceLabel}',
142 + textAlign: TextAlign.center,
143 + style: TextStyle(
144 + fontSize: 12,
145 + fontFamily: 'Lato',
146 + fontWeight: FontWeight.w400,
147 + color: Theme.of(context)
148 + .accentTextTheme
149 + .display2
150 + .backgroundColor,
151 + height: 1)),
152 + SizedBox(height: 8),
153 + AutoSizeText(
154 + additionalBalance,
155 + style: TextStyle(
156 + fontSize: 20,
157 + fontFamily: 'Lato',
158 + fontWeight: FontWeight.w400,
159 + color: Theme.of(context)
160 + .accentTextTheme
161 + .display3
162 + .backgroundColor,
163 + height: 1),
164 + maxLines: 1,
165 + textAlign: TextAlign.center),
166 + SizedBox(height: 4,),
167 + Text('${additionalFiatBalance}',
168 + textAlign: TextAlign.center,
169 + style: TextStyle(
170 + fontSize: 12,
171 + fontFamily: 'Lato',
172 + fontWeight: FontWeight.w400,
173 + color: Theme.of(context)
174 + .accentTextTheme
175 + .display3
176 + .backgroundColor,
177 + height: 1),
178 + )
179 + ])),
180 );
181 }
182 }
lib/src/screens/dashboard/widgets/menu_widget.dart
+4
@@ -22,6 +22,7 @@ class MenuWidgetState extends State<MenuWidget> {
22 Image moneroIcon;
23 Image bitcoinIcon;
24 Image litecoinIcon;
25 + Image havenIcon;
26 final largeScreen = 731;
27
28 double menuWidth;
@@ -78,6 +79,7 @@ class MenuWidgetState extends State<MenuWidget> {
79 bitcoinIcon = Image.asset('assets/images/bitcoin_menu.png',
80 color: Theme.of(context).accentTextTheme.overline.decorationColor);
81 litecoinIcon = Image.asset('assets/images/litecoin_menu.png');
82 + havenIcon = Image.asset('assets/images/haven_menu.png');
83
84 return Row(
85 mainAxisSize: MainAxisSize.max,
@@ -242,6 +244,8 @@ class MenuWidgetState extends State<MenuWidget> {
244 return bitcoinIcon;
245 case WalletType.litecoin:
246 return litecoinIcon;
247 + case WalletType.haven:
248 + return havenIcon;
249 default:
250 return null;
251 }
lib/src/screens/new_wallet/new_wallet_type_page.dart
+4
@@ -65,6 +65,8 @@ class WalletTypeFormState extends State<WalletTypeForm> {
65 final walletTypeImage = Image.asset('assets/images/wallet_type.png');
66 final walletTypeLightImage =
67 Image.asset('assets/images/wallet_type_light.png');
68 + final havenIcon =
69 + Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
70
71 WalletType selected;
72 List<WalletType> types;
@@ -129,6 +131,8 @@ class WalletTypeFormState extends State<WalletTypeForm> {
131 return bitcoinIcon;
132 case WalletType.litecoin:
133 return litecoinIcon;
134 + case WalletType.haven:
135 + return havenIcon;
136 default:
137 return null;
138 }
lib/src/screens/receive/receive_page.dart
+1 -1
@@ -109,7 +109,7 @@ class ReceivePage extends BasePage {
109
110 @override
111 Widget body(BuildContext context) {
112 - return addressListViewModel.type == WalletType.monero
112 + return (addressListViewModel.type == WalletType.monero || addressListViewModel.type == WalletType.haven)
113 ? KeyboardActions(
114 config: KeyboardActionsConfig(
115 keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
lib/src/screens/receive/widgets/qr_widget.dart
+1 -48
@@ -133,54 +133,7 @@ class QRWidget extends StatelessWidget {
133 ],
134 ),
135 ))),
136 - ),
137 - Observer(builder: (_) {
138 - return addressListViewModel.emoji.isNotEmpty
139 - ? Padding(
140 - padding: EdgeInsets.only(bottom: 10),
141 - child: Builder(
142 - builder: (context) => GestureDetector(
143 - onTap: () {
144 - Clipboard.setData(ClipboardData(
145 - text: addressListViewModel.emoji));
146 - showBar<void>(
147 - context, S.of(context).copied_to_clipboard);
148 - },
149 - child: Column(
150 - crossAxisAlignment: CrossAxisAlignment.center,
151 - children: [
152 - Text(
153 - S.of(context).yat,
154 - textAlign: TextAlign.center,
155 - style: TextStyle(
156 - fontSize: 13,
157 - fontWeight: FontWeight.normal,
158 - color: Theme.of(context).accentTextTheme.
159 - display3.backgroundColor),
160 - ),
161 - Padding(
162 - padding: EdgeInsets.only(top: 5),
163 - child: Row(
164 - mainAxisSize: MainAxisSize.max,
165 - crossAxisAlignment: CrossAxisAlignment.start,
166 - children: <Widget>[
167 - Expanded(child:Text(
168 - addressListViewModel.emoji,
169 - textAlign: TextAlign.center,
170 - style: TextStyle(
171 - fontSize: 26))),
172 - Padding(
173 - padding: EdgeInsets.only(left: 12),
174 - child: copyImage,
175 - )]
176 - ),
177 - )
178 - ]
179 - )
180 - )),
181 - )
182 - : Container();
183 - })
136 + )
137 ],
138 );
139 }
lib/src/screens/restore/wallet_restore_from_seed_form.dart
+2 -1
@@ -130,7 +130,8 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
130 BlockchainHeightWidget(
131 focusNode: widget.blockHeightFocusNode,
132 key: blockchainHeightKey,
133 - onHeightOrDateEntered: widget.onHeightOrDateEntered)
133 + onHeightOrDateEntered: widget.onHeightOrDateEntered,
134 + hasDatePicker: widget.type == WalletType.monero)
135 ]));
136 }
137
lib/src/screens/restore/wallet_restore_page.dart
+1 -1
@@ -215,7 +215,7 @@ class WalletRestorePage extends BasePage {
215 .text
216 .split(' ');
217
218 - if (walletRestoreViewModel.type == WalletType.monero &&
218 + if ((walletRestoreViewModel.type == WalletType.monero || walletRestoreViewModel.type == WalletType.haven) &&
219 seedWords.length != WalletRestoreViewModelBase.moneroSeedMnemonicLength) {
220 return false;
221 }
lib/src/screens/send/send_page.dart
+55 -23
@@ -2,6 +2,7 @@ import 'dart:ui';
2 import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator_icon.dart';
3 import 'package:cake_wallet/src/screens/send/widgets/send_card.dart';
4 import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
5 +import 'package:cake_wallet/src/widgets/picker.dart';
6 import 'package:cake_wallet/src/widgets/template_tile.dart';
7 import 'package:cake_wallet/view_model/send/output.dart';
8 import 'package:flutter/cupertino.dart';
@@ -22,6 +23,7 @@ import 'package:dotted_border/dotted_border.dart';
23 import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
24 import 'package:cake_wallet/src/screens/send/widgets/confirm_sending_alert.dart';
25 import 'package:smooth_page_indicator/smooth_page_indicator.dart';
26 +import 'package:cw_core/crypto_currency.dart';
27
28 class SendPage extends BasePage {
29 SendPage({@required this.sendViewModel}) : _formKey = GlobalKey<FormState>();
@@ -140,6 +142,7 @@ class SendPage extends BasePage {
142 ),
143 ),
144 ),
145 + if (sendViewModel.hasMultiRecipient)
146 Container(
147 height: 40,
148 width: double.infinity,
@@ -256,27 +259,43 @@ class SendPage extends BasePage {
259 EdgeInsets.only(left: 24, right: 24, bottom: 24),
260 bottomSection: Column(
261 children: [
259 - Padding(
260 - padding: EdgeInsets.only(bottom: 12),
261 - child: PrimaryButton(
262 - onPressed: () {
263 - sendViewModel.addOutput();
264 - Future.delayed(const Duration(milliseconds: 250), () {
265 - controller.jumpToPage(sendViewModel.outputs.length - 1);
266 - });
267 - },
268 - text: S.of(context).add_receiver,
269 - color: Colors.transparent,
270 - textColor: Theme.of(context)
271 - .accentTextTheme
272 - .display2
273 - .decorationColor,
274 - isDottedBorder: true,
275 - borderColor: Theme.of(context)
276 - .primaryTextTheme
277 - .display2
278 - .decorationColor,
279 - )),
262 + if (sendViewModel.hasCurrecyChanger)
263 + Observer(builder: (_) =>
264 + Padding(
265 + padding: EdgeInsets.only(bottom: 12),
266 + child: PrimaryButton(
267 + onPressed: () => presentCurrencyPicker(context),
268 + text: 'Change your asset (${sendViewModel.selectedCryptoCurrency})',
269 + color: Colors.transparent,
270 + textColor: Theme.of(context)
271 + .accentTextTheme
272 + .display2
273 + .decorationColor,
274 + )
275 + )
276 + ),
277 + if (sendViewModel.hasMultiRecipient)
278 + Padding(
279 + padding: EdgeInsets.only(bottom: 12),
280 + child: PrimaryButton(
281 + onPressed: () {
282 + sendViewModel.addOutput();
283 + Future.delayed(const Duration(milliseconds: 250), () {
284 + controller.jumpToPage(sendViewModel.outputs.length - 1);
285 + });
286 + },
287 + text: S.of(context).add_receiver,
288 + color: Colors.transparent,
289 + textColor: Theme.of(context)
290 + .accentTextTheme
291 + .display2
292 + .decorationColor,
293 + isDottedBorder: true,
294 + borderColor: Theme.of(context)
295 + .primaryTextTheme
296 + .display2
297 + .decorationColor,
298 + )),
299 Observer(
300 builder: (_) {
301 return LoadingPrimaryButton(
@@ -298,7 +317,7 @@ class SendPage extends BasePage {
317 showErrorValidationAlert(context);
318 return;
319 }
301 -
320 +
321 await sendViewModel.createTransaction();
322
323 },
@@ -377,7 +396,7 @@ class SendPage extends BasePage {
396 return AlertWithOneAction(
397 alertTitle: '',
398 alertContent: S.of(context).send_success(
380 - sendViewModel.currency.toString()),
399 + sendViewModel.selectedCryptoCurrency.toString()),
400 buttonText: S.of(context).ok,
401 buttonAction: () =>
402 Navigator.of(context).pop());
@@ -418,4 +437,17 @@ class SendPage extends BasePage {
437 buttonAction: () => Navigator.of(context).pop());
438 });
439 }
440 +
441 + void presentCurrencyPicker(BuildContext context) async {
442 + await showPopUp<CryptoCurrency>(
443 + builder: (_) => Picker(
444 + items: sendViewModel.currencies,
445 + displayItem: (Object item) => item.toString(),
446 + selectedAtIndex: sendViewModel.currencies.indexOf(sendViewModel.selectedCryptoCurrency),
447 + title: S.of(context).please_select,
448 + mainAxisAlignment: MainAxisAlignment.center,
449 + onItemSelected: (CryptoCurrency cur) => sendViewModel.selectedCryptoCurrency = cur,
450 + ),
451 + context: context);
452 + }
453 }
lib/src/screens/send/widgets/send_card.dart
+2 -2
@@ -196,7 +196,7 @@ class SendCardState extends State<SendCard>
196 prefixIcon: Padding(
197 padding: EdgeInsets.only(top: 9),
198 child: Text(
199 - sendViewModel.currency.title +
199 + sendViewModel.selectedCryptoCurrency.title +
200 ':',
201 style: TextStyle(
202 fontSize: 16,
@@ -391,7 +391,7 @@ class SendCardState extends State<SendCard>
391 .toString() +
392 ' ' +
393 sendViewModel
394 - .currency.title,
394 + .selectedCryptoCurrency.toString(),
395 style: TextStyle(
396 fontSize: 12,
397 fontWeight:
lib/src/screens/wallet_list/wallet_list_page.dart
+11 -19
@@ -45,6 +45,8 @@ class WalletListBodyState extends State<WalletListBody> {
45 Image.asset('assets/images/litecoin_icon.png', height: 24, width: 24);
46 final nonWalletTypeIcon =
47 Image.asset('assets/images/close.png', height: 24, width: 24);
48 + final havenIcon =
49 + Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
50 final scrollController = ScrollController();
51 final double tileHeight = 60;
52 Flushbar<void> _progressBar;
@@ -176,12 +178,12 @@ class WalletListBodyState extends State<WalletListBody> {
178 bottomSection: Column(children: <Widget>[
179 PrimaryImageButton(
180 onPressed: () {
179 - if (isMoneroOnly) {
180 - Navigator.of(context).pushNamed(Routes.newWallet, arguments: WalletType.monero);
181 - } else {
182 - Navigator.of(context).pushNamed(Routes.newWalletType);
183 - }
184 - },
181 + if (isSingleCoin) {
182 + Navigator.of(context).pushNamed(Routes.newWallet, arguments: widget.walletListViewModel.currentWalletType);
183 + } else {
184 + Navigator.of(context).pushNamed(Routes.newWalletType);
185 + }
186 + },
187 image: newWalletImage,
188 text: S.of(context).wallet_list_create_new_wallet,
189 color: Theme.of(context).accentTextTheme.body2.color,
@@ -190,7 +192,7 @@ class WalletListBodyState extends State<WalletListBody> {
192 SizedBox(height: 10.0),
193 PrimaryImageButton(
194 onPressed: () {
193 - if (isMoneroOnly) {
195 + if (isSingleCoin) {
196 Navigator
197 .of(context)
198 .pushNamed(
@@ -216,6 +218,8 @@ class WalletListBodyState extends State<WalletListBody> {
218 return moneroIcon;
219 case WalletType.litecoin:
220 return litecoinIcon;
221 + case WalletType.haven:
222 + return havenIcon;
223 default:
224 return nonWalletTypeIcon;
225 }
@@ -264,18 +268,6 @@ class WalletListBodyState extends State<WalletListBody> {
268 });
269 }
270
267 - Future<void> _generateNewWallet() async {
268 - try {
269 - changeProcessText(S.of(context).creating_new_wallet);
270 - await widget.walletListViewModel.walletNewVM
271 - .create(options: 'English'); // FIXME: Unnamed constant
272 - hideProgressText();
273 - await Navigator.of(context).pushNamed(Routes.preSeed);
274 - } catch (e) {
275 - changeProcessText(S.of(context).creating_new_wallet_error(e.toString()));
276 - }
277 - }
278 -
271 void changeProcessText(String text) {
272 _progressBar = createBar<void>(text, duration: null)..show(context);
273 }
lib/src/screens/welcome/welcome_page.dart
+26 -6
@@ -11,6 +11,30 @@ class WelcomePage extends BasePage {
11 final welcomeImageLight = Image.asset('assets/images/welcome_light.png');
12 final welcomeImageDark = Image.asset('assets/images/welcome.png');
13
14 + String appTitle(BuildContext context) {
15 + if (isMoneroOnly) {
16 + return S.of(context).monero_com;
17 + }
18 +
19 + if (isHaven) {
20 + return S.of(context).haven_app;
21 + }
22 +
23 + return S.of(context).cake_wallet;
24 + }
25 +
26 + String appDescription(BuildContext context) {
27 + if (isMoneroOnly) {
28 + return S.of(context).monero_com_wallet_text;
29 + }
30 +
31 + if (isHaven) {
32 + return S.of(context).haven_app_wallet_text;
33 + }
34 +
35 + return S.of(context).first_wallet_text;
36 + }
37 +
38 @override
39 Widget build(BuildContext context) {
40 return Scaffold(
@@ -83,9 +107,7 @@ class WelcomePage extends BasePage {
107 Padding(
108 padding: EdgeInsets.only(top: 5),
109 child: Text(
86 - isMoneroOnly
87 - ? S.of(context).monero_com
88 - : S.of(context).cake_wallet,
110 + appTitle(context),
111 style: TextStyle(
112 fontSize: 36,
113 fontWeight: FontWeight.bold,
@@ -101,9 +123,7 @@ class WelcomePage extends BasePage {
123 Padding(
124 padding: EdgeInsets.only(top: 5),
125 child: Text(
104 - isMoneroOnly
105 - ? S.of(context).monero_com_wallet_text
106 - : S.of(context).first_wallet_text,
126 + appDescription(context),
127 style: TextStyle(
128 fontSize: 16,
129 fontWeight: FontWeight.w500,
lib/src/widgets/blockchain_height_widget.dart
+38 -35
@@ -7,12 +7,13 @@ import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
7
8 class BlockchainHeightWidget extends StatefulWidget {
9 BlockchainHeightWidget({GlobalKey key, this.onHeightChange, this.focusNode,
10 - this.onHeightOrDateEntered})
10 + this.onHeightOrDateEntered, this.hasDatePicker})
11 : super(key: key);
12
13 final Function(int) onHeightChange;
14 final Function(bool) onHeightOrDateEntered;
15 final FocusNode focusNode;
16 + final bool hasDatePicker;
17
18 @override
19 State<StatefulWidget> createState() => BlockchainHeightState();
@@ -67,43 +68,45 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
68 )))
69 ],
70 ),
70 - Padding(
71 - padding: EdgeInsets.only(top: 15, bottom: 15),
72 - child: Text(
73 - S.of(context).widgets_or,
74 - style: TextStyle(
75 - fontSize: 16.0,
76 - fontWeight: FontWeight.w500,
77 - color: Theme.of(context).primaryTextTheme.title.color),
71 + if (widget.hasDatePicker) ...[
72 + Padding(
73 + padding: EdgeInsets.only(top: 15, bottom: 15),
74 + child: Text(
75 + S.of(context).widgets_or,
76 + style: TextStyle(
77 + fontSize: 16.0,
78 + fontWeight: FontWeight.w500,
79 + color: Theme.of(context).primaryTextTheme.title.color),
80 + ),
81 ),
79 - ),
80 - Row(
81 - children: <Widget>[
82 - Flexible(
83 - child: Container(
84 - child: InkWell(
85 - onTap: () => _selectDate(context),
86 - child: IgnorePointer(
87 - child: BaseTextFormField(
88 - controller: dateController,
89 - hintText: S.of(context).widgets_restore_from_date,
90 - )),
82 + Row(
83 + children: <Widget>[
84 + Flexible(
85 + child: Container(
86 + child: InkWell(
87 + onTap: () => _selectDate(context),
88 + child: IgnorePointer(
89 + child: BaseTextFormField(
90 + controller: dateController,
91 + hintText: S.of(context).widgets_restore_from_date,
92 + )),
93 + ),
94 + ))
95 + ],
96 + ),
97 + Padding(
98 + padding: EdgeInsets.only(left: 40, right: 40, top: 24),
99 + child: Text(
100 + S.of(context).restore_from_date_or_blockheight,
101 + textAlign: TextAlign.center,
102 + style: TextStyle(
103 + fontSize: 12,
104 + fontWeight: FontWeight.normal,
105 + color: Theme.of(context).hintColor
106 ),
92 - ))
93 - ],
94 - ),
95 - Padding(
96 - padding: EdgeInsets.only(left: 40, right: 40, top: 24),
97 - child: Text(
98 - S.of(context).restore_from_date_or_blockheight,
99 - textAlign: TextAlign.center,
100 - style: TextStyle(
101 - fontSize: 12,
102 - fontWeight: FontWeight.normal,
103 - color: Theme.of(context).hintColor
107 ),
105 - ),
106 - )
108 + )
109 + ]
110 ],
111 );
112 }
lib/store/settings_store.dart
+5 -1
@@ -227,9 +227,12 @@ abstract class SettingsStoreBase with Store {
227 .getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);
228 final litecoinElectrumServerId = sharedPreferences
229 .getInt(PreferencesKey.currentLitecoinElectrumSererIdKey);
230 + final havenNodeId = sharedPreferences
231 + .getInt(PreferencesKey.currentHavenNodeIdKey);
232 final moneroNode = nodeSource.get(nodeId);
233 final bitcoinElectrumServer = nodeSource.get(bitcoinElectrumServerId);
234 final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId);
235 + final havenNode = nodeSource.get(havenNodeId);
236 final packageInfo = await PackageInfo.fromPlatform();
237 final shouldShowYatPopup =
238 sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? true;
@@ -239,7 +242,8 @@ abstract class SettingsStoreBase with Store {
242 nodes: {
243 WalletType.monero: moneroNode,
244 WalletType.bitcoin: bitcoinElectrumServer,
242 - WalletType.litecoin: litecoinElectrumServer
245 + WalletType.litecoin: litecoinElectrumServer,
246 + WalletType.haven: havenNode
247 },
248 appVersion: packageInfo.version,
249 isBitcoinBuyEnabled: isBitcoinBuyEnabled,
lib/view_model/dashboard/balance_view_model.dart
+131 -41
@@ -15,6 +15,21 @@ import 'package:mobx/mobx.dart';
15
16 part 'balance_view_model.g.dart';
17
18 +class BalanceRecord {
19 + const BalanceRecord({this.availableBalance,
20 + this.additionalBalance,
21 + this.fiatAvailableBalance,
22 + this.fiatAdditionalBalance,
23 + this.asset,
24 + this.formattedAssetTitle});
25 + final String fiatAdditionalBalance;
26 + final String fiatAvailableBalance;
27 + final String additionalBalance;
28 + final String availableBalance;
29 + final CryptoCurrency asset;
30 + final String formattedAssetTitle;
31 +}
32 +
33 class BalanceViewModel = BalanceViewModelBase with _$BalanceViewModel;
34
35 abstract class BalanceViewModelBase with Store {
@@ -24,16 +39,7 @@ abstract class BalanceViewModelBase with Store {
39 @required this.fiatConvertationStore}) {
40 isReversing = false;
41 wallet ??= appStore.wallet;
27 - balance = wallet.balance;
28 -
42 reaction((_) => appStore.wallet, _onWalletChange);
30 -
31 - _onCurrentWalletChangeReaction =
32 - reaction<void>((_) => wallet.balance, (dynamic balance) {
33 - if (balance is Balance) {
34 - this.balance = balance;
35 - }
36 - });
43 }
44
45 final AppStore appStore;
@@ -45,9 +51,6 @@ abstract class BalanceViewModelBase with Store {
51 @observable
52 bool isReversing;
53
48 - @observable
49 - Balance balance;
50 -
54 @observable
55 WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>
56 wallet;
@@ -58,47 +61,56 @@ abstract class BalanceViewModelBase with Store {
61 @computed
62 BalanceDisplayMode get savedDisplayMode => settingsStore.balanceDisplayMode;
63
61 - @computed
64 + @computed
65 String get asset {
63 -
64 - switch(appStore.wallet.currency){
65 - case CryptoCurrency.btc:
66 - return 'Bitcoin Assets';
67 - case CryptoCurrency.xmr:
68 - return 'Monero Assets';
69 - case CryptoCurrency.ltc:
70 - return 'Litecoin Assets';
66 + final typeFormatted = walletTypeToString(appStore.wallet.type);
67 +
68 + switch(wallet.type) {
69 + case WalletType.haven:
70 + return '$typeFormatted Assets';
71 default:
72 - return '';
72 + return typeFormatted;
73 }
74 -
74 }
75
76 @computed
78 - BalanceDisplayMode get displayMode => isReversing
79 - ? savedDisplayMode == BalanceDisplayMode.hiddenBalance
80 - ? BalanceDisplayMode.displayableBalance
81 - : savedDisplayMode
82 - : savedDisplayMode;
77 + BalanceDisplayMode get displayMode {
78 + if (isReversing) {
79 + if (savedDisplayMode == BalanceDisplayMode.hiddenBalance) {
80 + return BalanceDisplayMode.displayableBalance;
81 + } else {
82 + return BalanceDisplayMode.hiddenBalance;
83 + }
84 + }
85 +
86 + return savedDisplayMode;
87 + }
88
89 @computed
90 String get availableBalanceLabel {
86 - if (wallet.type == WalletType.monero) {
87 - return S.current.xmr_available_balance;
91 + switch(wallet.type) {
92 + case WalletType.monero:
93 + case WalletType.haven:
94 + return S.current.xmr_available_balance;
95 + default:
96 + return S.current.confirmed;
97 }
89 -
90 - return S.current.confirmed;
98 }
99
100 @computed
101 String get additionalBalanceLabel {
95 - if (wallet.type == WalletType.monero) {
96 - return S.current.xmr_full_balance;
102 + switch(wallet.type) {
103 + case WalletType.monero:
104 + case WalletType.haven:
105 + return S.current.xmr_full_balance;
106 + default:
107 + return S.current.unconfirmed;
108 }
98 -
99 - return S.current.unconfirmed;
109 }
110
111 + @computed
112 + bool get hasMultiBalance => appStore.wallet.type == WalletType.haven;
113 +
114 @computed
115 String get availableBalance {
116 final walletBalance = _walletBalance;
@@ -152,7 +164,73 @@ abstract class BalanceViewModelBase with Store {
164 }
165
166 @computed
155 - Balance get _walletBalance => wallet.balance;
167 + Map<CryptoCurrency, BalanceRecord> get balances {
168 + return wallet.balance.map((key, value) {
169 + if (displayMode == BalanceDisplayMode.hiddenBalance) {
170 + return MapEntry(key, BalanceRecord(
171 + availableBalance: '---',
172 + additionalBalance: '---',
173 + fiatAdditionalBalance: '---',
174 + fiatAvailableBalance: '---',
175 + asset: key,
176 + formattedAssetTitle: _formatterAsset(key)));
177 + }
178 + final fiatCurrency = settingsStore.fiatCurrency;
179 + final additionalFiatBalance = fiatCurrency.toString()
180 + + ' '
181 + + _getFiatBalance(
182 + price: fiatConvertationStore.prices[key],
183 + cryptoAmount: value.formattedAdditionalBalance);
184 +
185 + final availableFiatBalance = fiatCurrency.toString()
186 + + ' '
187 + + _getFiatBalance(
188 + price: fiatConvertationStore.prices[key],
189 + cryptoAmount: value.formattedAvailableBalance);
190 +
191 + return MapEntry(key, BalanceRecord(
192 + availableBalance: value.formattedAvailableBalance,
193 + additionalBalance: value.formattedAdditionalBalance,
194 + fiatAdditionalBalance: additionalFiatBalance,
195 + fiatAvailableBalance: availableFiatBalance,
196 + asset: key,
197 + formattedAssetTitle: _formatterAsset(key)));
198 + });
199 + }
200 +
201 + @computed
202 + List<BalanceRecord> get formattedBalances {
203 + final balance = balances.values.toList();
204 +
205 + balance.sort((BalanceRecord a, BalanceRecord b) {
206 + if (b.asset == CryptoCurrency.xhv) {
207 + return 1;
208 + }
209 +
210 + if (b.asset == CryptoCurrency.xusd) {
211 + if (a.asset == CryptoCurrency.xhv) {
212 + return -1;
213 + }
214 +
215 + return 1;
216 + }
217 +
218 + if (b.asset == CryptoCurrency.xbtc) {
219 + return 1;
220 + }
221 +
222 + if (b.asset == CryptoCurrency.xeur) {
223 + return 1;
224 + }
225 +
226 + return 0;
227 + });
228 +
229 + return balance;
230 + }
231 +
232 + @computed
233 + Balance get _walletBalance => wallet.balance[wallet.currency];
234
235 @computed
236 CryptoCurrency get currency => appStore.wallet.currency;
@@ -164,11 +242,8 @@ abstract class BalanceViewModelBase with Store {
242 WalletBase<Balance, TransactionHistoryBase<TransactionInfo>,
243 TransactionInfo>
244 wallet) {
167 - this.wallet = wallet;
168 - balance = wallet.balance;
245 + this.wallet = wallet;
246 _onCurrentWalletChangeReaction?.reaction?.dispose();
170 - _onCurrentWalletChangeReaction = reaction<Balance>(
171 - (_) => wallet.balance, (Balance balance) => this.balance = balance);
247 }
248
249 String _getFiatBalance({double price, String cryptoAmount}) {
@@ -178,5 +253,20 @@ abstract class BalanceViewModelBase with Store {
253
254 return calculateFiatAmount(price: price, cryptoAmount: cryptoAmount);
255 }
256 +
257 + String _formatterAsset(CryptoCurrency asset) {
258 + switch (wallet.type) {
259 + case WalletType.haven:
260 + final assetStringified = asset.toString();
261 +
262 + if (asset != CryptoCurrency.xhv && assetStringified[0].toUpperCase() == 'X') {
263 + return assetStringified.replaceFirst('X', 'x');
264 + }
265 +
266 + return asset.toString();
267 + default:
268 + return asset.toString();
269 + }
270 + }
271 }
272
lib/view_model/dashboard/dashboard_view_model.dart
+34
@@ -1,3 +1,4 @@
1 +import 'package:cake_wallet/wallet_type_utils.dart';
2 import 'package:cw_core/transaction_history.dart';
3 import 'package:cw_core/balance.dart';
4 import 'package:cake_wallet/buy/order.dart';
@@ -78,6 +79,8 @@ abstract class DashboardViewModelBase with Store {
79 isShowFirstYatIntroduction = false;
80 isShowSecondYatIntroduction = false;
81 isShowThirdYatIntroduction = false;
82 + updateActions();
83 +
84 final _wallet = wallet;
85
86 if (_wallet.type == WalletType.monero) {
@@ -229,6 +232,24 @@ abstract class DashboardViewModelBase with Store {
232 void furtherShowYatPopup(bool shouldShow) =>
233 settingsStore.shouldShowYatPopup = shouldShow;
234
235 + @observable
236 + bool isEnabledExchangeAction;
237 +
238 + @observable
239 + bool hasExchangeAction;
240 +
241 + @observable
242 + bool isEnabledBuyAction;
243 +
244 + @observable
245 + bool hasBuyAction;
246 +
247 + @observable
248 + bool isEnabledSellAction;
249 +
250 + @observable
251 + bool hasSellAction;
252 +
253 ReactionDisposer _onMoneroAccountChangeReaction;
254
255 ReactionDisposer _onMoneroBalanceChangeReaction;
@@ -251,6 +272,7 @@ abstract class DashboardViewModelBase with Store {
272 name = wallet.name;
273 isOutdatedElectrumWallet =
274 wallet.type == WalletType.bitcoin && wallet.seed.split(' ').length < 24;
275 + updateActions();
276
277 if (wallet.type == WalletType.monero) {
278 subname = monero.getCurrentAccount(wallet)?.label;
@@ -313,4 +335,16 @@ abstract class DashboardViewModelBase with Store {
335 balanceViewModel: balanceViewModel,
336 settingsStore: appStore.settingsStore)));
337 }
338 +
339 + void updateActions() {
340 + isEnabledExchangeAction = wallet.type != WalletType.haven;
341 + hasExchangeAction = !isHaven;
342 + isEnabledBuyAction = wallet.type != WalletType.haven
343 + && wallet.type != WalletType.monero;
344 + hasBuyAction = !isMoneroOnly && !isHaven;
345 + isEnabledSellAction = wallet.type != WalletType.haven
346 + && wallet.type != WalletType.monero
347 + && wallet.type != WalletType.litecoin;
348 + hasSellAction = !isMoneroOnly && !isHaven;
349 + }
350 }
lib/view_model/dashboard/transaction_list_item.dart
+24 -9
@@ -1,15 +1,18 @@
1 import 'package:cake_wallet/entities/balance_display_mode.dart';
2 import 'package:cake_wallet/entities/fiat_currency.dart';
3 +import 'package:cw_core/crypto_currency.dart';
4 import 'package:cw_core/transaction_info.dart';
5 import 'package:cake_wallet/store/settings_store.dart';
6 import 'package:cake_wallet/utils/mobx.dart';
7 import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
8 import 'package:cake_wallet/monero/monero.dart';
9 +import 'package:cake_wallet/haven/haven.dart';
10 import 'package:cake_wallet/bitcoin/bitcoin.dart';
11 import 'package:cake_wallet/entities/calculate_fiat_amount_raw.dart';
12 import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
13 import 'package:cw_core/keyable.dart';
14 import 'package:cw_core/wallet_type.dart';
15 +import 'package:cw_haven/haven_transaction_info.dart';
16
17 class TransactionListItem extends ActionListItem with Keyable {
18 TransactionListItem(
@@ -35,21 +38,33 @@ class TransactionListItem extends ActionListItem with Keyable {
38 }
39
40 String get formattedFiatAmount {
38 - if (balanceViewModel.wallet.type == WalletType.monero) {
39 - final amount = calculateFiatAmountRaw(
41 + var amount = '';
42 +
43 + switch(balanceViewModel.wallet.type) {
44 + case WalletType.monero:
45 + amount = calculateFiatAmountRaw(
46 cryptoAmount: monero.formatterMoneroAmountToDouble(amount: transaction.amount),
47 price: price);
42 - transaction.changeFiatAmount(amount);
43 - }
44 -
45 - if (balanceViewModel.wallet.type == WalletType.bitcoin
46 - || balanceViewModel.wallet.type == WalletType.litecoin) {
47 - final amount = calculateFiatAmountRaw(
48 + break;
49 + case WalletType.bitcoin:
50 + case WalletType.litecoin:
51 + amount = calculateFiatAmountRaw(
52 cryptoAmount: bitcoin.formatterBitcoinAmountToDouble(amount: transaction.amount),
53 price: price);
50 - transaction.changeFiatAmount(amount);
54 + break;
55 + case WalletType.haven:
56 + final tx = transaction as HavenTransactionInfo;
57 + final asset = CryptoCurrency.fromString(tx.assetType);
58 + final price = balanceViewModel.fiatConvertationStore.prices[asset];
59 + amount = calculateFiatAmountRaw(
60 + cryptoAmount: haven.formatterMoneroAmountToDouble(amount: transaction.amount),
61 + price: price);
62 + break;
63 + default:
64 + break;
65 }
66
67 + transaction.changeFiatAmount(amount);
68 return displayMode == BalanceDisplayMode.hiddenBalance
69 ? '---'
70 : fiatCurrency.title + ' ' + transaction.fiatAmount();
lib/view_model/exchange/exchange_view_model.dart
+1 -1
@@ -338,7 +338,7 @@ abstract class ExchangeViewModelBase with Store {
338 @action
339 void calculateDepositAllAmount() {
340 if (wallet.type == WalletType.bitcoin) {
341 - final availableBalance = wallet.balance.available;
341 + final availableBalance = wallet.balance[wallet.currency].available;
342 final priority = _settingsStore.priority[wallet.type];
343 final fee = wallet.calculateEstimatedFee(priority, null);
344
lib/view_model/monero_account_list/monero_account_edit_or_create_view_model.dart
+40 -1
@@ -1,8 +1,10 @@
1 import 'package:cw_core/wallet_base.dart';
2 +import 'package:cw_core/wallet_type.dart';
3 import 'package:flutter/foundation.dart';
4 import 'package:mobx/mobx.dart';
5 import 'package:cake_wallet/core/execution_state.dart';
6 import 'package:cake_wallet/monero/monero.dart';
7 +import 'package:cake_wallet/haven/haven.dart';
8 import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
9
10 part 'monero_account_edit_or_create_view_model.g.dart';
@@ -11,7 +13,7 @@ class MoneroAccountEditOrCreateViewModel = MoneroAccountEditOrCreateViewModelBas
13 with _$MoneroAccountEditOrCreateViewModel;
14
15 abstract class MoneroAccountEditOrCreateViewModelBase with Store {
14 - MoneroAccountEditOrCreateViewModelBase(this._moneroAccountList,
16 + MoneroAccountEditOrCreateViewModelBase(this._moneroAccountList, this._havenAccountList,
17 {@required WalletBase wallet, AccountListItem accountListItem})
18 : state = InitialExecutionState(),
19 isEdit = accountListItem != null,
@@ -28,10 +30,21 @@ abstract class MoneroAccountEditOrCreateViewModelBase with Store {
30 String label;
31
32 final MoneroAccountList _moneroAccountList;
33 + final HavenAccountList _havenAccountList;
34 final AccountListItem _accountListItem;
35 final WalletBase _wallet;
36
37 Future<void> save() async {
38 + if (_wallet.type == WalletType.monero) {
39 + await saveMonero();
40 + }
41 +
42 + if (_wallet.type == WalletType.haven) {
43 + await saveHaven();
44 + }
45 + }
46 +
47 + Future<void> saveMonero() async {
48 try {
49 state = IsExecutingState();
50
@@ -52,4 +65,30 @@ abstract class MoneroAccountEditOrCreateViewModelBase with Store {
65 state = FailureState(e.toString());
66 }
67 }
68 +
69 + Future<void> saveHaven() async {
70 + if (!(_wallet.type == WalletType.haven)) {
71 + return;
72 + }
73 +
74 + try {
75 + state = IsExecutingState();
76 +
77 + if (_accountListItem != null) {
78 + await _havenAccountList.setLabelAccount(
79 + _wallet,
80 + accountIndex: _accountListItem.id,
81 + label: label);
82 + } else {
83 + await _havenAccountList.addAccount(
84 + _wallet,
85 + label: label);
86 + }
87 +
88 + await _wallet.save();
89 + state = ExecutedSuccessfullyState();
90 + } catch (e) {
91 + state = FailureState(e.toString());
92 + }
93 + }
94 }
lib/view_model/monero_account_list/monero_account_list_view_model.dart
+36 -11
@@ -1,7 +1,9 @@
1 +import 'package:cw_core/wallet_type.dart';
2 import 'package:mobx/mobx.dart';
3 import 'package:cw_core/wallet_base.dart';
4 import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
5 import 'package:cake_wallet/monero/monero.dart';
6 +import 'package:cake_wallet/haven/haven.dart';
7
8 part 'monero_account_list_view_model.g.dart';
9
@@ -20,20 +22,43 @@ abstract class MoneroAccountListViewModelBase with Store {
22 }
23
24 @computed
23 - List<AccountListItem> get accounts => monero
24 - .getAccountList(_wallet)
25 - .accounts.map((acc) => AccountListItem(
26 - label: acc.label,
27 - id: acc.id,
28 - isSelected: acc.id == monero.getCurrentAccount(_wallet).id))
29 - .toList();
25 + List<AccountListItem> get accounts {
26 + if (_wallet.type == WalletType.haven) {
27 + return haven
28 + .getAccountList(_wallet)
29 + .accounts.map((acc) => AccountListItem(
30 + label: acc.label,
31 + id: acc.id,
32 + isSelected: acc.id == haven.getCurrentAccount(_wallet).id))
33 + .toList();
34 + }
35 +
36 + if (_wallet.type == WalletType.monero) {
37 + return monero
38 + .getAccountList(_wallet)
39 + .accounts.map((acc) => AccountListItem(
40 + label: acc.label,
41 + id: acc.id,
42 + isSelected: acc.id == monero.getCurrentAccount(_wallet).id))
43 + .toList();
44 + }
45 + }
46
47 final WalletBase _wallet;
48
33 - void select(AccountListItem item) =>
49 + void select(AccountListItem item) {
50 + if (_wallet.type == WalletType.monero) {
51 monero.setCurrentAccount(
52 _wallet,
36 - Account(
37 - id: item.id,
38 - label: item.label));
53 + item.id,
54 + item.label);
55 + }
56 +
57 + if (_wallet.type == WalletType.haven) {
58 + haven.setCurrentAccount(
59 + _wallet,
60 + item.id,
61 + item.label);
62 + }
63 + }
64 }
lib/view_model/node_list/node_create_or_edit_view_model.dart
+2 -1
@@ -41,7 +41,8 @@ abstract class NodeCreateOrEditViewModelBase with Store {
41 bool get isReady =>
42 (address?.isNotEmpty ?? false) && (port?.isNotEmpty ?? false);
43
44 - bool get hasAuthCredentials => _wallet.type == WalletType.monero;
44 + bool get hasAuthCredentials => _wallet.type == WalletType.monero ||
45 + _wallet.type == WalletType.haven;
46
47 String get uri {
48 var uri = address;
lib/view_model/send/output.dart
+18 -5
@@ -2,7 +2,9 @@ import 'package:cake_wallet/di.dart';
2 import 'package:cake_wallet/entities/calculate_fiat_amount_raw.dart';
3 import 'package:cake_wallet/entities/parse_address_from_domain.dart';
4 import 'package:cake_wallet/entities/parsed_address.dart';
5 +import 'package:cake_wallet/haven/haven.dart';
6 import 'package:cake_wallet/src/screens/send/widgets/extract_address_from_parsed.dart';
7 +import 'package:cw_core/crypto_currency.dart';
8 import 'package:flutter/material.dart';
9 import 'package:intl/intl.dart';
10 import 'package:mobx/mobx.dart';
@@ -22,7 +24,7 @@ const String cryptoNumberPattern = '0.0';
24 class Output = OutputBase with _$Output;
25
26 abstract class OutputBase with Store {
25 - OutputBase(this._wallet, this._settingsStore, this._fiatConversationStore)
27 + OutputBase(this._wallet, this._settingsStore, this._fiatConversationStore, this.cryptoCurrencyHandler)
28 : _cryptoNumberFormat = NumberFormat(cryptoNumberPattern) {
29 reset();
30 _setCryptoNumMaximumFractionDigits();
@@ -77,6 +79,9 @@ abstract class OutputBase with Store {
79 _amount =
80 bitcoin.formatterStringDoubleToBitcoinAmount(_cryptoAmount);
81 break;
82 + case WalletType.haven:
83 + _amount = haven.formatterMoneroParseAmount(amount: _cryptoAmount);
84 + break;
85 default:
86 break;
87 }
@@ -106,6 +111,10 @@ abstract class OutputBase with Store {
111 if (_wallet.type == WalletType.monero) {
112 return monero.formatterMoneroAmountToDouble(amount: fee);
113 }
114 +
115 + if (_wallet.type == WalletType.haven) {
116 + return haven.formatterMoneroAmountToDouble(amount: fee);
117 + }
118 } catch (e) {
119 print(e.toString());
120 }
@@ -117,7 +126,7 @@ abstract class OutputBase with Store {
126 String get estimatedFeeFiatAmount {
127 try {
128 final fiat = calculateFiatAmountRaw(
120 - price: _fiatConversationStore.prices[_wallet.currency],
129 + price: _fiatConversationStore.prices[cryptoCurrencyHandler()],
130 cryptoAmount: estimatedFee);
131 return fiat;
132 } catch (_) {
@@ -126,6 +135,7 @@ abstract class OutputBase with Store {
135 }
136
137 WalletType get walletType => _wallet.type;
138 + final CryptoCurrency Function() cryptoCurrencyHandler;
139 final WalletBase _wallet;
140 final SettingsStore _settingsStore;
141 final FiatConversionStore _fiatConversationStore;
@@ -169,7 +179,7 @@ abstract class OutputBase with Store {
179 void _updateFiatAmount() {
180 try {
181 final fiat = calculateFiatAmount(
172 - price: _fiatConversationStore.prices[_wallet.currency],
182 + price: _fiatConversationStore.prices[cryptoCurrencyHandler()],
183 cryptoAmount: cryptoAmount.replaceAll(',', '.'));
184 if (fiatAmount != fiat) {
185 fiatAmount = fiat;
@@ -183,7 +193,7 @@ abstract class OutputBase with Store {
193 void _updateCryptoAmount() {
194 try {
195 final crypto = double.parse(fiatAmount.replaceAll(',', '.')) /
186 - _fiatConversationStore.prices[_wallet.currency];
196 + _fiatConversationStore.prices[cryptoCurrencyHandler()];
197 final cryptoAmountTmp = _cryptoNumberFormat.format(crypto);
198
199 if (cryptoAmount != cryptoAmountTmp) {
@@ -207,6 +217,9 @@ abstract class OutputBase with Store {
217 case WalletType.litecoin:
218 maximumFractionDigits = 8;
219 break;
220 + case WalletType.haven:
221 + maximumFractionDigits = 12;
222 + break;
223 default:
224 break;
225 }
@@ -216,7 +229,7 @@ abstract class OutputBase with Store {
229
230 Future<void> fetchParsedAddress(BuildContext context) async {
231 final domain = address;
219 - final ticker = _wallet.currency.title.toLowerCase();
232 + final ticker = cryptoCurrencyHandler().title.toLowerCase();
233 parsedAddress = await getIt.get<AddressResolver>().resolve(domain, ticker);
234 extractedAddress = await extractAddressFromParsed(context, parsedAddress);
235 note = parsedAddress.description;
lib/view_model/send/send_template_view_model.dart
+1 -1
@@ -21,7 +21,7 @@ abstract class SendTemplateViewModelBase with Store {
21 SendTemplateViewModelBase(this._wallet, this._settingsStore,
22 this._sendTemplateStore, this._fiatConversationStore) {
23
24 - output = Output(_wallet, _settingsStore, _fiatConversationStore);
24 + output = Output(_wallet, _settingsStore, _fiatConversationStore, () => currency);
25 }
26
27 Output output;
lib/view_model/send/send_view_model.dart
+24 -11
@@ -24,6 +24,7 @@ import 'package:cake_wallet/store/settings_store.dart';
24 import 'package:cake_wallet/view_model/send/send_view_model_state.dart';
25 import 'package:cake_wallet/entities/parsed_address.dart';
26 import 'package:cake_wallet/bitcoin/bitcoin.dart';
27 +import 'package:cake_wallet/haven/haven.dart';
28
29 part 'send_view_model.g.dart';
30
@@ -39,13 +40,15 @@ abstract class SendViewModelBase with Store {
40 : state = InitialExecutionState() {
41 final priority = _settingsStore.priority[_wallet.type];
42 final priorities = priorityForWalletType(_wallet.type);
43 + selectedCryptoCurrency = _wallet.currency;
44 + currencies = _wallet.balance.keys.toList();
45
46 if (!priorityForWalletType(_wallet.type).contains(priority)) {
47 _settingsStore.priority[_wallet.type] = priorities.first;
48 }
49
50 outputs = ObservableList<Output>()
48 - ..add(Output(_wallet, _settingsStore, _fiatConversationStore));
51 + ..add(Output(_wallet, _settingsStore, _fiatConversationStore, () => selectedCryptoCurrency));
52 }
53
54 @observable
@@ -55,7 +58,7 @@ abstract class SendViewModelBase with Store {
58
59 @action
60 void addOutput() {
58 - outputs.add(Output(_wallet, _settingsStore, _fiatConversationStore));
61 + outputs.add(Output(_wallet, _settingsStore, _fiatConversationStore, () => selectedCryptoCurrency));
62 }
63
64 @action
@@ -79,7 +82,7 @@ abstract class SendViewModelBase with Store {
82 try {
83 if (pendingTransaction != null) {
84 final fiat = calculateFiatAmount(
82 - price: _fiatConversationStore.prices[_wallet.currency],
85 + price: _fiatConversationStore.prices[selectedCryptoCurrency],
86 cryptoAmount: pendingTransaction.amountFormatted);
87 return fiat;
88 } else {
@@ -95,7 +98,7 @@ abstract class SendViewModelBase with Store {
98 try {
99 if (pendingTransaction != null) {
100 final fiat = calculateFiatAmount(
98 - price: _fiatConversationStore.prices[_wallet.currency],
101 + price: _fiatConversationStore.prices[selectedCryptoCurrency],
102 cryptoAmount: pendingTransaction.feeFormatted);
103 return fiat;
104 } else {
@@ -117,7 +120,7 @@ abstract class SendViewModelBase with Store {
120
121 Validator get allAmountValidator => AllAmountValidator();
122
120 - Validator get addressValidator => AddressValidator(type: _wallet.currency);
123 + Validator get addressValidator => AddressValidator(type: selectedCryptoCurrency);
124
125 Validator get textValidator => TextValidator();
126
@@ -125,12 +128,7 @@ abstract class SendViewModelBase with Store {
128 PendingTransaction pendingTransaction;
129
130 @computed
128 - String get balance {
129 - if(_settingsStore.balanceDisplayMode == BalanceDisplayMode.hiddenBalance){
130 - return '---';
131 - }
132 - return _wallet.balance.formattedAvailableBalance ?? '0.0' ;
133 - }
131 + String get balance => _wallet.balance[selectedCryptoCurrency].formattedAvailableBalance ?? '0.0';
132
133 @computed
134 bool get isReadyForSend => _wallet.syncStatus is SyncedSyncStatus;
@@ -144,11 +142,21 @@ abstract class SendViewModelBase with Store {
142 bool get isElectrumWallet =>
143 _wallet.type == WalletType.bitcoin || _wallet.type == WalletType.litecoin;
144
145 + @observable
146 + CryptoCurrency selectedCryptoCurrency;
147 +
148 + List<CryptoCurrency> currencies;
149 +
150 + bool get hasMultiRecipient => _wallet.type != WalletType.haven;
151 +
152 bool get hasYat => outputs.any((out) =>
153 out.isParsedAddress &&
154 out.parsedAddress.parseFrom == ParseFrom.yatRecord);
155
156 WalletType get walletType => _wallet.type;
157 +
158 + bool get hasCurrecyChanger => walletType == WalletType.haven;
159 +
160 final WalletBase _wallet;
161 final SettingsStore _settingsStore;
162 final SendTemplateViewModel sendTemplateViewModel;
@@ -221,6 +229,11 @@ abstract class SendViewModelBase with Store {
229
230 return monero.createMoneroTransactionCreationCredentials(
231 outputs: outputs, priority: priority);
232 + case WalletType.haven:
233 + final priority = _settingsStore.priority[_wallet.type];
234 +
235 + return haven.createHavenTransactionCreationCredentials(
236 + outputs: outputs, priority: priority, assetType: selectedCryptoCurrency.title);
237 default:
238 return null;
239 }
lib/view_model/settings/settings_view_model.dart
+11 -6
@@ -14,6 +14,7 @@ import 'package:cake_wallet/entities/balance_display_mode.dart';
14 import 'package:cake_wallet/entities/fiat_currency.dart';
15 import 'package:cw_core/node.dart';
16 import 'package:cake_wallet/monero/monero.dart';
17 +import 'package:cake_wallet/haven/haven.dart';
18 import 'package:cake_wallet/entities/action_list_display_mode.dart';
19 import 'package:cake_wallet/view_model/settings/version_list_item.dart';
20 import 'package:cake_wallet/view_model/settings/picker_list_item.dart';
@@ -29,6 +30,7 @@ import 'package:cw_core/transaction_priority.dart';
30 import 'package:cake_wallet/themes/theme_base.dart';
31 import 'package:cake_wallet/themes/theme_list.dart';
32 import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
33 +import 'package:cake_wallet/wallet_type_utils.dart';
34
35 part 'settings_view_model.g.dart';
36
@@ -42,6 +44,8 @@ List<TransactionPriority> priorityForWalletType(WalletType type) {
44 return bitcoin.getTransactionPriorities();
45 case WalletType.litecoin:
46 return bitcoin.getLitecoinTransactionPriorities();
47 + case WalletType.haven:
48 + return haven.getTransactionPriorities();
49 default:
50 return [];
51 }
@@ -101,12 +105,13 @@ abstract class SettingsViewModelBase with Store {
105 selectedItem: () => balanceDisplayMode,
106 onItemSelected: (BalanceDisplayMode mode) =>
107 _settingsStore.balanceDisplayMode = mode),
104 - PickerListItem(
105 - title: S.current.settings_currency,
106 - items: FiatCurrency.all,
107 - selectedItem: () => fiatCurrency,
108 - onItemSelected: (FiatCurrency currency) =>
109 - setFiatCurrency(currency)),
108 + if (!isHaven)
109 + PickerListItem(
110 + title: S.current.settings_currency,
111 + items: FiatCurrency.all,
112 + selectedItem: () => fiatCurrency,
113 + onItemSelected: (FiatCurrency currency) =>
114 + setFiatCurrency(currency)),
115 PickerListItem(
116 title: S.current.settings_fee_priority,
117 items: priorityForWalletType(wallet.type),
lib/view_model/transaction_details_view_model.dart
+22
@@ -14,6 +14,7 @@ import 'package:cake_wallet/store/settings_store.dart';
14 import 'package:cake_wallet/generated/i18n.dart';
15 import 'package:url_launcher/url_launcher.dart';
16 import 'package:cake_wallet/monero/monero.dart';
17 +import 'package:cake_wallet/haven/haven.dart';
18
19 part 'transaction_details_view_model.g.dart';
20
@@ -100,6 +101,23 @@ abstract class TransactionDetailsViewModelBase with Store {
101 items.addAll(_items);
102 }
103
104 + if (wallet.type == WalletType.haven) {
105 + items.addAll([
106 + StandartListItem(
107 + title: S.current.transaction_details_transaction_id, value: tx.id),
108 + StandartListItem(
109 + title: S.current.transaction_details_date,
110 + value: dateFormat.format(tx.date)),
111 + StandartListItem(
112 + title: S.current.transaction_details_height, value: '${tx.height}'),
113 + StandartListItem(
114 + title: S.current.transaction_details_amount,
115 + value: tx.amountFormatted()),
116 + StandartListItem(
117 + title: S.current.transaction_details_fee, value: tx.feeFormatted()),
118 + ]);
119 + }
120 +
121 if (showRecipientAddress && !isRecipientAddressShown) {
122 final recipientAddress = transactionDescriptionBox.values
123 .firstWhere((val) => val.id == transactionInfo.id, orElse: () => null)
@@ -154,6 +172,8 @@ abstract class TransactionDetailsViewModelBase with Store {
172 return 'https://www.blockchain.com/btc/tx/${txId}';
173 case WalletType.litecoin:
174 return 'https://blockchair.com/litecoin/transaction/${txId}';
175 + case WalletType.haven:
176 + return 'https://explorer.havenprotocol.org/search?value=${txId}';
177 default:
178 return '';
179 }
@@ -167,6 +187,8 @@ abstract class TransactionDetailsViewModelBase with Store {
187 return 'View Transaction on Blockchain.com';
188 case WalletType.litecoin:
189 return 'View Transaction on Blockchair.com';
190 + case WalletType.haven:
191 + return 'View Transaction on explorer.havenprotocol.org';
192 default:
193 return '';
194 }
lib/view_model/wallet_address_list/wallet_address_edit_or_create_view_model.dart
+22
@@ -3,6 +3,7 @@ import 'package:flutter/foundation.dart';
3 import 'package:cw_core/wallet_base.dart';
4 import 'package:cake_wallet/bitcoin/bitcoin.dart';
5 import 'package:cake_wallet/monero/monero.dart';
6 +import 'package:cake_wallet/haven/haven.dart';
7 import 'package:cw_core/wallet_type.dart';
8
9 part 'wallet_address_edit_or_create_view_model.g.dart';
@@ -78,6 +79,16 @@ abstract class WalletAddressEditOrCreateViewModelBase with Store {
79 label: label);
80 await wallet.save();
81 }
82 +
83 + if (wallet.type == WalletType.haven) {
84 + await haven
85 + .getSubaddressList(wallet)
86 + .addSubaddress(
87 + wallet,
88 + accountIndex: haven.getCurrentAccount(wallet).id,
89 + label: label);
90 + await wallet.save();
91 + }
92 }
93
94 Future<void> _update() async {
@@ -98,5 +109,16 @@ abstract class WalletAddressEditOrCreateViewModelBase with Store {
109 label: label);
110 await wallet.save();
111 }
112 +
113 + if (wallet.type == WalletType.haven) {
114 + await haven
115 + .getSubaddressList(wallet)
116 + .setLabelSubaddress(
117 + wallet,
118 + accountIndex: haven.getCurrentAccount(wallet).id,
119 + addressIndex: _item.id as int,
120 + label: label);
121 + await wallet.save();
122 + }
123 }
124 }
lib/view_model/wallet_address_list/wallet_address_list_view_model.dart
+45 -32
@@ -15,6 +15,7 @@ import 'package:cw_core/wallet_type.dart';
15 import 'package:cake_wallet/store/app_store.dart';
16 import 'dart:async';
17 import 'package:cake_wallet/monero/monero.dart';
18 +import 'package:cake_wallet/haven/haven.dart';
19
20 part 'wallet_address_list_view_model.g.dart';
21
@@ -44,6 +45,22 @@ class MoneroURI extends PaymentURI {
45 }
46 }
47
48 +class HavenURI extends PaymentURI {
49 + HavenURI({String amount, String address})
50 + : super(amount: amount, address: address);
51 +
52 + @override
53 + String toString() {
54 + var base = 'haven:' + address;
55 +
56 + if (amount?.isNotEmpty ?? false) {
57 + base += '?tx_amount=${amount.replaceAll(',', '.')}';
58 + }
59 +
60 + return base;
61 + }
62 +}
63 +
64 class BitcoinURI extends PaymentURI {
65 BitcoinURI({String amount, String address})
66 : super(amount: amount, address: address);
@@ -83,30 +100,7 @@ abstract class WalletAddressListViewModelBase with Store {
100 }) {
101 _appStore = appStore;
102 _wallet = _appStore.wallet;
86 - emoji = '';
87 - hasAccounts = _wallet?.type == WalletType.monero;
88 - reaction((_) => _wallet.walletAddresses.address, (String address) {
89 - if (address == _wallet.walletInfo.yatLastUsedAddress) {
90 - emoji = yatStore.emoji;
91 - } else {
92 - emoji = '';
93 - }
94 - });
95 -
96 - //reaction((_) => yatStore.emoji, (String emojiId) => this.emoji = emojiId);
97 -
98 - //_onLastUsedYatAddressSubscription =
99 - // _wallet.walletInfo.yatLastUsedAddressStream.listen((String yatAddress) {
100 - // if (yatAddress == _wallet.walletAddresses.address) {
101 - // emoji = yatStore.emoji;
102 - // } else {
103 - // emoji = '';
104 - // }
105 - //});
106 -
107 - if (_wallet.walletAddresses.address == _wallet.walletInfo.yatLastUsedAddress) {
108 - emoji = yatStore.emoji;
109 - }
103 + hasAccounts = _wallet?.type == WalletType.monero || _wallet?.type == WalletType.haven;
104
105 _onWalletChangeReaction = reaction((_) => _appStore.wallet, (WalletBase<
106 Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>
@@ -133,6 +127,10 @@ abstract class WalletAddressListViewModelBase with Store {
127 return MoneroURI(amount: amount, address: address.address);
128 }
129
130 + if (_wallet.type == WalletType.haven) {
131 + return HavenURI(amount: amount, address: address.address);
132 + }
133 +
134 if (_wallet.type == WalletType.bitcoin) {
135 return BitcoinURI(amount: amount, address: address.address);
136 }
@@ -170,6 +168,23 @@ abstract class WalletAddressListViewModelBase with Store {
168 addressList.addAll(addressItems);
169 }
170
171 + if (wallet.type == WalletType.haven) {
172 + final primaryAddress = haven.getSubaddressList(wallet).subaddresses.first;
173 + final addressItems = haven
174 + .getSubaddressList(wallet)
175 + .subaddresses
176 + .map((subaddress) {
177 + final isPrimary = subaddress == primaryAddress;
178 +
179 + return WalletAddressListItem(
180 + id: subaddress.id,
181 + isPrimary: isPrimary,
182 + name: subaddress.label,
183 + address: subaddress.address);
184 + });
185 + addressList.addAll(addressItems);
186 + }
187 +
188 if (wallet.type == WalletType.bitcoin) {
189 final primaryAddress = bitcoin.getAddress(wallet);
190 final bitcoinAddresses = bitcoin.getAddresses(wallet).map((addr) {
@@ -195,14 +210,15 @@ abstract class WalletAddressListViewModelBase with Store {
210 return monero.getCurrentAccount(wallet).label;
211 }
212
213 + if (wallet.type == WalletType.haven) {
214 + return haven.getCurrentAccount(wallet).label;
215 + }
216 +
217 return null;
218 }
219
220 @computed
202 - bool get hasAddressList => _wallet.type == WalletType.monero;
203 -
204 - @observable
205 - String emoji;
221 + bool get hasAddressList => _wallet.type == WalletType.monero || _wallet.type == WalletType.haven;
222
223 @observable
224 WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>
@@ -216,9 +232,6 @@ abstract class WalletAddressListViewModelBase with Store {
232
233 ReactionDisposer _onWalletChangeReaction;
234
219 - StreamSubscription<String> _onLastUsedYatAddressSubscription;
220 - StreamSubscription<String> _onEmojiIdChangeSubscription;
221 -
235 @action
236 void setAddress(WalletAddressListItem address) =>
237 _wallet.walletAddresses.address = address.address;
@@ -226,7 +239,7 @@ abstract class WalletAddressListViewModelBase with Store {
239 void _init() {
240 _baseItems = [];
241
229 - if (_wallet.type == WalletType.monero) {
242 + if (_wallet.type == WalletType.monero || _wallet.type == WalletType.haven) {
243 _baseItems.add(WalletAccountListHeader());
244 }
245
lib/view_model/wallet_keys_view_model.dart
+17
@@ -5,6 +5,7 @@ import 'package:cw_core/wallet_base.dart';
5 import 'package:cake_wallet/bitcoin/bitcoin.dart';
6 import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
7 import 'package:cake_wallet/monero/monero.dart';
8 +import 'package:cake_wallet/haven/haven.dart';
9
10 part 'wallet_keys_view_model.g.dart';
11
@@ -29,6 +30,22 @@ abstract class WalletKeysViewModelBase with Store {
30 ]);
31 }
32
33 + if (wallet.type == WalletType.haven) {
34 + final keys = haven.getKeys(wallet);
35 +
36 + items.addAll([
37 + StandartListItem(
38 + title: S.current.spend_key_public, value: keys['publicSpendKey']),
39 + StandartListItem(
40 + title: S.current.spend_key_private, value: keys['privateSpendKey']),
41 + StandartListItem(
42 + title: S.current.view_key_public, value: keys['publicViewKey']),
43 + StandartListItem(
44 + title: S.current.view_key_private, value: keys['privateViewKey']),
45 + StandartListItem(title: S.current.wallet_seed, value: wallet.seed),
46 + ]);
47 + }
48 +
49 if (wallet.type == WalletType.bitcoin || wallet.type == WalletType.litecoin) {
50 final keys = bitcoin.getWalletKeys(wallet);
51
lib/view_model/wallet_list/wallet_list_view_model.dart
+1 -2
@@ -16,7 +16,7 @@ class WalletListViewModel = WalletListViewModelBase with _$WalletListViewModel;
16
17 abstract class WalletListViewModelBase with Store {
18 WalletListViewModelBase(this._walletInfoSource, this._appStore,
19 - this._keyService, this.walletNewVM) {
19 + this._keyService) {
20 wallets = ObservableList<WalletListItem>();
21 _updateList();
22 }
@@ -27,7 +27,6 @@ abstract class WalletListViewModelBase with Store {
27 final AppStore _appStore;
28 final Box<WalletInfo> _walletInfoSource;
29 final KeyService _keyService;
30 - final WalletNewVM walletNewVM;
30
31 WalletType get currentWalletType => _appStore.wallet.type;
32
lib/view_model/wallet_new_vm.dart
+5 -1
@@ -10,6 +10,7 @@ import 'package:cw_core/wallet_info.dart';
10 import 'package:cw_core/wallet_type.dart';
11 import 'package:cake_wallet/view_model/wallet_creation_vm.dart';
12 import 'package:cake_wallet/bitcoin/bitcoin.dart';
13 +import 'package:cake_wallet/haven/haven.dart';
14
15 part 'wallet_new_vm.g.dart';
16
@@ -25,7 +26,7 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store {
26 @observable
27 String selectedMnemonicLanguage;
28
28 - bool get hasLanguageSelector => type == WalletType.monero;
29 + bool get hasLanguageSelector => type == WalletType.monero || type == WalletType.haven;
30
31 final WalletCreationService _walletCreationService;
32
@@ -39,6 +40,9 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store {
40 return bitcoin.createBitcoinNewWalletCredentials(name: name);
41 case WalletType.litecoin:
42 return bitcoin.createBitcoinNewWalletCredentials(name: name);
43 + case WalletType.haven:
44 + return haven.createHavenNewWalletCredentials(
45 + name: name, language: options as String);
46 default:
47 return null;
48 }
lib/view_model/wallet_restore_view_model.dart
+32 -12
@@ -12,6 +12,7 @@ import 'package:cw_core/wallet_type.dart';
12 import 'package:cw_core/wallet_info.dart';
13 import 'package:cake_wallet/view_model/wallet_creation_vm.dart';
14 import 'package:cake_wallet/monero/monero.dart';
15 +import 'package:cake_wallet/haven/haven.dart';
16
17 part 'wallet_restore_view_model.g.dart';
18
@@ -24,11 +25,11 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
25 WalletRestoreViewModelBase(AppStore appStore, this._walletCreationService,
26 Box<WalletInfo> walletInfoSource,
27 {@required WalletType type})
27 - : availableModes = type == WalletType.monero
28 + : availableModes = (type == WalletType.monero || type == WalletType.haven)
29 ? WalletRestoreMode.values
30 : [WalletRestoreMode.seed],
30 - hasSeedLanguageSelector = type == WalletType.monero,
31 - hasBlockchainHeightLanguageSelector = type == WalletType.monero,
31 + hasSeedLanguageSelector = type == WalletType.monero || type == WalletType.haven,
32 + hasBlockchainHeightLanguageSelector = type == WalletType.monero || type == WalletType.haven,
33 super(appStore, walletInfoSource, type: type, isRecovery: true) {
34 isButtonEnabled =
35 !hasSeedLanguageSelector && !hasBlockchainHeightLanguageSelector;
@@ -64,7 +65,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
65 case WalletType.monero:
66 return monero.createMoneroRestoreWalletFromSeedCredentials(
67 name: name,
67 - height: height,
68 + height: height ?? 0,
69 mnemonic: seed,
70 password: password);
71 case WalletType.bitcoin:
@@ -77,6 +78,12 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
78 name: name,
79 mnemonic: seed,
80 password: password);
81 + case WalletType.haven:
82 + return haven.createHavenRestoreWalletFromSeedCredentials(
83 + name: name,
84 + height: height ?? 0,
85 + mnemonic: seed,
86 + password: password);
87 default:
88 break;
89 }
@@ -87,14 +94,27 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
94 final spendKey = options['spendKey'] as String;
95 final address = options['address'] as String;
96
90 - return monero.createMoneroRestoreWalletFromKeysCredentials(
91 - name: name,
92 - height: height,
93 - spendKey: spendKey,
94 - viewKey: viewKey,
95 - address: address,
96 - password: password,
97 - language: 'English');
97 + if (type == WalletType.monero) {
98 + return monero.createMoneroRestoreWalletFromKeysCredentials(
99 + name: name,
100 + height: height,
101 + spendKey: spendKey,
102 + viewKey: viewKey,
103 + address: address,
104 + password: password,
105 + language: 'English');
106 + }
107 +
108 + if (type == WalletType.haven) {
109 + return haven.createHavenRestoreWalletFromKeysCredentials(
110 + name: name,
111 + height: height,
112 + spendKey: spendKey,
113 + viewKey: viewKey,
114 + address: address,
115 + password: password,
116 + language: 'English');
117 + }
118 }
119
120 return null;
lib/wallet_type_utils.dart
+21 -5
@@ -2,12 +2,28 @@ import 'package:cw_core/wallet_type.dart';
2 import 'package:cake_wallet/wallet_types.g.dart';
3
4 bool get isMoneroOnly {
5 - return availableWalletTypes.length == 1
6 - && availableWalletTypes.first == WalletType.monero;
5 + return availableWalletTypes.length == 1
6 + && availableWalletTypes.first == WalletType.monero;
7 +}
8 +
9 +bool get isHaven {
10 + return availableWalletTypes.length == 1
11 + && availableWalletTypes.first == WalletType.haven;
12 +}
13 +
14 +
15 +bool get isSingleCoin {
16 + return availableWalletTypes.length == 1;
17 }
18
19 String get approximatedAppName {
10 - return isMoneroOnly
11 - ? 'Monero.com'
12 - : 'Cake Wallet';
20 + if (isMoneroOnly) {
21 + return 'Monero.com';
22 + }
23 +
24 + if (isHaven) {
25 + return 'Haven';
26 + }
27 +
28 + return 'Cake Wallet';
29 }
\ No newline at end of file
pubspec_base.yaml
+1
@@ -76,6 +76,7 @@ flutter:
76 assets:
77 - assets/images/
78 - assets/node_list.yml
79 + - assets/haven_node_list.yml
80 - assets/bitcoin_electrum_server_list.yml
81 - assets/litecoin_electrum_server_list.yml
82 - assets/text/
res/values/strings_de.arb
+3
@@ -8,6 +8,9 @@
8
9 "monero_com": "Monero.com by Cake Wallet",
10 "monero_com_wallet_text": "Awesome wallet for Monero",
11 +
12 + "haven_app": "Haven by Cake Wallet",
13 + "haven_app_wallet_text": "Awesome wallet for Haven",
14
15 "accounts" : "Konten",
16 "edit" : "Bearbeiten",
res/values/strings_en.arb
+2
@@ -9,6 +9,8 @@
9 "monero_com": "Monero.com by Cake Wallet",
10 "monero_com_wallet_text": "Awesome wallet for Monero",
11
12 + "haven_app": "Haven by Cake Wallet",
13 + "haven_app_wallet_text": "Awesome wallet for Haven",
14
15 "accounts" : "Accounts",
16 "edit" : "Edit",
res/values/strings_es.arb
+3
@@ -9,6 +9,9 @@
9 "monero_com": "Monero.com by Cake Wallet",
10 "monero_com_wallet_text": "Awesome wallet for Monero",
11
12 + "haven_app": "Haven by Cake Wallet",
13 + "haven_app_wallet_text": "Awesome wallet for Haven",
14 +
15 "accounts" : "Cuentas",
16 "edit" : "Editar",
17 "account" : "Cuenta",
res/values/strings_hi.arb
+3
@@ -8,6 +8,9 @@
8
9 "monero_com": "Monero.com by Cake Wallet",
10 "monero_com_wallet_text": "Awesome wallet for Monero",
11 +
12 + "haven_app": "Haven by Cake Wallet",
13 + "haven_app_wallet_text": "Awesome wallet for Haven",
14
15 "accounts" : "हिसाब किताब",
16 "edit" : "संपादित करें",
res/values/strings_hr.arb
+3
@@ -8,6 +8,9 @@
8
9 "monero_com": "Monero.com by Cake Wallet",
10 "monero_com_wallet_text": "Awesome wallet for Monero",
11 +
12 + "haven_app": "Haven by Cake Wallet",
13 + "haven_app_wallet_text": "Awesome wallet for Haven",
14
15 "accounts" : "Računi",
16 "edit" : "Uredi",
res/values/strings_it.arb
+3
@@ -8,6 +8,9 @@
8
9 "monero_com": "Monero.com by Cake Wallet",
10 "monero_com_wallet_text": "Awesome wallet for Monero",
11 +
12 + "haven_app": "Haven by Cake Wallet",
13 + "haven_app_wallet_text": "Awesome wallet for Haven",
14
15 "accounts" : "Accounts",
16 "edit" : "Modifica",
res/values/strings_ja.arb
+3
@@ -8,6 +8,9 @@
8
9 "monero_com": "Monero.com by Cake Wallet",
10 "monero_com_wallet_text": "Awesome wallet for Monero",
11 +
12 + "haven_app": "Haven by Cake Wallet",
13 + "haven_app_wallet_text": "Awesome wallet for Haven",
14
15 "accounts" : "アカウント",
16 "edit" : "編集",
res/values/strings_ko.arb
+3
@@ -8,6 +8,9 @@
8
9 "monero_com": "Monero.com by Cake Wallet",
10 "monero_com_wallet_text": "Awesome wallet for Monero",
11 +
12 + "haven_app": "Haven by Cake Wallet",
13 + "haven_app_wallet_text": "Awesome wallet for Haven",
14
15 "accounts" : "계정",
16 "edit" : "편집하다",
res/values/strings_nl.arb
+3
@@ -8,6 +8,9 @@
8
9 "monero_com": "Monero.com by Cake Wallet",
10 "monero_com_wallet_text": "Awesome wallet for Monero",
11 +
12 + "haven_app": "Haven by Cake Wallet",
13 + "haven_app_wallet_text": "Awesome wallet for Haven",
14
15 "accounts" : "Accounts",
16 "edit" : "Bewerk",
res/values/strings_pl.arb
+6
@@ -8,6 +8,12 @@
8
9 "monero_com": "Monero.com by Cake Wallet",
10 "monero_com_wallet_text": "Awesome wallet for Monero",
11 +
12 + "haven_app": "Haven by Cake Wallet",
13 + "haven_app_wallet_text": "Awesome wallet for Haven",
14 +
15 + "haven_app": "Haven by Cake Wallet",
16 + "haven_app_wallet_text": "Awesome wallet for Haven",
17
18 "accounts" : "Konta",
19 "edit" : "Edytować",
res/values/strings_pt.arb
+3
@@ -8,6 +8,9 @@
8
9 "monero_com": "Monero.com by Cake Wallet",
10 "monero_com_wallet_text": "Awesome wallet for Monero",
11 +
12 + "haven_app": "Haven by Cake Wallet",
13 + "haven_app_wallet_text": "Awesome wallet for Haven",
14
15 "accounts" : "Contas",
16 "edit" : "Editar",
res/values/strings_ru.arb
+3
@@ -8,6 +8,9 @@
8
9 "monero_com": "Monero.com by Cake Wallet",
10 "monero_com_wallet_text": "Awesome wallet for Monero",
11 +
12 + "haven_app": "Haven by Cake Wallet",
13 + "haven_app_wallet_text": "Awesome wallet for Haven",
14
15 "accounts" : "Аккаунты",
16 "edit" : "Редактировать",
res/values/strings_uk.arb
+3
@@ -8,6 +8,9 @@
8
9 "monero_com": "Monero.com by Cake Wallet",
10 "monero_com_wallet_text": "Awesome wallet for Monero",
11 +
12 + "haven_app": "Haven by Cake Wallet",
13 + "haven_app_wallet_text": "Awesome wallet for Haven",
14
15 "accounts" : "Акаунти",
16 "edit" : "Редагувати",
res/values/strings_zh.arb
+3
@@ -8,6 +8,9 @@
8
9 "monero_com": "Monero.com by Cake Wallet",
10 "monero_com_wallet_text": "Awesome wallet for Monero",
11 +
12 + "haven_app": "Haven by Cake Wallet",
13 + "haven_app_wallet_text": "Awesome wallet for Haven",
14
15 "accounts" : "账户",
16 "edit" : "编辑",
scripts/android/app_env.sh
+17 -3
@@ -8,8 +8,9 @@ APP_ANDROID_PACKAGE=""
8
9 MONERO_COM="monero.com"
10 CAKEWALLET="cakewallet"
11 +HAVEN="haven"
12
12 -TYPES=($MONERO_COM $CAKEWALLET)
13 +TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
14 APP_ANDROID_TYPE=$1
15
16 MONERO_COM_NAME="Monero.com"
@@ -19,11 +20,17 @@ MONERO_COM_BUNDLE_ID="com.monero.app"
20 MONERO_COM_PACKAGE="com.monero.app"
21
22 CAKEWALLET_NAME="Cake Wallet"
22 -CAKEWALLET_VERSION="4.3.8"
23 -CAKEWALLET_BUILD_NUMBER=89
23 +CAKEWALLET_VERSION="4.3.9"
24 +CAKEWALLET_BUILD_NUMBER=94
25 CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
26 CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"
27
28 +HAVEN_NAME="Haven"
29 +HAVEN_VERSION="1.0.0"
30 +HAVEN_BUILD_NUMBER=1
31 +HAVEN_BUNDLE_ID="com.cakewallet.haven"
32 +HAVEN_PACKAGE="com.cakewallet.haven"
33 +
34 if ! [[ " ${TYPES[*]} " =~ " ${APP_ANDROID_TYPE} " ]]; then
35 echo "Wrong app type."
36 exit 1
@@ -44,6 +51,13 @@ case $APP_ANDROID_TYPE in
51 APP_ANDROID_BUNDLE_ID=$CAKEWALLET_BUNDLE_ID
52 APP_ANDROID_PACKAGE=$CAKEWALLET_PACKAGE
53 ;;
54 + $HAVEN)
55 + APP_ANDROID_NAME=$HAVEN_NAME
56 + APP_ANDROID_VERSION=$HAVEN_VERSION
57 + APP_ANDROID_BUILD_NUMBER=$HAVEN_BUILD_NUMBER
58 + APP_ANDROID_BUNDLE_ID=$HAVEN_BUNDLE_ID
59 + APP_ANDROID_PACKAGE=$HAVEN_PACKAGE
60 + ;;
61 esac
62
63 export APP_ANDROID_TYPE
scripts/android/app_icon.sh
+8 -3
@@ -14,15 +14,20 @@ ANDROID_ICON_SET_DEST_PATH=`pwd`/../../android/app/src/main/res
14
15 case $APP_ANDROID_TYPE in
16 "monero.com")
17 - APP_LOGO=$ASSETS_DIR/images/monero.com_logo.png
18 - ANDROID_ICON=$MONERO_COM_PATH
19 - ANDROID_ICON_SET=$MONEROCOM_ICON_SET_PATH
17 + APP_LOGO=$ASSETS_DIR/images/monero.com_logo.png
18 + ANDROID_ICON=$MONERO_COM_PATH
19 + ANDROID_ICON_SET=$MONEROCOM_ICON_SET_PATH
20 ;;
21 "cakewallet")
22 APP_LOGO=$ASSETS_DIR/images/cakewallet_logo.png
23 ANDROID_ICON=$CAKEWALLET_PATH
24 ANDROID_ICON_SET=$CAKEWALLET_ICON_SET_PATH
25 ;;
26 + "haven")
27 + APP_LOGO=$ASSETS_DIR/images/cakewallet_logo.png
28 + ANDROID_ICON=$CAKEWALLET_PATH
29 + ANDROID_ICON_SET=$CAKEWALLET_ICON_SET_PATH
30 + ;;
31 esac
32
33 rm $APP_LOGO_DEST_PATH
scripts/android/build_all.sh
+13 -7
@@ -1,8 +1,14 @@
1 -# /bin/bash
1 +#!/bin/sh
2
3 -./build_iconv.sh
4 -./build_boost.sh
5 -./build_openssl.sh
6 -./build_sodium.sh
7 -./build_zmq.sh
8 -./build_monero.sh
3 +if [ -z "$APP_ANDROID_TYPE" ]; then
4 + echo "Please set APP_ANDROID_TYPE"
5 + exit 1
6 +fi
7 +
8 +DIR=$(dirname "$0")
9 +
10 +case $APP_ANDROID_TYPE in
11 + "monero.com") $DIR/build_monero_all.sh ;;
12 + "cakewallet") $DIR/build_monero_all.sh ;;
13 + "haven") $DIR/build_haven_all.sh ;;
14 +esac
scripts/android/build_haven.sh new
+70
@@ -0,0 +1,70 @@
1 +#!/bin/sh
2 +
3 +. ./config.sh
4 +HAVEN_VERSION=tags/v2.2.2
5 +HAVEN_SRC_DIR=${WORKDIR}/haven
6 +
7 +git clone https://github.com/haven-protocol-org/haven-main.git ${HAVEN_SRC_DIR}
8 +git checkout ${HAVEN_VERSION}
9 +cd $HAVEN_SRC_DIR
10 +git submodule init
11 +git submodule update
12 +
13 +for arch in "aarch" "aarch64" "i686" "x86_64"
14 +do
15 +FLAGS=""
16 +PREFIX=${WORKDIR}/prefix_${arch}
17 +DEST_LIB_DIR=${PREFIX}/lib/haven
18 +DEST_INCLUDE_DIR=${PREFIX}/include
19 +export CMAKE_INCLUDE_PATH="${PREFIX}/include"
20 +export CMAKE_LIBRARY_PATH="${PREFIX}/lib"
21 +ANDROID_STANDALONE_TOOLCHAIN_PATH="${TOOLCHAIN_BASE_DIR}_${arch}"
22 +PATH="${ANDROID_STANDALONE_TOOLCHAIN_PATH}/bin:${ORIGINAL_PATH}"
23 +
24 +mkdir -p $DEST_LIB_DIR
25 +mkdir -p $DEST_INCLUDE_DIR
26 +
27 +case $arch in
28 + "aarch" )
29 + CLANG=arm-linux-androideabi-clang
30 + CXXLANG=arm-linux-androideabi-clang++
31 + BUILD_64=OFF
32 + TAG="android-armv7"
33 + ARCH="armv7-a"
34 + ARCH_ABI="armeabi-v7a"
35 + FLAGS="-D CMAKE_ANDROID_ARM_MODE=ON -D NO_AES=true";;
36 + "aarch64" )
37 + CLANG=aarch64-linux-androideabi-clang
38 + CXXLANG=aarch64-linux-androideabi-clang++
39 + BUILD_64=ON
40 + TAG="android-armv8"
41 + ARCH="armv8-a"
42 + ARCH_ABI="arm64-v8a";;
43 + "i686" )
44 + CLANG=i686-linux-androideabi-clang
45 + CXXLANG=i686-linux-androideabi-clang++
46 + BUILD_64=OFF
47 + TAG="android-x86"
48 + ARCH="i686"
49 + ARCH_ABI="x86";;
50 + "x86_64" )
51 + CLANG=x86_64-linux-androideabi-clang
52 + CXXLANG=x86_64-linux-androideabi-clang++
53 + BUILD_64=ON
54 + TAG="android-x86_64"
55 + ARCH="x86-64"
56 + ARCH_ABI="x86_64";;
57 +esac
58 +
59 +cd $HAVEN_SRC_DIR
60 +rm -rf ./build/release
61 +mkdir -p ./build/release
62 +cd ./build/release
63 +CC=${CLANG} CXX=${CXXLANG} cmake -D USE_DEVICE_TREZOR=OFF -D BUILD_GUI_DEPS=1 -D BUILD_TESTS=OFF -D ARCH=${ARCH} -D STATIC=ON -D BUILD_64=${BUILD_64} -D CMAKE_BUILD_TYPE=release -D ANDROID=true -D INSTALL_VENDORED_LIBUNBOUND=ON -D BUILD_TAG=${TAG} -D CMAKE_SYSTEM_NAME="Android" -D CMAKE_ANDROID_STANDALONE_TOOLCHAIN="${ANDROID_STANDALONE_TOOLCHAIN_PATH}" -D CMAKE_ANDROID_ARCH_ABI=${ARCH_ABI} $FLAGS ../..
64 +
65 +make wallet_api -j4
66 +find . -path ./lib -prune -o -name '*.a' -exec cp '{}' lib \;
67 +
68 +cp -r ./lib/* $DEST_LIB_DIR
69 +cp ../../src/wallet/api/wallet2_api.h $DEST_INCLUDE_DIR
70 +done
scripts/android/build_haven_all.sh new
+8
@@ -0,0 +1,8 @@
1 +# /bin/bash
2 +
3 +./build_iconv.sh
4 +./build_boost.sh
5 +./build_openssl.sh
6 +./build_sodium.sh
7 +./build_zmq.sh
8 +./build_haven.sh
scripts/android/build_monero_all.sh new
+8
@@ -0,0 +1,8 @@
1 +# /bin/bash
2 +
3 +./build_iconv.sh
4 +./build_boost.sh
5 +./build_openssl.sh
6 +./build_sodium.sh
7 +./build_zmq.sh
8 +./build_monero.sh
scripts/android/copy_monero_deps.sh
+1 -1
@@ -2,7 +2,7 @@
2
3 WORKDIR=/opt/android
4 CW_DIR=${WORKDIR}/cake_wallet
5 -CW_EXRTERNAL_DIR=${CW_DIR}/cw_monero/ios/External/android
5 +CW_EXRTERNAL_DIR=${CW_DIR}/cw_shared_external/ios/External/android
6
7 for arch in "aarch" "aarch64" "i686" "x86_64"
8 do
scripts/android/pubspec_gen.sh
+5 -1
@@ -2,6 +2,7 @@
2
3 MONERO_COM=monero.com
4 CAKEWALLET=cakewallet
5 +HAVEN=haven
6 CONFIG_ARGS=""
7
8 case $APP_ANDROID_TYPE in
@@ -9,7 +10,10 @@ case $APP_ANDROID_TYPE in
10 CONFIG_ARGS="--monero"
11 ;;
12 $CAKEWALLET)
12 - CONFIG_ARGS="--monero --bitcoin"
13 + CONFIG_ARGS="--monero --bitcoin --haven"
14 + ;;
15 + $HAVEN)
16 + CONFIG_ARGS="--haven"
17 ;;
18 esac
19
scripts/ios/app_config.sh
+5 -1
@@ -2,6 +2,7 @@
2
3 MONERO_COM="monero.com"
4 CAKEWALLET="cakewallet"
5 +HAVEN="haven"
6 DIR=`pwd`
7
8 if [ -z "$APP_IOS_TYPE" ]; then
@@ -22,7 +23,10 @@ case $APP_IOS_TYPE in
23 CONFIG_ARGS="--monero"
24 ;;
25 $CAKEWALLET)
25 - CONFIG_ARGS="--monero --bitcoin"
26 + CONFIG_ARGS="--monero --bitcoin --haven"
27 + ;;
28 + $HAVEN)
29 + CONFIG_ARGS="--haven"
30 ;;
31 esac
32
scripts/ios/app_env.sh
+15 -3
@@ -7,8 +7,9 @@ APP_IOS_BUNDLE_ID=""
7
8 MONERO_COM="monero.com"
9 CAKEWALLET="cakewallet"
10 +HAVEN="haven"
11
11 -TYPES=($MONERO_COM $CAKEWALLET)
12 +TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
13 APP_IOS_TYPE=$1
14
15 MONERO_COM_NAME="Monero.com"
@@ -17,10 +18,15 @@ MONERO_COM_BUILD_NUMBER=14
18 MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
19
20 CAKEWALLET_NAME="Cake Wallet"
20 -CAKEWALLET_VERSION="4.3.8"
21 -CAKEWALLET_BUILD_NUMBER=84
21 +CAKEWALLET_VERSION="4.3.9"
22 +CAKEWALLET_BUILD_NUMBER=89
23 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
24
25 +HAVEN_NAME="Haven"
26 +HAVEN_VERSION="1.0.0"
27 +HAVEN_BUILD_NUMBER=3
28 +HAVEN_BUNDLE_ID="com.cakewallet.haven"
29 +
30 if ! [[ " ${TYPES[*]} " =~ " ${APP_IOS_TYPE} " ]]; then
31 echo "Wrong app type."
32 exit 1
@@ -39,6 +45,12 @@ case $APP_IOS_TYPE in
45 APP_IOS_BUILD_NUMBER=$CAKEWALLET_BUILD_NUMBER
46 APP_IOS_BUNDLE_ID=$CAKEWALLET_BUNDLE_ID
47 ;;
48 + $HAVEN)
49 + APP_IOS_NAME=$HAVEN_NAME
50 + APP_IOS_VERSION=$HAVEN_VERSION
51 + APP_IOS_BUILD_NUMBER=$HAVEN_BUILD_NUMBER
52 + APP_IOS_BUNDLE_ID=$HAVEN_BUNDLE_ID
53 + ;;
54 esac
55
56 export APP_IOS_TYPE
scripts/ios/app_icon.sh
+4
@@ -14,6 +14,10 @@ case $APP_IOS_TYPE in
14 ICON_120_PATH=`pwd`/../../assets/images/cakewallet_icon_120.png
15 ICON_180_PATH=`pwd`/../../assets/images/cakewallet_icon_180.png
16 ICON_1024_PATH=`pwd`/../../assets/images/cakewallet_icon_1024.png;;
17 + "haven")
18 + ICON_120_PATH=`pwd`/../../assets/images/cakewallet_icon_120.png
19 + ICON_180_PATH=`pwd`/../../assets/images/cakewallet_icon_180.png
20 + ICON_1024_PATH=`pwd`/../../assets/images/cakewallet_icon_1024.png;;
21 esac
22
23 rm $DEST_DIR_PATH/app_icon_120.png
scripts/ios/build_all.sh renamed
+1
@@ -10,4 +10,5 @@ DIR=$(dirname "$0")
10 case $APP_IOS_TYPE in
11 "monero.com") $DIR/build_monero_all.sh ;;
12 "cakewallet") $DIR/build_monero_all.sh ;;
13 + "haven") $DIR/build_haven_all.sh ;;
14 esac
scripts/ios/build_haven.sh new
+62
@@ -0,0 +1,62 @@
1 +#!/bin/sh
2 +
3 +. ./config.sh
4 +
5 +HAVEN_URL="https://github.com/haven-protocol-org/haven-main.git"
6 +HAVEN_DIR_PATH="${EXTERNAL_IOS_SOURCE_DIR}/haven"
7 +HAVEN_VERSION=tags/v2.2.2
8 +BUILD_TYPE=release
9 +PREFIX=${EXTERNAL_IOS_DIR}
10 +
11 +echo "Cloning haven from - $HAVEN_URL to - $HAVEN_DIR_PATH"
12 +git clone $HAVEN_URL $HAVEN_DIR_PATH
13 +cd $HAVEN_DIR_PATH
14 +git checkout $HAVEN_VERSION
15 +git submodule update --init --force
16 +mkdir -p build
17 +cd ..
18 +
19 +ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
20 +if [ -z $INSTALL_PREFIX ]; then
21 + INSTALL_PREFIX=${ROOT_DIR}/haven
22 +fi
23 +
24 +for arch in "arm64" #"armv7" "arm64"
25 +do
26 +
27 +echo "Building IOS ${arch}"
28 +export CMAKE_INCLUDE_PATH="${PREFIX}/include"
29 +export CMAKE_LIBRARY_PATH="${PREFIX}/lib"
30 +
31 +case $arch in
32 + "armv7" )
33 + DEST_LIB=../../lib-armv7;;
34 + "arm64" )
35 + DEST_LIB=../../lib-armv8-a;;
36 +esac
37 +
38 +rm -rf haven/build > /dev/null
39 +
40 +mkdir -p haven/build/${BUILD_TYPE}
41 +pushd haven/build/${BUILD_TYPE}
42 +cmake -D IOS=ON \
43 + -DARCH=${arch} \
44 + -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
45 + -DSTATIC=ON \
46 + -DBUILD_GUI_DEPS=ON \
47 + -DINSTALL_VENDORED_LIBUNBOUND=ON \
48 + -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} \
49 + -DUSE_DEVICE_TREZOR=OFF \
50 + ../..
51 +make -j4 && make install
52 +cp src/cryptonote_basic/libcryptonote_basic.a ${DEST_LIB}
53 +cp src/offshore/liboffshore.a ${DEST_LIB}
54 +popd
55 +
56 +done
57 +
58 +mkdir -p $EXTERNAL_IOS_LIB_DIR/haven
59 +mkdir -p $EXTERNAL_IOS_INCLUDE_DIR/haven
60 +#only for arm64
61 +cp ${HAVEN_DIR_PATH}/lib-armv8-a/* $EXTERNAL_IOS_LIB_DIR/haven
62 +cp ${HAVEN_DIR_PATH}/include/wallet/api/* $EXTERNAL_IOS_INCLUDE_DIR/haven
\ No newline at end of file
scripts/ios/build_haven_all.sh new
+9
@@ -0,0 +1,9 @@
1 +#!/bin/sh
2 +
3 +. ./config.sh
4 +./install_missing_headers.sh
5 +./build_openssl.sh
6 +./build_boost.sh
7 +./build_sodium.sh
8 +./build_zmq.sh
9 +./build_haven.sh
\ No newline at end of file
scripts/ios/config.sh
+1 -1
@@ -2,7 +2,7 @@
2
3 export IOS_SCRIPTS_DIR=`pwd`
4 export CW_ROOT=${IOS_SCRIPTS_DIR}/../..
5 -export EXTERNAL_DIR=${CW_ROOT}/cw_monero/ios/External
5 +export EXTERNAL_DIR=${CW_ROOT}/cw_shared_external/ios/External
6 export EXTERNAL_IOS_DIR=${EXTERNAL_DIR}/ios
7 export EXTERNAL_IOS_SOURCE_DIR=${EXTERNAL_IOS_DIR}/sources
8 export EXTERNAL_IOS_LIB_DIR=${EXTERNAL_IOS_DIR}/lib
scripts/ios/setup.sh new
+29
@@ -0,0 +1,29 @@
1 +#!/bin/sh
2 +
3 +. ./config.sh
4 +
5 +cd $EXTERNAL_IOS_LIB_DIR
6 +libtool -static -o libboost.a ./boost/*.a
7 +libtool -static -o libhaven.a ./haven/*.a
8 +libtool -static -o libmonero.a ./monero/*.a
9 +
10 +CW_HAVEN_EXTERNAL_LIB=../../../cw_haven/ios/External/ios/lib
11 +CW_HAVEN_EXTERNAL_INCLUDE=../../../cw_haven/ios/External/ios/include
12 +CW_MONERO_EXTERNAL=../../../cw_haven/ios/External/ios/lib
13 +
14 +mkdir -p $CW_HAVEN_EXTERNAL_INCLUDE
15 +mkdir -p $CW_HAVEN_EXTERNAL_LIB
16 +mkdir -p $CW_MONERO_EXTERNAL
17 +
18 +ln -s ./libboost.a $CW_HAVEN_EXTERNAL_LIB
19 +ln -s ./libcrypto.a $CW_HAVEN_EXTERNAL_LIB
20 +ln -s ./libssl.a $CW_HAVEN_EXTERNAL_LIB
21 +ln -s ./libsodium.a $CW_HAVEN_EXTERNAL_LIB
22 +cp ./libhaven.a $CW_HAVEN_EXTERNAL_LIB
23 +cp ../include/haven/* $CW_HAVEN_EXTERNAL_INCLUDE
24 +
25 +#ln -s ./libboost.a $CW_HAVEN_EXTERNAL_LIB
26 +#ln -s ./libcrypto.a $CW_HAVEN_EXTERNAL_LIB
27 +#ln -s ./libssl.a $CW_HAVEN_EXTERNAL_LIB
28 +#ln -s ./libsodium.a $CW_HAVEN_EXTERNAL_LIB
29 +#cp ./libhaven.a $CW_HAVEN_EXTERNAL_LIB
\ No newline at end of file
tool/configure.dart
+194 -10
@@ -3,6 +3,7 @@ import 'dart:io';
3
4 const bitcoinOutputPath = 'lib/bitcoin/bitcoin.dart';
5 const moneroOutputPath = 'lib/monero/monero.dart';
6 +const havenOutputPath = 'lib/haven/haven.dart';
7 const walletTypesPath = 'lib/wallet_types.g.dart';
8 const pubspecDefaultPath = 'pubspec_default.yaml';
9 const pubspecOutputPath = 'pubspec.yaml';
@@ -11,10 +12,11 @@ Future<void> main(List<String> args) async {
12 const prefix = '--';
13 final hasBitcoin = args.contains('${prefix}bitcoin');
14 final hasMonero = args.contains('${prefix}monero');
15 + final hasHaven = args.contains('${prefix}haven');
16 await generateBitcoin(hasBitcoin);
17 await generateMonero(hasMonero);
16 - await generatePubspec(hasMonero: hasMonero, hasBitcoin: hasBitcoin);
17 - await generateWalletTypes(hasMonero: hasMonero, hasBitcoin: hasBitcoin);
18 + await generatePubspec(hasMonero: hasMonero, hasBitcoin: hasBitcoin, hasHaven: hasHaven);
19 + await generateWalletTypes(hasMonero: hasMonero, hasBitcoin: hasBitcoin, hasHaven: hasHaven);
20 }
21
22 Future<void> generateBitcoin(bool hasImplementation) async {
@@ -123,15 +125,15 @@ import 'package:cake_wallet/view_model/send/output.dart';
125 import 'package:cw_core/wallet_service.dart';
126 import 'package:hive/hive.dart';""";
127 const moneroCWHeaders = """
126 -import 'package:cw_monero/get_height_by_date.dart';
127 -import 'package:cw_monero/monero_amount_format.dart';
128 -import 'package:cw_monero/monero_transaction_priority.dart';
128 +import 'package:cw_core/get_height_by_date.dart';
129 +import 'package:cw_core/monero_amount_format.dart';
130 +import 'package:cw_core/monero_transaction_priority.dart';
131 import 'package:cw_monero/monero_wallet_service.dart';
132 import 'package:cw_monero/monero_wallet.dart';
133 import 'package:cw_monero/monero_transaction_info.dart';
134 import 'package:cw_monero/monero_transaction_history.dart';
135 import 'package:cw_monero/monero_transaction_creation_credentials.dart';
134 -import 'package:cw_monero/account.dart' as monero_account;
136 +import 'package:cw_core/account.dart' as monero_account;
137 import 'package:cw_monero/api/wallet.dart' as monero_wallet_api;
138 import 'package:cw_monero/mnemonics/english.dart';
139 import 'package:cw_monero/mnemonics/chinese_simplified.dart';
@@ -228,7 +230,7 @@ abstract class Monero {
230 double formatterMoneroAmountToDouble({int amount});
231 int formatterMoneroParseAmount({String amount});
232 Account getCurrentAccount(Object wallet);
231 - void setCurrentAccount(Object wallet, Account account);
233 + void setCurrentAccount(Object wallet, int id, String label);
234 void onStartup();
235 int getTransactionInfoAccountId(TransactionInfo tx);
236 WalletService createMoneroWalletService(Box<WalletInfo> walletInfoSource);
@@ -271,7 +273,171 @@ abstract class MoneroAccountList {
273 await outputFile.writeAsString(output);
274 }
275
274 -Future<void> generatePubspec({bool hasMonero, bool hasBitcoin}) async {
276 +Future<void> generateHaven(bool hasImplementation) async {
277 + final outputFile = File(moneroOutputPath);
278 + const havenCommonHeaders = """
279 +import 'package:mobx/mobx.dart';
280 +import 'package:flutter/foundation.dart';
281 +import 'package:cw_core/wallet_credentials.dart';
282 +import 'package:cw_core/wallet_info.dart';
283 +import 'package:cw_core/transaction_priority.dart';
284 +import 'package:cw_core/transaction_history.dart';
285 +import 'package:cw_core/transaction_info.dart';
286 +import 'package:cw_core/balance.dart';
287 +import 'package:cw_core/output_info.dart';
288 +import 'package:cake_wallet/view_model/send/output.dart';
289 +import 'package:cw_core/wallet_service.dart';
290 +import 'package:hive/hive.dart';""";
291 + const havenCWHeaders = """
292 +import 'package:cw_core/get_height_by_date.dart';
293 +import 'package:cw_core/monero_amount_format.dart';
294 +import 'package:cw_core/monero_transaction_priority.dart';
295 +import 'package:cw_haven/haven_wallet_service.dart';
296 +import 'package:cw_haven/haven_wallet.dart';
297 +import 'package:cw_haven/haven_transaction_info.dart';
298 +import 'package:cw_haven/haven_transaction_history.dart';
299 +import 'package:cw_core/account.dart' as monero_account;
300 +import 'package:cw_haven/api/wallet.dart' as monero_wallet_api;
301 +import 'package:cw_haven/mnemonics/english.dart';
302 +import 'package:cw_haven/mnemonics/chinese_simplified.dart';
303 +import 'package:cw_haven/mnemonics/dutch.dart';
304 +import 'package:cw_haven/mnemonics/german.dart';
305 +import 'package:cw_haven/mnemonics/japanese.dart';
306 +import 'package:cw_haven/mnemonics/russian.dart';
307 +import 'package:cw_haven/mnemonics/spanish.dart';
308 +import 'package:cw_haven/mnemonics/portuguese.dart';
309 +import 'package:cw_haven/mnemonics/french.dart';
310 +import 'package:cw_haven/mnemonics/italian.dart';
311 +import 'package:cw_haven/haven_transaction_creation_credentials.dart';
312 +""";
313 + const havenCwPart = "part 'cw_haven.dart';";
314 + const havenContent = """
315 +class Account {
316 + Account({this.id, this.label});
317 + final int id;
318 + final String label;
319 +}
320 +
321 +class Subaddress {
322 + Subaddress({this.id, this.accountId, this.label, this.address});
323 + final int id;
324 + final int accountId;
325 + final String label;
326 + final String address;
327 +}
328 +
329 +class HavenBalance extends Balance {
330 + HavenBalance({@required this.fullBalance, @required this.unlockedBalance})
331 + : formattedFullBalance = haven.formatterMoneroAmountToString(amount: fullBalance),
332 + formattedUnlockedBalance =
333 + haven.formatterMoneroAmountToString(amount: unlockedBalance),
334 + super(unlockedBalance, fullBalance);
335 +
336 + HavenBalance.fromString(
337 + {@required this.formattedFullBalance,
338 + @required this.formattedUnlockedBalance})
339 + : fullBalance = haven.formatterMoneroParseAmount(amount: formattedFullBalance),
340 + unlockedBalance = haven.formatterMoneroParseAmount(amount: formattedUnlockedBalance),
341 + super(haven.formatterMoneroParseAmount(amount: formattedUnlockedBalance),
342 + haven.formatterMoneroParseAmount(amount: formattedFullBalance));
343 +
344 + final int fullBalance;
345 + final int unlockedBalance;
346 + final String formattedFullBalance;
347 + final String formattedUnlockedBalance;
348 +
349 + @override
350 + String get formattedAvailableBalance => formattedUnlockedBalance;
351 +
352 + @override
353 + String get formattedAdditionalBalance => formattedFullBalance;
354 +}
355 +
356 +abstract class HavenWalletDetails {
357 + @observable
358 + Account account;
359 +
360 + @observable
361 + HavenBalance balance;
362 +}
363 +
364 +abstract class Haven {
365 + HavenAccountList getAccountList(Object wallet);
366 +
367 + MoneroSubaddressList getSubaddressList(Object wallet);
368 +
369 + TransactionHistoryBase getTransactionHistory(Object wallet);
370 +
371 + HavenWalletDetails getMoneroWalletDetails(Object wallet);
372 +
373 + String getTransactionAddress(Object wallet, int accountIndex, int addressIndex);
374 +
375 + int getHeigthByDate({DateTime date});
376 + TransactionPriority getDefaultTransactionPriority();
377 + TransactionPriority deserializeMoneroTransactionPriority({int raw});
378 + List<TransactionPriority> getTransactionPriorities();
379 + List<String> getMoneroWordList(String language);
380 +
381 + WalletCredentials createHavenRestoreWalletFromKeysCredentials({
382 + String name,
383 + String spendKey,
384 + String viewKey,
385 + String address,
386 + String password,
387 + String language,
388 + int height});
389 + WalletCredentials createHavenRestoreWalletFromSeedCredentials({String name, String password, int height, String mnemonic});
390 + WalletCredentials createHavenNewWalletCredentials({String name, String password, String language});
391 + Map<String, String> getKeys(Object wallet);
392 + Object createHavenTransactionCreationCredentials({List<Output> outputs, TransactionPriority priority, String assetType});
393 + String formatterMoneroAmountToString({int amount});
394 + double formatterMoneroAmountToDouble({int amount});
395 + int formatterMoneroParseAmount({String amount});
396 + Account getCurrentAccount(Object wallet);
397 + void setCurrentAccount(Object wallet, int id, String label);
398 + void onStartup();
399 + int getTransactionInfoAccountId(TransactionInfo tx);
400 + WalletService createHavenWalletService(Box<WalletInfo> walletInfoSource);
401 +}
402 +
403 +abstract class MoneroSubaddressList {
404 + ObservableList<Subaddress> get subaddresses;
405 + void update(Object wallet, {int accountIndex});
406 + void refresh(Object wallet, {int accountIndex});
407 + List<Subaddress> getAll(Object wallet);
408 + Future<void> addSubaddress(Object wallet, {int accountIndex, String label});
409 + Future<void> setLabelSubaddress(Object wallet,
410 + {int accountIndex, int addressIndex, String label});
411 +}
412 +
413 +abstract class HavenAccountList {
414 + ObservableList<Account> get accounts;
415 + void update(Object wallet);
416 + void refresh(Object wallet);
417 + List<Account> getAll(Object wallet);
418 + Future<void> addAccount(Object wallet, {String label});
419 + Future<void> setLabelAccount(Object wallet, {int accountIndex, String label});
420 +}
421 + """;
422 +
423 + const havenEmptyDefinition = 'Monero monero;\n';
424 + const havenCWDefinition = 'Monero monero = CWMonero();\n';
425 +
426 + final output = '$havenCommonHeaders\n'
427 + + (hasImplementation ? '$havenCWHeaders\n' : '\n')
428 + + (hasImplementation ? '$havenCwPart\n\n' : '\n')
429 + + (hasImplementation ? havenCWDefinition : havenEmptyDefinition)
430 + + '\n'
431 + + havenContent;
432 +
433 + if (outputFile.existsSync()) {
434 + await outputFile.delete();
435 + }
436 +
437 + await outputFile.writeAsString(output);
438 +}
439 +
440 +Future<void> generatePubspec({bool hasMonero, bool hasBitcoin, bool hasHaven}) async {
441 const cwCore = """
442 cw_core:
443 path: ./cw_core
@@ -284,6 +450,14 @@ Future<void> generatePubspec({bool hasMonero, bool hasBitcoin}) async {
450 cw_bitcoin:
451 path: ./cw_bitcoin
452 """;
453 + const cwHaven = """
454 + cw_haven:
455 + path: ./cw_haven
456 + """;
457 + const cwSharedExternal = """
458 + cw_shared_external:
459 + path: ./cw_shared_external
460 + """;
461 final inputFile = File(pubspecOutputPath);
462 final inputText = await inputFile.readAsString();
463 final inputLines = inputText.split('\n');
@@ -291,13 +465,19 @@ Future<void> generatePubspec({bool hasMonero, bool hasBitcoin}) async {
465 var output = cwCore;
466
467 if (hasMonero) {
294 - output += '\n$cwMonero';
468 + output += '\n$cwMonero\n$cwSharedExternal';
469 }
470
471 if (hasBitcoin) {
472 output += '\n$cwBitcoin';
473 }
474
475 + if (hasHaven && !hasMonero) {
476 + output += '\n$cwSharedExternal\n$cwHaven';
477 + } else if (hasHaven) {
478 + output += '\n$cwHaven';
479 + }
480 +
481 final outputLines = output.split('\n');
482 inputLines.insertAll(dependenciesIndex + 1, outputLines);
483 final outputContent = inputLines.join('\n');
@@ -310,7 +490,7 @@ Future<void> generatePubspec({bool hasMonero, bool hasBitcoin}) async {
490 await outputFile.writeAsString(outputContent);
491 }
492
313 -Future<void> generateWalletTypes({bool hasMonero, bool hasBitcoin}) async {
493 +Future<void> generateWalletTypes({bool hasMonero, bool hasBitcoin, bool hasHaven}) async {
494 final walletTypesFile = File(walletTypesPath);
495
496 if (walletTypesFile.existsSync()) {
@@ -329,6 +509,10 @@ Future<void> generateWalletTypes({bool hasMonero, bool hasBitcoin}) async {
509 outputContent += '\tWalletType.bitcoin,\n\tWalletType.litecoin,\n';
510 }
511
512 + if (hasHaven) {
513 + outputContent += '\tWalletType.haven,\n';
514 + }
515 +
516 outputContent += '];\n';
517 await walletTypesFile.writeAsString(outputContent);
518 }
\ No newline at end of file