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