mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 19:49:22 +00:00
Merge branch 'main' into CAKE-272-implement-localization-generation-script
This commit is contained in:
commit
8603e3f2bf
52 changed files with 1506 additions and 94 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -87,6 +87,8 @@ cw_monero/cw_monero/android/.cxx/
|
|||
android/key.properties
|
||||
|
||||
**/tool/.secrets-prod.json
|
||||
**/tool/.secrets-test.json
|
||||
**/tool/.secrets-config.json
|
||||
**/lib/.secrets.g.dart
|
||||
|
||||
vendor/
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
# Cake Wallet
|
||||
# CakeWallet for Android and iOS
|
||||
|
||||
The project description, motivation, build scripts, instructions, tests will be added soon (February 2021);
|
||||
## Open Source Monero and Bitcoin Wallet
|
||||
|
||||
Copyright (c) 2021 Cake Technologies LLC.
|
||||
|
||||
More instructions to follow
|
||||
|
||||
For instructions on how to build for Android: please view file `howto-build-android.md`
|
BIN
assets/images/wyre-icon.png
Normal file
BIN
assets/images/wyre-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
|
@ -17,7 +17,7 @@ set(EXTERNAL_LIBS_DIR ${CMAKE_SOURCE_DIR}/../ios/External/android)
|
|||
|
||||
add_library(sodium STATIC IMPORTED)
|
||||
set_target_properties(sodium PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/libsodium/lib/${ANDROID_ABI}/libsodium.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libsodium.a)
|
||||
|
||||
############
|
||||
# OpenSSL
|
||||
|
@ -25,11 +25,11 @@ set_target_properties(sodium PROPERTIES IMPORTED_LOCATION
|
|||
|
||||
add_library(crypto STATIC IMPORTED)
|
||||
set_target_properties(crypto PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/openssl/lib/${ANDROID_ABI}/libcrypto.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libcrypto.a)
|
||||
|
||||
add_library(ssl STATIC IMPORTED)
|
||||
set_target_properties(ssl PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/openssl/lib/${ANDROID_ABI}/libssl.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libssl.a)
|
||||
|
||||
############
|
||||
# Boost
|
||||
|
@ -37,39 +37,39 @@ set_target_properties(ssl PROPERTIES IMPORTED_LOCATION
|
|||
|
||||
add_library(boost_chrono STATIC IMPORTED)
|
||||
set_target_properties(boost_chrono PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_chrono.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_chrono.a)
|
||||
|
||||
add_library(boost_date_time STATIC IMPORTED)
|
||||
set_target_properties(boost_date_time PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_date_time.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_date_time.a)
|
||||
|
||||
add_library(boost_filesystem STATIC IMPORTED)
|
||||
set_target_properties(boost_filesystem PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_filesystem.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_filesystem.a)
|
||||
|
||||
add_library(boost_program_options STATIC IMPORTED)
|
||||
set_target_properties(boost_program_options PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_program_options.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_program_options.a)
|
||||
|
||||
add_library(boost_regex STATIC IMPORTED)
|
||||
set_target_properties(boost_regex PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_regex.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_regex.a)
|
||||
|
||||
add_library(boost_serialization STATIC IMPORTED)
|
||||
set_target_properties(boost_serialization PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_serialization.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_serialization.a)
|
||||
|
||||
add_library(boost_system STATIC IMPORTED)
|
||||
set_target_properties(boost_system PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_system.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_system.a)
|
||||
|
||||
add_library(boost_thread STATIC IMPORTED)
|
||||
set_target_properties(boost_thread PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_thread.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_thread.a)
|
||||
|
||||
add_library(boost_wserialization STATIC IMPORTED)
|
||||
set_target_properties(boost_wserialization PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_wserialization.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_wserialization.a)
|
||||
|
||||
#############
|
||||
# Monero
|
||||
|
@ -77,101 +77,111 @@ set_target_properties(boost_wserialization PROPERTIES IMPORTED_LOCATION
|
|||
|
||||
add_library(wallet_api STATIC IMPORTED)
|
||||
set_target_properties(wallet_api PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libwallet_api.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libwallet_api.a)
|
||||
|
||||
add_library(wallet STATIC IMPORTED)
|
||||
set_target_properties(wallet PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libwallet.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libwallet.a)
|
||||
|
||||
add_library(cryptonote_core STATIC IMPORTED)
|
||||
set_target_properties(cryptonote_core PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcryptonote_core.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libcryptonote_core.a)
|
||||
|
||||
add_library(cryptonote_basic STATIC IMPORTED)
|
||||
set_target_properties(cryptonote_basic PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcryptonote_basic.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libcryptonote_basic.a)
|
||||
|
||||
add_library(mnemonics STATIC IMPORTED)
|
||||
set_target_properties(mnemonics PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libmnemonics.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libmnemonics.a)
|
||||
|
||||
add_library(common STATIC IMPORTED)
|
||||
set_target_properties(common PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcommon.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libcommon.a)
|
||||
|
||||
add_library(cncrypto STATIC IMPORTED)
|
||||
set_target_properties(cncrypto PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcncrypto.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libcncrypto.a)
|
||||
|
||||
add_library(ringct STATIC IMPORTED)
|
||||
set_target_properties(ringct PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libringct.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libringct.a)
|
||||
|
||||
add_library(ringct_basic STATIC IMPORTED)
|
||||
set_target_properties(ringct_basic PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libringct_basic.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libringct_basic.a)
|
||||
|
||||
add_library(blockchain_db STATIC IMPORTED)
|
||||
set_target_properties(blockchain_db PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libblockchain_db.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libblockchain_db.a)
|
||||
|
||||
add_library(lmdb STATIC IMPORTED)
|
||||
set_target_properties(lmdb PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/liblmdb.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/liblmdb.a)
|
||||
|
||||
add_library(easylogging STATIC IMPORTED)
|
||||
set_target_properties(easylogging PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libeasylogging.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libeasylogging.a)
|
||||
|
||||
add_library(unbound STATIC IMPORTED)
|
||||
set_target_properties(unbound PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libunbound.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libunbound.a)
|
||||
|
||||
add_library(epee STATIC IMPORTED)
|
||||
set_target_properties(epee PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libepee.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libepee.a)
|
||||
|
||||
add_library(blocks STATIC IMPORTED)
|
||||
set_target_properties(blocks PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libblocks.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libblocks.a)
|
||||
|
||||
add_library(checkpoints STATIC IMPORTED)
|
||||
set_target_properties(checkpoints PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcheckpoints.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libcheckpoints.a)
|
||||
|
||||
add_library(device STATIC IMPORTED)
|
||||
set_target_properties(device PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libdevice.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libdevice.a)
|
||||
|
||||
add_library(device_trezor STATIC IMPORTED)
|
||||
set_target_properties(device_trezor PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libdevice_trezor.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libdevice_trezor.a)
|
||||
|
||||
add_library(multisig STATIC IMPORTED)
|
||||
set_target_properties(multisig PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libmultisig.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libmultisig.a)
|
||||
|
||||
add_library(version STATIC IMPORTED)
|
||||
set_target_properties(version PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libversion.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libversion.a)
|
||||
|
||||
add_library(net STATIC IMPORTED)
|
||||
set_target_properties(net PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libnet.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libnet.a)
|
||||
|
||||
add_library(hardforks STATIC IMPORTED)
|
||||
set_target_properties(hardforks PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libhardforks.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libhardforks.a)
|
||||
|
||||
add_library(randomx STATIC IMPORTED)
|
||||
set_target_properties(randomx PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/librandomx.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/librandomx.a)
|
||||
|
||||
add_library(rpc_base STATIC IMPORTED)
|
||||
set_target_properties(rpc_base PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/librpc_base.a)
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/librpc_base.a)
|
||||
|
||||
include_directories( ${EXTERNAL_LIBS_DIR}/monero/include )
|
||||
add_library(wallet-crypto STATIC IMPORTED)
|
||||
set_target_properties(wallet-crypto PROPERTIES IMPORTED_LOCATION
|
||||
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/monero/libwallet-crypto.a)
|
||||
|
||||
set(WALLET_CRYPTO "")
|
||||
|
||||
if(${ANDROID_ABI} STREQUAL "x86_64")
|
||||
set(WALLET_CRYPTO "wallet-crypto")
|
||||
endif()
|
||||
|
||||
include_directories( ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/include )
|
||||
|
||||
target_link_libraries( cw_monero
|
||||
|
||||
|
@ -199,6 +209,7 @@ target_link_libraries( cw_monero
|
|||
randomx
|
||||
hardforks
|
||||
rpc_base
|
||||
${WALLET_CRYPTO}
|
||||
|
||||
boost_chrono
|
||||
boost_date_time
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include <unistd.h>
|
||||
#include "thread"
|
||||
#include "CwWalletListener.h"
|
||||
#include "../External/android/monero/include/wallet2_api.h"
|
||||
#include "../External/android/x86/include/wallet2_api.h"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
|
|
136
howto-build-android.md
Normal file
136
howto-build-android.md
Normal file
|
@ -0,0 +1,136 @@
|
|||
# Building CakeWallet for Android
|
||||
|
||||
## Requirements and Setup
|
||||
|
||||
The following are the system requirements to build CakeWallet for your Android device.
|
||||
|
||||
```
|
||||
Ubuntu >= 16.04
|
||||
Android SDK 28
|
||||
Android NDK 17c
|
||||
Flutter 1.22.6
|
||||
```
|
||||
|
||||
## Building CakeWallet on Android
|
||||
|
||||
These steps will help you configure and execute a build of CakeWallet from its source code.
|
||||
|
||||
### 1. Installing Package Dependencies
|
||||
|
||||
CakeWallet cannot be built without the following packages installed on your build system.
|
||||
|
||||
- unzip
|
||||
|
||||
- automake
|
||||
|
||||
- build-essential
|
||||
|
||||
- file
|
||||
|
||||
- pkg-config
|
||||
|
||||
- git
|
||||
|
||||
- python
|
||||
|
||||
- libtool
|
||||
|
||||
- libtinfo5
|
||||
|
||||
- cmake
|
||||
|
||||
- openjdk-8-jre-headless
|
||||
|
||||
You may easily install them on your build sytem with the following command:
|
||||
|
||||
`$ sudo apt-get install -y unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake openjdk-8-jre-headless`
|
||||
|
||||
### 2. Installing Android Studio and Android toolchain
|
||||
|
||||
You may download and install the latest version of Android Studio [here](https://developer.android.com/studio#downloads). After installing, start Android Studio, and go through the "Setup Wizard." This installs the latest Android SDK, Android SDK Command-line Tools, and Android SDK Build-Tools, which are required by CakeWallet. **Be sure you are installing SDK version 28 or later when stepping through the wizard**
|
||||
|
||||
### 3. Installing Flutter
|
||||
|
||||
CakeWallet requires **EXACTLY** Flutter version `1.22.6` to build properly.
|
||||
|
||||
To install this version of Flutter on your Ubuntu system, please use [these instructions](https://flutter.dev/docs/get-started/install/linux#install-flutter-manually).
|
||||
|
||||
### 4. Verify Installations
|
||||
|
||||
Verify that the Android toolchain, Flutter, and Android Studio have been correctly installed on your system with the following command:
|
||||
|
||||
`$ flutter doctor`
|
||||
|
||||
The output of this command will appear like this, indicating successful installations. If there are problems with your installation, they **must** be corrected before proceeding.
|
||||
```
|
||||
Doctor summary (to see all details, run flutter doctor -v):
|
||||
[✓] Flutter (Channel stable, 1.22.6, on Linux, locale en_US.UTF-8)
|
||||
[✓] Android toolchain - develop for Android devices (Android SDK version 28)
|
||||
[✓] Android Studio (version 4.0)
|
||||
```
|
||||
|
||||
### 5. Generate a secure keystore for Android
|
||||
|
||||
`$ keytool -genkey -v -keystore $HOME/key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias key`
|
||||
|
||||
You will be prompted to create two passwords. First you will be prompted for the "store password", followed by a "key password" towards the end of the creation process. **TAKE NOTE OF THESE PASSWORDS!** You will need them in later steps.
|
||||
|
||||
### 6. Acquiring the CakeWallet Source Code
|
||||
|
||||
Create the directory that will be use to store the CakeWallet source...
|
||||
|
||||
```
|
||||
$ sudo mkdir -p /opt/android
|
||||
$ sudo chown $USER /opt/android
|
||||
$ cd /opt/android
|
||||
```
|
||||
|
||||
..and download the source code into that directory.
|
||||
|
||||
`$ git clone https://github.com/cake-tech/cake_wallet.git --branch deploy`
|
||||
|
||||
Proceed into the source code before proceeding with the next steps:
|
||||
|
||||
`$ cd cake_wallet/scripts/android/`
|
||||
|
||||
### 7. Installing Android NDK
|
||||
|
||||
`$ ./install_ndk.sh`
|
||||
|
||||
### 8. Execute Build & Setup Commands for CakeWallet
|
||||
|
||||
Build the Monero libraries and their dependencies:
|
||||
|
||||
`$ ./build_all.sh`
|
||||
|
||||
Now the dependencies need to be copied into the CakeWallet project with this command:
|
||||
|
||||
`$ ./copy_monero_deps.sh`
|
||||
|
||||
It is now time to change back to the base directory of the CakeWallet source code:
|
||||
|
||||
`$ cd ../../`
|
||||
|
||||
Install Flutter package dependencies with this command:
|
||||
|
||||
`$ flutter pub get`
|
||||
|
||||
Your CakeWallet binary will be built with cryptographic salts, which are used for secure encryption of your data. You may generate these secret salts with the following command:
|
||||
|
||||
`$ flutter packages pub run tool/generate_new_secrets.dart`
|
||||
|
||||
Next, we must generate key properties based on the secure keystore you generated for Android (in step 5). **MODIFY THE FOLLOWING COMMAND** with the "store password" and "key password" you assigned when creating your keystore (in step 5).
|
||||
|
||||
`$ flutter packages pub run tool/generate_android_key_properties.dart keyAlias=key storeFile=$HOME/key.jks storePassword=<store password> keyPassword=<key password>`
|
||||
|
||||
**REMINDER:** The *above* command will **not** succeed unless you replaced the `storePassword` and `keyPassword` variables with the correct passwords for your keystore.
|
||||
|
||||
Lastly, we will generate mobx models for the project.
|
||||
|
||||
`$ flutter packages pub run build_runner build --delete-conflicting-outputs`
|
||||
|
||||
### 9. Build!
|
||||
|
||||
`$ flutter build apk —release`
|
||||
|
||||
Copyright (c) 2021 Cake Technologies LLC.
|
|
@ -86,6 +86,8 @@ PODS:
|
|||
- SwiftyGif (5.3.0)
|
||||
- url_launcher (0.0.1):
|
||||
- Flutter
|
||||
- webview_flutter (0.0.1):
|
||||
- Flutter
|
||||
|
||||
DEPENDENCIES:
|
||||
- barcode_scan (from `.symlinks/plugins/barcode_scan/ios`)
|
||||
|
@ -104,6 +106,7 @@ DEPENDENCIES:
|
|||
- share (from `.symlinks/plugins/share/ios`)
|
||||
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
|
||||
- url_launcher (from `.symlinks/plugins/url_launcher/ios`)
|
||||
- webview_flutter (from `.symlinks/plugins/webview_flutter/ios`)
|
||||
|
||||
SPEC REPOS:
|
||||
https://github.com/CocoaPods/Specs.git:
|
||||
|
@ -147,6 +150,8 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/shared_preferences/ios"
|
||||
url_launcher:
|
||||
:path: ".symlinks/plugins/url_launcher/ios"
|
||||
webview_flutter:
|
||||
:path: ".symlinks/plugins/webview_flutter/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
barcode_scan: a5c27959edfafaa0c771905bad0b29d6d39e4479
|
||||
|
@ -172,6 +177,7 @@ SPEC CHECKSUMS:
|
|||
SwiftProtobuf: 4ef85479c18ca85b5482b343df9c319c62bda699
|
||||
SwiftyGif: e466e86c660d343357ab944a819a101c4127cb40
|
||||
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
|
||||
webview_flutter: d2b4d6c66968ad042ad94cbb791f5b72b4678a96
|
||||
|
||||
PODFILE CHECKSUM: 5b5f101b119a1b6eb857c967d462832a9062dec4
|
||||
|
||||
|
|
|
@ -357,7 +357,7 @@
|
|||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 26;
|
||||
CURRENT_PROJECT_VERSION = 30;
|
||||
DEVELOPMENT_TEAM = 32J6BB6VUS;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
|
@ -374,7 +374,7 @@
|
|||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
MARKETING_VERSION = 4.1.2;
|
||||
MARKETING_VERSION = 4.1.3;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.fotolockr.cakewallet;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
|
@ -498,7 +498,7 @@
|
|||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 26;
|
||||
CURRENT_PROJECT_VERSION = 30;
|
||||
DEVELOPMENT_TEAM = 32J6BB6VUS;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
|
@ -515,7 +515,7 @@
|
|||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
MARKETING_VERSION = 4.1.2;
|
||||
MARKETING_VERSION = 4.1.3;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.fotolockr.cakewallet;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
|
@ -533,7 +533,7 @@
|
|||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 26;
|
||||
CURRENT_PROJECT_VERSION = 30;
|
||||
DEVELOPMENT_TEAM = 32J6BB6VUS;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
|
@ -550,7 +550,7 @@
|
|||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
MARKETING_VERSION = 4.1.2;
|
||||
MARKETING_VERSION = 4.1.3;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.fotolockr.cakewallet;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
|
|
51
lib/di.dart
51
lib/di.dart
|
@ -4,8 +4,10 @@ import 'package:cake_wallet/core/wallet_service.dart';
|
|||
import 'package:cake_wallet/entities/biometric_auth.dart';
|
||||
import 'package:cake_wallet/entities/contact_record.dart';
|
||||
import 'package:cake_wallet/entities/load_current_wallet.dart';
|
||||
import 'package:cake_wallet/entities/order.dart';
|
||||
import 'package:cake_wallet/entities/transaction_description.dart';
|
||||
import 'package:cake_wallet/entities/transaction_info.dart';
|
||||
import 'package:cake_wallet/entities/wyre_service.dart';
|
||||
import 'package:cake_wallet/monero/monero_wallet_service.dart';
|
||||
import 'package:cake_wallet/entities/contact.dart';
|
||||
import 'package:cake_wallet/entities/node.dart';
|
||||
|
@ -22,6 +24,7 @@ import 'package:cake_wallet/src/screens/faq/faq_page.dart';
|
|||
import 'package:cake_wallet/src/screens/new_wallet/new_wallet_type_page.dart';
|
||||
import 'package:cake_wallet/src/screens/nodes/node_create_or_edit_page.dart';
|
||||
import 'package:cake_wallet/src/screens/nodes/nodes_list_page.dart';
|
||||
import 'package:cake_wallet/src/screens/order_details/order_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/rescan/rescan_page.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/restore_from_backup_page.dart';
|
||||
|
@ -39,6 +42,8 @@ import 'package:cake_wallet/src/screens/transaction_details/transaction_details_
|
|||
import 'package:cake_wallet/src/screens/wallet_keys/wallet_keys_page.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/exchange_page.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/exchange_template_page.dart';
|
||||
import 'package:cake_wallet/src/screens/wyre/wyre_page.dart';
|
||||
import 'package:cake_wallet/store/dashboard/orders_store.dart';
|
||||
import 'package:cake_wallet/store/node_list_store.dart';
|
||||
import 'package:cake_wallet/store/secret_store.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
|
@ -63,6 +68,7 @@ import 'package:cake_wallet/view_model/exchange/exchange_trade_view_model.dart';
|
|||
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/node_list/node_list_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/order_details_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/rescan_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/restore_from_backup_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/setup_pin_code_view_model.dart';
|
||||
|
@ -83,6 +89,7 @@ import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
|
|||
import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_seed_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/exchange/exchange_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wyre_view_model.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
|
@ -104,6 +111,7 @@ import 'package:cake_wallet/store/templates/send_template_store.dart';
|
|||
import 'package:cake_wallet/store/templates/exchange_template_store.dart';
|
||||
import 'package:cake_wallet/entities/template.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_template.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
|
||||
final getIt = GetIt.instance;
|
||||
|
||||
|
@ -115,6 +123,7 @@ Box<Trade> _tradesSource;
|
|||
Box<Template> _templates;
|
||||
Box<ExchangeTemplate> _exchangeTemplates;
|
||||
Box<TransactionDescription> _transactionDescriptionBox;
|
||||
Box<Order> _ordersSource;
|
||||
|
||||
Future setup(
|
||||
{Box<WalletInfo> walletInfoSource,
|
||||
|
@ -123,7 +132,8 @@ Future setup(
|
|||
Box<Trade> tradesSource,
|
||||
Box<Template> templates,
|
||||
Box<ExchangeTemplate> exchangeTemplates,
|
||||
Box<TransactionDescription> transactionDescriptionBox}) async {
|
||||
Box<TransactionDescription> transactionDescriptionBox,
|
||||
Box<Order> ordersSource}) async {
|
||||
_walletInfoSource = walletInfoSource;
|
||||
_nodeSource = nodeSource;
|
||||
_contactSource = contactSource;
|
||||
|
@ -131,13 +141,18 @@ Future setup(
|
|||
_templates = templates;
|
||||
_exchangeTemplates = exchangeTemplates;
|
||||
_transactionDescriptionBox = transactionDescriptionBox;
|
||||
_ordersSource = ordersSource;
|
||||
|
||||
if (!_isSetupFinished) {
|
||||
getIt.registerSingletonAsync<SharedPreferences>(
|
||||
() => SharedPreferences.getInstance());
|
||||
}
|
||||
|
||||
final settingsStore = await SettingsStoreBase.load(nodeSource: _nodeSource);
|
||||
final isBitcoinBuyEnabled = (secrets.wyreSecretKey?.isNotEmpty ?? false) &&
|
||||
(secrets.wyreApiKey?.isNotEmpty ?? false) &&
|
||||
(secrets.wyreAccountId?.isNotEmpty ?? false);
|
||||
final settingsStore = await SettingsStoreBase.load(
|
||||
nodeSource: _nodeSource, isBitcoinBuyEnabled: isBitcoinBuyEnabled);
|
||||
|
||||
if (_isSetupFinished) {
|
||||
return;
|
||||
|
@ -157,6 +172,8 @@ Future setup(
|
|||
nodeListStore: getIt.get<NodeListStore>()));
|
||||
getIt.registerSingleton<TradesStore>(TradesStore(
|
||||
tradesSource: _tradesSource, settingsStore: getIt.get<SettingsStore>()));
|
||||
getIt.registerSingleton<OrdersStore>(OrdersStore(
|
||||
ordersSource: _ordersSource, settingsStore: getIt.get<SettingsStore>()));
|
||||
getIt.registerSingleton<TradeFilterStore>(TradeFilterStore());
|
||||
getIt.registerSingleton<TransactionFilterStore>(TransactionFilterStore());
|
||||
getIt.registerSingleton<FiatConversionStore>(FiatConversionStore());
|
||||
|
@ -219,7 +236,11 @@ Future setup(
|
|||
appStore: getIt.get<AppStore>(),
|
||||
tradesStore: getIt.get<TradesStore>(),
|
||||
tradeFilterStore: getIt.get<TradeFilterStore>(),
|
||||
transactionFilterStore: getIt.get<TransactionFilterStore>()));
|
||||
transactionFilterStore: getIt.get<TransactionFilterStore>(),
|
||||
settingsStore: settingsStore,
|
||||
ordersSource: _ordersSource,
|
||||
ordersStore: getIt.get<OrdersStore>(),
|
||||
wyreViewModel: getIt.get<WyreViewModel>()));
|
||||
|
||||
getIt.registerFactory<AuthService>(() => AuthService(
|
||||
secureStorage: getIt.get<FlutterSecureStorage>(),
|
||||
|
@ -511,6 +532,30 @@ Future setup(
|
|||
getIt.registerFactoryParam<TradeDetailsPage, Trade, void>((Trade trade, _) =>
|
||||
TradeDetailsPage(getIt.get<TradeDetailsViewModel>(param1: trade)));
|
||||
|
||||
getIt.registerFactory(() {
|
||||
final wallet = getIt.get<AppStore>().wallet;
|
||||
return WyreService(walletType: wallet.type, walletAddress: wallet.address);
|
||||
});
|
||||
|
||||
getIt.registerFactory(() {
|
||||
final wallet = getIt.get<AppStore>().wallet;
|
||||
return WyreViewModel(ordersSource, getIt.get<OrdersStore>(),
|
||||
walletId: wallet.id, address: wallet.address, type: wallet.type,
|
||||
wyreService: getIt.get<WyreService>());
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<WyrePage, String, void>((String url, _) =>
|
||||
WyrePage(getIt.get<WyreViewModel>(),
|
||||
ordersStore: getIt.get<OrdersStore>(), url: url));
|
||||
|
||||
getIt.registerFactoryParam<OrderDetailsViewModel, Order, void>(
|
||||
(order, _) => OrderDetailsViewModel(
|
||||
wyreViewModel: getIt.get<WyreViewModel>(),
|
||||
orderForDetails: order));
|
||||
|
||||
getIt.registerFactoryParam<OrderDetailsPage, Order, void>((Order order, _) =>
|
||||
OrderDetailsPage(getIt.get<OrderDetailsViewModel>(param1: order)));
|
||||
|
||||
getIt.registerFactory(() => SupportViewModel());
|
||||
|
||||
getIt.registerFactory(() => SupportPage(getIt.get<SupportViewModel>()));
|
||||
|
|
55
lib/entities/order.dart
Normal file
55
lib/entities/order.dart
Normal file
|
@ -0,0 +1,55 @@
|
|||
import 'package:hive/hive.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/entities/format_amount.dart';
|
||||
|
||||
part 'order.g.dart';
|
||||
|
||||
@HiveType(typeId: Order.typeId)
|
||||
class Order extends HiveObject {
|
||||
Order(
|
||||
{this.id,
|
||||
this.transferId,
|
||||
this.from,
|
||||
this.to,
|
||||
TradeState state,
|
||||
this.createdAt,
|
||||
this.amount,
|
||||
this.receiveAddress,
|
||||
this.walletId})
|
||||
: stateRaw = state?.raw;
|
||||
|
||||
static const typeId = 8;
|
||||
static const boxName = 'Orders';
|
||||
static const boxKey = 'ordersBoxKey';
|
||||
|
||||
@HiveField(0)
|
||||
String id;
|
||||
|
||||
@HiveField(1)
|
||||
String transferId;
|
||||
|
||||
@HiveField(2)
|
||||
String from;
|
||||
|
||||
@HiveField(3)
|
||||
String to;
|
||||
|
||||
@HiveField(4)
|
||||
String stateRaw;
|
||||
|
||||
TradeState get state => TradeState.deserialize(raw: stateRaw);
|
||||
|
||||
@HiveField(5)
|
||||
DateTime createdAt;
|
||||
|
||||
@HiveField(6)
|
||||
String amount;
|
||||
|
||||
@HiveField(7)
|
||||
String receiveAddress;
|
||||
|
||||
@HiveField(8)
|
||||
String walletId;
|
||||
|
||||
String amountFormatted() => formatAmount(amount);
|
||||
}
|
8
lib/entities/wyre_exception.dart
Normal file
8
lib/entities/wyre_exception.dart
Normal file
|
@ -0,0 +1,8 @@
|
|||
class WyreException implements Exception {
|
||||
WyreException(this.description);
|
||||
|
||||
String description;
|
||||
|
||||
@override
|
||||
String toString() => description;
|
||||
}
|
111
lib/entities/wyre_service.dart
Normal file
111
lib/entities/wyre_service.dart
Normal file
|
@ -0,0 +1,111 @@
|
|||
import 'dart:convert';
|
||||
import 'package:cake_wallet/entities/wyre_exception.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cake_wallet/entities/order.dart';
|
||||
import 'package:cake_wallet/entities/wallet_type.dart';
|
||||
|
||||
class WyreService {
|
||||
WyreService({
|
||||
@required this.walletType,
|
||||
@required this.walletAddress,
|
||||
this.isTestEnvironment = false}) {
|
||||
baseApiUrl = isTestEnvironment
|
||||
? _baseTestApiUrl
|
||||
: _baseProductApiUrl;
|
||||
trackUrl = isTestEnvironment
|
||||
? _trackTestUrl
|
||||
: _trackProductUrl;
|
||||
}
|
||||
|
||||
static const _baseTestApiUrl = 'https://api.testwyre.com';
|
||||
static const _baseProductApiUrl = 'https://api.sendwyre.com';
|
||||
static const _trackTestUrl = 'https://dash.testwyre.com/track/';
|
||||
static const _trackProductUrl = 'https://dash.sendwyre.com/track/';
|
||||
static const _ordersSuffix = '/v3/orders';
|
||||
static const _reserveSuffix = '/reserve';
|
||||
static const _timeStampSuffix = '?timestamp=';
|
||||
static const _transferSuffix = '/v2/transfer/';
|
||||
static const _trackSuffix = '/track';
|
||||
|
||||
final bool isTestEnvironment;
|
||||
final WalletType walletType;
|
||||
final String walletAddress;
|
||||
|
||||
String baseApiUrl;
|
||||
String trackUrl;
|
||||
|
||||
Future<String> getWyreUrl() async {
|
||||
final timestamp = DateTime.now().millisecondsSinceEpoch.toString();
|
||||
final url = baseApiUrl + _ordersSuffix + _reserveSuffix +
|
||||
_timeStampSuffix + timestamp;
|
||||
final secretKey = secrets.wyreSecretKey;
|
||||
final accountId = secrets.wyreAccountId;
|
||||
final body = {
|
||||
'destCurrency': walletTypeToCryptoCurrency(walletType).title,
|
||||
'dest': walletTypeToString(walletType).toLowerCase() + ':' + walletAddress,
|
||||
'referrerAccountId': accountId,
|
||||
'lockFields': ['destCurrency', 'dest']
|
||||
};
|
||||
|
||||
final response = await post(url,
|
||||
headers: {
|
||||
'Authorization': 'Bearer $secretKey',
|
||||
'Content-Type': 'application/json',
|
||||
'cache-control': 'no-cache'
|
||||
},
|
||||
body: json.encode(body));
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw WyreException('Url $url is not found!');
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final urlFromResponse = responseJSON['url'] as String;
|
||||
return urlFromResponse;
|
||||
}
|
||||
|
||||
Future<Order> findOrderById(String id) async {
|
||||
final orderUrl = baseApiUrl + _ordersSuffix + '/$id';
|
||||
final orderResponse = await get(orderUrl);
|
||||
|
||||
if (orderResponse.statusCode != 200) {
|
||||
throw WyreException('Order $id is not found!');
|
||||
}
|
||||
|
||||
final orderResponseJSON =
|
||||
json.decode(orderResponse.body) as Map<String, dynamic>;
|
||||
final transferId = orderResponseJSON['transferId'] as String;
|
||||
final from = orderResponseJSON['sourceCurrency'] as String;
|
||||
final to = orderResponseJSON['destCurrency'] as String;
|
||||
final status = orderResponseJSON['status'] as String;
|
||||
final state = TradeState.deserialize(raw: status.toLowerCase());
|
||||
final createdAtRaw = orderResponseJSON['createdAt'] as int;
|
||||
final createdAt =
|
||||
DateTime.fromMillisecondsSinceEpoch(createdAtRaw).toLocal();
|
||||
|
||||
final transferUrl =
|
||||
baseApiUrl + _transferSuffix + transferId + _trackSuffix;
|
||||
final transferResponse = await get(transferUrl);
|
||||
|
||||
if (transferResponse.statusCode != 200) {
|
||||
throw WyreException('Transfer $transferId is not found!');
|
||||
}
|
||||
|
||||
final transferResponseJSON =
|
||||
json.decode(transferResponse.body) as Map<String, dynamic>;
|
||||
final amount = transferResponseJSON['destAmount'] as double;
|
||||
|
||||
return Order(
|
||||
id: id,
|
||||
transferId: transferId,
|
||||
from: from,
|
||||
to: to,
|
||||
state: state,
|
||||
createdAt: createdAt,
|
||||
amount: amount.toString()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
.toList());
|
||||
|
||||
static const apiUri = 'https://changenow.io/api/v1';
|
||||
static const apiKey = secrets.change_now_api_key;
|
||||
static const apiKey = secrets.changeNowApiKey;
|
||||
static const _exchangeAmountUriSufix = '/exchange-amount/';
|
||||
static const _transactionsUriSufix = '/transactions/';
|
||||
static const _minAmountUriSufix = '/min-amount/';
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:cake_wallet/entities/order.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
|
@ -69,11 +70,17 @@ Future<void> main() async {
|
|||
Hive.registerAdapter(ExchangeTemplateAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(Order.typeId)) {
|
||||
Hive.registerAdapter(OrderAdapter());
|
||||
}
|
||||
|
||||
final secureStorage = FlutterSecureStorage();
|
||||
final transactionDescriptionsBoxKey = await getEncryptionKey(
|
||||
secureStorage: secureStorage, forKey: TransactionDescription.boxKey);
|
||||
final tradesBoxKey = await getEncryptionKey(
|
||||
secureStorage: secureStorage, forKey: Trade.boxKey);
|
||||
final ordersBoxKey = await getEncryptionKey(
|
||||
secureStorage: secureStorage, forKey: Order.boxKey);
|
||||
final contacts = await Hive.openBox<Contact>(Contact.boxName);
|
||||
final nodes = await Hive.openBox<Node>(Node.boxName);
|
||||
final transactionDescriptions = await Hive.openBox<TransactionDescription>(
|
||||
|
@ -81,6 +88,8 @@ Future<void> main() async {
|
|||
encryptionKey: transactionDescriptionsBoxKey);
|
||||
final trades =
|
||||
await Hive.openBox<Trade>(Trade.boxName, encryptionKey: tradesBoxKey);
|
||||
final orders =
|
||||
await Hive.openBox<Order>(Order.boxName, encryptionKey: ordersBoxKey);
|
||||
final walletInfoSource = await Hive.openBox<WalletInfo>(WalletInfo.boxName);
|
||||
final templates = await Hive.openBox<Template>(Template.boxName);
|
||||
final exchangeTemplates =
|
||||
|
@ -91,6 +100,7 @@ Future<void> main() async {
|
|||
walletInfoSource: walletInfoSource,
|
||||
contactSource: contacts,
|
||||
tradesSource: trades,
|
||||
ordersSource: orders,
|
||||
// fiatConvertationService: fiatConvertationService,
|
||||
templates: templates,
|
||||
exchangeTemplates: exchangeTemplates,
|
||||
|
@ -118,6 +128,7 @@ Future<void> initialSetup(
|
|||
@required Box<WalletInfo> walletInfoSource,
|
||||
@required Box<Contact> contactSource,
|
||||
@required Box<Trade> tradesSource,
|
||||
@required Box<Order> ordersSource,
|
||||
// @required FiatConvertationService fiatConvertationService,
|
||||
@required Box<Template> templates,
|
||||
@required Box<ExchangeTemplate> exchangeTemplates,
|
||||
|
@ -139,7 +150,8 @@ Future<void> initialSetup(
|
|||
tradesSource: tradesSource,
|
||||
templates: templates,
|
||||
exchangeTemplates: exchangeTemplates,
|
||||
transactionDescriptionBox: transactionDescriptions);
|
||||
transactionDescriptionBox: transactionDescriptions,
|
||||
ordersSource: ordersSource);
|
||||
await bootstrap(navigatorKey);
|
||||
monero_wallet.onStartup();
|
||||
}
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
import 'package:cake_wallet/entities/contact_record.dart';
|
||||
import 'package:cake_wallet/entities/order.dart';
|
||||
import 'package:cake_wallet/entities/transaction_description.dart';
|
||||
import 'package:cake_wallet/src/screens/backup/backup_page.dart';
|
||||
import 'package:cake_wallet/src/screens/backup/edit_backup_password_page.dart';
|
||||
import 'package:cake_wallet/src/screens/order_details/order_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/restore_from_backup_page.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/wallet_restore_page.dart';
|
||||
import 'package:cake_wallet/src/screens/seed/pre_seed_page.dart';
|
||||
import 'package:cake_wallet/src/screens/support/support_page.dart';
|
||||
import 'package:cake_wallet/src/screens/wyre/wyre_page.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
@ -285,6 +288,16 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
builder: (_) =>
|
||||
getIt.get<TradeDetailsPage>(param1: settings.arguments as Trade));
|
||||
|
||||
case Routes.orderDetails:
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) =>
|
||||
getIt.get<OrderDetailsPage>(param1: settings.arguments as Order));
|
||||
|
||||
case Routes.wyre:
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) =>
|
||||
getIt.get<WyrePage>(param1: settings.arguments as String));
|
||||
|
||||
case Routes.restoreWalletFromSeedDetails:
|
||||
final args = settings.arguments as List;
|
||||
final walletRestorationFromSeedVM =
|
||||
|
|
|
@ -52,4 +52,6 @@ class Routes {
|
|||
static const editBackupPassword = '/edit_backup_passowrd';
|
||||
static const restoreFromBackup = '/restore_from_backup';
|
||||
static const support = '/support';
|
||||
static const orderDetails = '/order_details';
|
||||
static const wyre = '/wyre';
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:cake_wallet/entities/wallet_type.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
|
@ -12,7 +13,9 @@ import 'package:cake_wallet/src/screens/dashboard/widgets/address_page.dart';
|
|||
import 'package:cake_wallet/src/screens/dashboard/widgets/transactions_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
|
||||
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
||||
|
||||
class DashboardPage extends BasePage {
|
||||
DashboardPage({
|
||||
|
@ -81,7 +84,7 @@ class DashboardPage extends BasePage {
|
|||
final exchangeImage = Image.asset('assets/images/transfer.png',
|
||||
height: 24.27, width: 22.25,
|
||||
color: Theme.of(context).accentTextTheme.display3.backgroundColor);
|
||||
final receiveImage = Image.asset('assets/images/download.png',
|
||||
final buyImage = Image.asset('assets/images/coins.png',
|
||||
height: 22.24, width: 24,
|
||||
color: Theme.of(context).accentTextTheme.display3.backgroundColor);
|
||||
_setEffects();
|
||||
|
@ -111,7 +114,7 @@ class DashboardPage extends BasePage {
|
|||
)),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 45, right: 45, bottom: 24),
|
||||
child: Row(
|
||||
child: Observer(builder: (_) => Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: <Widget>[
|
||||
ActionButton(
|
||||
|
@ -122,8 +125,41 @@ class DashboardPage extends BasePage {
|
|||
image: exchangeImage,
|
||||
title: S.of(context).exchange,
|
||||
route: Routes.exchange),
|
||||
],
|
||||
if (walletViewModel.type == WalletType.bitcoin) Observer(
|
||||
builder: (_) => Stack(
|
||||
clipBehavior: Clip.none,
|
||||
alignment: Alignment.topCenter,
|
||||
children: [
|
||||
if (walletViewModel.isRunningWebView) Positioned(
|
||||
top: -5,
|
||||
child: SpinKitRing(
|
||||
color: Theme.of(context).buttonColor,
|
||||
lineWidth: 3,
|
||||
size: 70.0,
|
||||
),
|
||||
),
|
||||
ActionButton(
|
||||
image: buyImage,
|
||||
title: S.of(context).buy,
|
||||
onClick: walletViewModel.isRunningWebView
|
||||
? null
|
||||
: () async {
|
||||
try {
|
||||
walletViewModel.isRunningWebView = true;
|
||||
final url =
|
||||
await walletViewModel.wyreViewModel.wyreUrl;
|
||||
await Navigator.of(context)
|
||||
.pushNamed(Routes.wyre, arguments: url);
|
||||
walletViewModel.isRunningWebView = false;
|
||||
} catch(e) {
|
||||
print(e.toString());
|
||||
walletViewModel.isRunningWebView = false;
|
||||
}
|
||||
})
|
||||
],
|
||||
)),
|
||||
],
|
||||
)),
|
||||
)
|
||||
],
|
||||
));
|
||||
|
|
|
@ -4,13 +4,15 @@ class ActionButton extends StatelessWidget {
|
|||
ActionButton(
|
||||
{@required this.image,
|
||||
@required this.title,
|
||||
@required this.route,
|
||||
this.route,
|
||||
this.onClick,
|
||||
this.alignment = Alignment.center});
|
||||
|
||||
final Image image;
|
||||
final String title;
|
||||
final String route;
|
||||
final Alignment alignment;
|
||||
final void Function() onClick;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -23,8 +25,10 @@ class ActionButton extends StatelessWidget {
|
|||
children: <Widget>[
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
if (route.isNotEmpty) {
|
||||
if (route?.isNotEmpty ?? false) {
|
||||
Navigator.of(context, rootNavigator: true).pushNamed(route);
|
||||
} else {
|
||||
onClick?.call();
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
|
|
72
lib/src/screens/dashboard/widgets/order_row.dart
Normal file
72
lib/src/screens/dashboard/widgets/order_row.dart
Normal file
|
@ -0,0 +1,72 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class OrderRow extends StatelessWidget {
|
||||
OrderRow({
|
||||
@required this.onTap,
|
||||
this.from,
|
||||
this.to,
|
||||
this.createdAtFormattedDate,
|
||||
this.formattedAmount});
|
||||
final VoidCallback onTap;
|
||||
final String from;
|
||||
final String to;
|
||||
final String createdAtFormattedDate;
|
||||
final String formattedAmount;
|
||||
final wyreImage =
|
||||
Image.asset('assets/images/wyre-icon.png', width: 36, height: 36);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
padding: EdgeInsets.fromLTRB(24, 8, 24, 8),
|
||||
color: Colors.transparent,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
wyreImage,
|
||||
SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text('$from → $to',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).accentTextTheme.
|
||||
display3.backgroundColor
|
||||
)),
|
||||
formattedAmount != null
|
||||
? Text(formattedAmount + ' ' + to,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).accentTextTheme.
|
||||
display3.backgroundColor
|
||||
))
|
||||
: Container()
|
||||
]),
|
||||
SizedBox(height: 5),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(createdAtFormattedDate,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).textTheme
|
||||
.overline.backgroundColor))
|
||||
])
|
||||
],
|
||||
)
|
||||
)
|
||||
],
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
import 'package:cake_wallet/src/screens/dashboard/widgets/order_row.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/order_list_item.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
@ -75,6 +77,21 @@ class TransactionsPage extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
|
||||
if (item is OrderListItem) {
|
||||
final order = item.order;
|
||||
|
||||
return OrderRow(
|
||||
onTap: () => Navigator.of(context).pushNamed(
|
||||
Routes.orderDetails,
|
||||
arguments: order),
|
||||
from: order.from,
|
||||
to: order.to,
|
||||
createdAtFormattedDate:
|
||||
DateFormat('HH:mm').format(order.createdAt),
|
||||
formattedAmount: item.orderFormattedAmount,
|
||||
);
|
||||
}
|
||||
|
||||
return Container(
|
||||
color: Colors.transparent,
|
||||
height: 1);
|
||||
|
|
47
lib/src/screens/order_details/order_details_page.dart
Normal file
47
lib/src/screens/order_details/order_details_page.dart
Normal file
|
@ -0,0 +1,47 @@
|
|||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:cake_wallet/view_model/order_details_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/standart_list_row.dart';
|
||||
import 'package:cake_wallet/src/screens/trade_details/track_trade_list_item.dart';
|
||||
|
||||
class OrderDetailsPage extends BasePage {
|
||||
OrderDetailsPage(this.orderDetailsViewModel);
|
||||
|
||||
@override
|
||||
String get title => 'Order Details';
|
||||
|
||||
final OrderDetailsViewModel orderDetailsViewModel;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Observer(builder: (_) {
|
||||
return SectionStandardList(
|
||||
sectionCount: 1,
|
||||
itemCounter: (int _) => orderDetailsViewModel.items.length,
|
||||
itemBuilder: (_, __, index) {
|
||||
final item = orderDetailsViewModel.items[index];
|
||||
|
||||
if (item is TrackTradeListItem) {
|
||||
return GestureDetector(
|
||||
onTap: item.onTap,
|
||||
child: StandartListRow(
|
||||
title: '${item.title}', value: '${item.value}'));
|
||||
} else {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Clipboard.setData(ClipboardData(text: '${item.value}'));
|
||||
showBar<void>(context, S.of(context).copied_to_clipboard);
|
||||
},
|
||||
child: StandartListRow(
|
||||
title: '${item.title}', value: '${item.value}'));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
97
lib/src/screens/wyre/wyre_page.dart
Normal file
97
lib/src/screens/wyre/wyre_page.dart
Normal file
|
@ -0,0 +1,97 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/store/dashboard/orders_store.dart';
|
||||
import 'package:cake_wallet/view_model/wyre_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:webview_flutter/webview_flutter.dart';
|
||||
|
||||
class WyrePage extends BasePage {
|
||||
WyrePage(this.wyreViewModel,
|
||||
{@required this.ordersStore, @required this.url});
|
||||
|
||||
final OrdersStore ordersStore;
|
||||
final String url;
|
||||
final WyreViewModel wyreViewModel;
|
||||
|
||||
@override
|
||||
String get title => S.current.buy;
|
||||
|
||||
@override
|
||||
Color get backgroundDarkColor => Colors.white;
|
||||
|
||||
@override
|
||||
Color get titleColor => Palette.darkBlueCraiola;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) =>
|
||||
WyrePageBody(wyreViewModel, ordersStore: ordersStore, url: url);
|
||||
}
|
||||
|
||||
class WyrePageBody extends StatefulWidget {
|
||||
WyrePageBody(this.wyreViewModel, {this.ordersStore, this.url});
|
||||
|
||||
final OrdersStore ordersStore;
|
||||
final String url;
|
||||
final WyreViewModel wyreViewModel;
|
||||
|
||||
@override
|
||||
WyrePageBodyState createState() => WyrePageBodyState();
|
||||
}
|
||||
|
||||
class WyrePageBodyState extends State<WyrePageBody> {
|
||||
String orderId;
|
||||
WebViewController _webViewController;
|
||||
GlobalKey _webViewkey;
|
||||
Timer _timer;
|
||||
bool _isSaving;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_webViewkey = GlobalKey();
|
||||
_isSaving = false;
|
||||
widget.ordersStore.orderId = '';
|
||||
|
||||
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
|
||||
|
||||
_timer?.cancel();
|
||||
_timer = Timer.periodic(Duration(seconds: 1), (timer) async {
|
||||
|
||||
try {
|
||||
if (_webViewController == null || _isSaving) {
|
||||
return;
|
||||
}
|
||||
|
||||
final url = await _webViewController.currentUrl();
|
||||
|
||||
if (url.contains('completed')) {
|
||||
final urlParts = url.split('/');
|
||||
orderId = urlParts.last;
|
||||
widget.ordersStore.orderId = orderId;
|
||||
|
||||
if (orderId.isNotEmpty) {
|
||||
_isSaving = true;
|
||||
await widget.wyreViewModel.saveOrder(orderId);
|
||||
timer.cancel();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
_isSaving = false;
|
||||
print(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return WebView(
|
||||
key: _webViewkey,
|
||||
initialUrl: widget.url,
|
||||
javascriptMode: JavascriptMode.unrestricted,
|
||||
onWebViewCreated: (WebViewController controller) =>
|
||||
setState(() => _webViewController = controller));
|
||||
}
|
||||
}
|
45
lib/store/dashboard/orders_store.dart
Normal file
45
lib/store/dashboard/orders_store.dart
Normal file
|
@ -0,0 +1,45 @@
|
|||
import 'dart:async';
|
||||
import 'package:cake_wallet/entities/order.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/order_list_item.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
|
||||
part 'orders_store.g.dart';
|
||||
|
||||
class OrdersStore = OrdersStoreBase with _$OrdersStore;
|
||||
|
||||
abstract class OrdersStoreBase with Store {
|
||||
OrdersStoreBase({this.ordersSource, this.settingsStore}) {
|
||||
orders = <OrderListItem>[];
|
||||
|
||||
orderId = '';
|
||||
|
||||
_onOrdersChanged =
|
||||
ordersSource.watch().listen((_) async => await updateOrderList());
|
||||
|
||||
updateOrderList();
|
||||
}
|
||||
|
||||
Box<Order> ordersSource;
|
||||
StreamSubscription<BoxEvent> _onOrdersChanged;
|
||||
SettingsStore settingsStore;
|
||||
|
||||
@observable
|
||||
List<OrderListItem> orders;
|
||||
|
||||
@observable
|
||||
Order order;
|
||||
|
||||
@observable
|
||||
String orderId;
|
||||
|
||||
@action
|
||||
void setOrder(Order order) => this.order = order;
|
||||
|
||||
@action
|
||||
Future updateOrderList() async => orders =
|
||||
ordersSource.values.map((order) => OrderListItem(
|
||||
order: order,
|
||||
displayMode: settingsStore.balanceDisplayMode)).toList();
|
||||
}
|
|
@ -38,6 +38,7 @@ abstract class SettingsStoreBase with Store {
|
|||
@required Map<WalletType, Node> nodes,
|
||||
@required TransactionPriority initialBitcoinTransactionPriority,
|
||||
@required TransactionPriority initialMoneroTransactionPriority,
|
||||
@required this.isBitcoinBuyEnabled,
|
||||
this.actionlistDisplayMode}) {
|
||||
fiatCurrency = initialFiatCurrency;
|
||||
balanceDisplayMode = initialBalanceDisplayMode;
|
||||
|
@ -144,8 +145,11 @@ abstract class SettingsStoreBase with Store {
|
|||
|
||||
Node getCurrentNode(WalletType walletType) => nodes[walletType];
|
||||
|
||||
bool isBitcoinBuyEnabled;
|
||||
|
||||
static Future<SettingsStore> load(
|
||||
{@required Box<Node> nodeSource,
|
||||
@required bool isBitcoinBuyEnabled,
|
||||
FiatCurrency initialFiatCurrency = FiatCurrency.usd,
|
||||
MoneroTransactionPriority initialMoneroTransactionPriority =
|
||||
MoneroTransactionPriority.slow,
|
||||
|
@ -212,6 +216,7 @@ abstract class SettingsStoreBase with Store {
|
|||
WalletType.bitcoin: bitcoinElectrumServer
|
||||
},
|
||||
appVersion: packageInfo.version,
|
||||
isBitcoinBuyEnabled: isBitcoinBuyEnabled,
|
||||
initialFiatCurrency: currentFiatCurrency,
|
||||
initialBalanceDisplayMode: currentBalanceDisplayMode,
|
||||
initialSaveRecipientAddress: shouldSaveRecipientAddress,
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:cake_wallet/bitcoin/bitcoin_transaction_info.dart';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart';
|
||||
import 'package:cake_wallet/entities/balance.dart';
|
||||
import 'package:cake_wallet/entities/order.dart';
|
||||
import 'package:cake_wallet/entities/transaction_history.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/monero/account.dart';
|
||||
import 'package:cake_wallet/monero/monero_balance.dart';
|
||||
import 'package:cake_wallet/monero/monero_transaction_history.dart';
|
||||
|
@ -13,13 +18,21 @@ import 'package:cake_wallet/entities/transaction_direction.dart';
|
|||
import 'package:cake_wallet/entities/transaction_info.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/store/dashboard/orders_store.dart';
|
||||
import 'package:cake_wallet/utils/mobx.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/filter_item.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/order_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/action_list_display_mode.dart';
|
||||
import 'package:cake_wallet/view_model/wyre_view_model.dart';
|
||||
import 'package:crypto/crypto.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/core/wallet_base.dart';
|
||||
import 'package:cake_wallet/entities/sync_status.dart';
|
||||
|
@ -30,6 +43,8 @@ import 'package:cake_wallet/store/dashboard/trades_store.dart';
|
|||
import 'package:cake_wallet/store/dashboard/trade_filter_store.dart';
|
||||
import 'package:cake_wallet/store/dashboard/transaction_filter_store.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/formatted_item_list.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:convert/convert.dart';
|
||||
|
||||
part 'dashboard_view_model.g.dart';
|
||||
|
||||
|
@ -41,7 +56,11 @@ abstract class DashboardViewModelBase with Store {
|
|||
this.appStore,
|
||||
this.tradesStore,
|
||||
this.tradeFilterStore,
|
||||
this.transactionFilterStore}) {
|
||||
this.transactionFilterStore,
|
||||
this.settingsStore,
|
||||
this.ordersSource,
|
||||
this.ordersStore,
|
||||
this.wyreViewModel}) {
|
||||
filterItems = {
|
||||
S.current.transactions: [
|
||||
FilterItem(
|
||||
|
@ -76,6 +95,8 @@ abstract class DashboardViewModelBase with Store {
|
|||
]
|
||||
};
|
||||
|
||||
isRunningWebView = false;
|
||||
|
||||
name = appStore.wallet?.name;
|
||||
wallet ??= appStore.wallet;
|
||||
type = wallet.type;
|
||||
|
@ -141,6 +162,9 @@ abstract class DashboardViewModelBase with Store {
|
|||
@observable
|
||||
String subname;
|
||||
|
||||
@observable
|
||||
bool isRunningWebView;
|
||||
|
||||
@computed
|
||||
String get address => wallet.address;
|
||||
|
||||
|
@ -171,6 +195,11 @@ abstract class DashboardViewModelBase with Store {
|
|||
.where((trade) => trade.trade.walletId == wallet.id)
|
||||
.toList();
|
||||
|
||||
@computed
|
||||
List<OrderListItem> get orders => ordersStore.orders
|
||||
.where((item) => item.order.walletId == wallet.id)
|
||||
.toList();
|
||||
|
||||
@computed
|
||||
double get price => balanceViewModel.price;
|
||||
|
||||
|
@ -180,6 +209,7 @@ abstract class DashboardViewModelBase with Store {
|
|||
|
||||
_items.addAll(transactionFilterStore.filtered(transactions: transactions));
|
||||
_items.addAll(tradeFilterStore.filtered(trades: trades, wallet: wallet));
|
||||
_items.addAll(orders);
|
||||
|
||||
return formattedItemsList(_items);
|
||||
}
|
||||
|
@ -189,18 +219,28 @@ abstract class DashboardViewModelBase with Store {
|
|||
|
||||
bool get hasRescan => wallet.type == WalletType.monero;
|
||||
|
||||
Box<Order> ordersSource;
|
||||
|
||||
BalanceViewModel balanceViewModel;
|
||||
|
||||
AppStore appStore;
|
||||
|
||||
SettingsStore settingsStore;
|
||||
|
||||
TradesStore tradesStore;
|
||||
|
||||
OrdersStore ordersStore;
|
||||
|
||||
TradeFilterStore tradeFilterStore;
|
||||
|
||||
TransactionFilterStore transactionFilterStore;
|
||||
|
||||
WyreViewModel wyreViewModel;
|
||||
|
||||
Map<String, List<FilterItem>> filterItems;
|
||||
|
||||
bool get isBuyEnabled => settingsStore.isBitcoinBuyEnabled;
|
||||
|
||||
ReactionDisposer _reaction;
|
||||
|
||||
ReactionDisposer _onMoneroAccountChangeReaction;
|
||||
|
@ -279,4 +319,6 @@ abstract class DashboardViewModelBase with Store {
|
|||
balanceViewModel: balanceViewModel,
|
||||
settingsStore: appStore.settingsStore)));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
21
lib/view_model/dashboard/order_list_item.dart
Normal file
21
lib/view_model/dashboard/order_list_item.dart
Normal file
|
@ -0,0 +1,21 @@
|
|||
import 'package:cake_wallet/entities/order.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
|
||||
import 'package:cake_wallet/entities/balance_display_mode.dart';
|
||||
|
||||
class OrderListItem extends ActionListItem {
|
||||
OrderListItem({this.order, this.displayMode});
|
||||
|
||||
final Order order;
|
||||
final BalanceDisplayMode displayMode;
|
||||
|
||||
String get orderFormattedAmount {
|
||||
return order.amount != null
|
||||
? displayMode == BalanceDisplayMode.hiddenBalance
|
||||
? '---'
|
||||
: order.amountFormatted()
|
||||
: order.amount;
|
||||
}
|
||||
|
||||
@override
|
||||
DateTime get date => order.createdAt;
|
||||
}
|
85
lib/view_model/order_details_view_model.dart
Normal file
85
lib/view_model/order_details_view_model.dart
Normal file
|
@ -0,0 +1,85 @@
|
|||
import 'dart:async';
|
||||
import 'package:cake_wallet/entities/order.dart';
|
||||
import 'package:cake_wallet/utils/date_formatter.dart';
|
||||
import 'package:cake_wallet/view_model/wyre_view_model.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
|
||||
import 'package:cake_wallet/src/screens/trade_details/track_trade_list_item.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
part 'order_details_view_model.g.dart';
|
||||
|
||||
class OrderDetailsViewModel = OrderDetailsViewModelBase
|
||||
with _$OrderDetailsViewModel;
|
||||
|
||||
abstract class OrderDetailsViewModelBase with Store {
|
||||
OrderDetailsViewModelBase({this.wyreViewModel, Order orderForDetails}) {
|
||||
order = orderForDetails;
|
||||
|
||||
items = ObservableList<StandartListItem>();
|
||||
|
||||
_updateItems();
|
||||
|
||||
_updateOrder();
|
||||
|
||||
_timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateOrder());
|
||||
}
|
||||
|
||||
@observable
|
||||
Order order;
|
||||
|
||||
@observable
|
||||
ObservableList<StandartListItem> items;
|
||||
|
||||
WyreViewModel wyreViewModel;
|
||||
|
||||
Timer _timer;
|
||||
|
||||
@action
|
||||
Future<void> _updateOrder() async {
|
||||
try {
|
||||
final updatedOrder =
|
||||
await wyreViewModel.wyreService.findOrderById(order.id);
|
||||
|
||||
updatedOrder.receiveAddress = order.receiveAddress;
|
||||
updatedOrder.walletId = order.walletId;
|
||||
order = updatedOrder;
|
||||
|
||||
_updateItems();
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
void _updateItems() {
|
||||
final dateFormat = DateFormatter.withCurrentLocal();
|
||||
final buildURL =
|
||||
wyreViewModel.trackUrl + '${order.transferId}';
|
||||
|
||||
items?.clear();
|
||||
|
||||
items.addAll([
|
||||
StandartListItem(
|
||||
title: 'Transfer ID',
|
||||
value: order.transferId),
|
||||
StandartListItem(
|
||||
title: S.current.trade_details_state,
|
||||
value: order.state != null
|
||||
? order.state.toString()
|
||||
: S.current.trade_details_fetching),
|
||||
TrackTradeListItem(
|
||||
title: 'Track',
|
||||
value: buildURL,
|
||||
onTap: () {
|
||||
launch(buildURL);
|
||||
}),
|
||||
StandartListItem(
|
||||
title: S.current.trade_details_created_at,
|
||||
value: dateFormat.format(order.createdAt).toString()),
|
||||
StandartListItem(
|
||||
title: S.current.trade_details_pair,
|
||||
value: '${order.from} → ${order.to}')
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -188,6 +188,8 @@ abstract class SettingsViewModelBase with Store {
|
|||
@computed
|
||||
ThemeBase get theme => _settingsStore.currentTheme;
|
||||
|
||||
bool get isBitcoinBuyEnabled => _settingsStore.isBitcoinBuyEnabled;
|
||||
|
||||
final Map<String, String> itemHeaders;
|
||||
List<List<SettingsListItem>> sections;
|
||||
final SettingsStore _settingsStore;
|
||||
|
|
42
lib/view_model/wyre_view_model.dart
Normal file
42
lib/view_model/wyre_view_model.dart
Normal file
|
@ -0,0 +1,42 @@
|
|||
import 'package:cake_wallet/entities/wyre_service.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:cake_wallet/entities/order.dart';
|
||||
import 'package:cake_wallet/entities/wallet_type.dart';
|
||||
import 'package:cake_wallet/store/dashboard/orders_store.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
part 'wyre_view_model.g.dart';
|
||||
|
||||
class WyreViewModel = WyreViewModelBase with _$WyreViewModel;
|
||||
|
||||
abstract class WyreViewModelBase with Store {
|
||||
WyreViewModelBase(this.ordersSource, this.ordersStore,
|
||||
{@required this.walletId, @required this.address, @required this.type,
|
||||
@required this.wyreService});
|
||||
|
||||
Future<String> get wyreUrl => wyreService.getWyreUrl();
|
||||
|
||||
String get trackUrl => wyreService.trackUrl;
|
||||
|
||||
final Box<Order> ordersSource;
|
||||
final OrdersStore ordersStore;
|
||||
|
||||
final String walletId;
|
||||
final WalletType type;
|
||||
final String address;
|
||||
|
||||
final WyreService wyreService;
|
||||
|
||||
Future<void> saveOrder(String orderId) async {
|
||||
try {
|
||||
final order = await wyreService.findOrderById(orderId);
|
||||
order.receiveAddress = address;
|
||||
order.walletId = walletId;
|
||||
await ordersSource.add(order);
|
||||
ordersStore.setOrder(order);
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
14
pubspec.lock
14
pubspec.lock
|
@ -426,6 +426,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.5.7"
|
||||
flutter_spinkit:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_spinkit
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.1.2+1"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
|
@ -1029,6 +1036,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
webview_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: webview_flutter
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.7"
|
||||
win32:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -11,7 +11,7 @@ description: Cake Wallet.
|
|||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
version: 4.1.2+41
|
||||
version: 4.1.3+42
|
||||
|
||||
environment:
|
||||
sdk: ">=2.7.0 <3.0.0"
|
||||
|
@ -55,6 +55,8 @@ dependencies:
|
|||
auto_size_text: ^2.1.0
|
||||
dotted_border: ^1.0.5
|
||||
smooth_page_indicator: ^0.2.0
|
||||
webview_flutter: ^1.0.7
|
||||
flutter_spinkit: ^4.1.2
|
||||
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
# Use with the CupertinoIcons class for iOS style icons.
|
||||
|
@ -112,7 +114,7 @@ flutter:
|
|||
fonts:
|
||||
- asset: assets/fonts/Lato-Regular.ttf
|
||||
- asset: assets/fonts/Lato-Medium.ttf
|
||||
- asset: assets/fonts/Lato-SemiBold.ttf
|
||||
- asset: assets/fonts/Lato-Semibold.ttf
|
||||
- asset: assets/fonts/Lato-Bold.ttf
|
||||
|
||||
|
||||
|
|
8
scripts/android/build_all.sh
Executable file
8
scripts/android/build_all.sh
Executable file
|
@ -0,0 +1,8 @@
|
|||
# /bin/bash
|
||||
|
||||
./build_iconv.sh
|
||||
./build_boost.sh
|
||||
./build_openssl.sh
|
||||
./build_sodium.sh
|
||||
./build_zmq.sh
|
||||
./build_monero.sh
|
16
scripts/android/build_boost.sh
Executable file
16
scripts/android/build_boost.sh
Executable file
|
@ -0,0 +1,16 @@
|
|||
# /bin/bash
|
||||
|
||||
WORKDIR=/opt/android
|
||||
TOOLCHAIN_BASE_DIR=${WORKDIR}/toolchain
|
||||
ORIGINAL_PATH=$PATH
|
||||
|
||||
for arch in "aarch" "aarch64" "i686" "x86_64"
|
||||
do
|
||||
|
||||
PREFIX=$WORKDIR/prefix_${arch}
|
||||
PATH="${TOOLCHAIN_BASE_DIR}_${arch}/bin:${ORIGINAL_PATH}"
|
||||
|
||||
./init_boost.sh $arch
|
||||
./finish_boost.sh $arch
|
||||
|
||||
done
|
38
scripts/android/build_iconv.sh
Executable file
38
scripts/android/build_iconv.sh
Executable file
|
@ -0,0 +1,38 @@
|
|||
# /bin/bash
|
||||
|
||||
export WORKDIR=/opt/android
|
||||
export ICONV_FILENAME=libiconv-1.15.tar.gz
|
||||
export ICONV_FILE_PATH=$WORKDIR/$ICONV_FILENAME
|
||||
export ICONV_SRC_DIR=$WORKDIR/libiconv-1.15
|
||||
|
||||
wget http://ftp.gnu.org/pub/gnu/libiconv/$ICONV_FILENAME -O $ICONV_FILE_PATH
|
||||
|
||||
ORIGINAL_PATH=$PATH
|
||||
TOOLCHAIN_BASE_DIR=${WORKDIR}/toolchain
|
||||
|
||||
for arch in aarch aarch64 i686 x86_64
|
||||
do
|
||||
|
||||
PREFIX=${WORKDIR}/prefix_${arch}
|
||||
PATH="${TOOLCHAIN_BASE_DIR}_${arch}/bin:${ORIGINAL_PATH}"
|
||||
|
||||
case $arch in
|
||||
"aarch" )
|
||||
CLANG=arm-linux-androideabi-clang
|
||||
CXXLANG=arm-linux-androideabi-clang++
|
||||
HOST="arm-linux-android";;
|
||||
* )
|
||||
CLANG=${arch}-linux-android-clang
|
||||
CXXLANG=${arch}-linux-android-clang++
|
||||
HOST="${arch}-linux-android";;
|
||||
esac
|
||||
|
||||
cd $WORKDIR
|
||||
rm -rf $ICONV_SRC_DIR
|
||||
tar -xzf $ICONV_FILE_PATH -C $WORKDIR
|
||||
cd $ICONV_SRC_DIR
|
||||
CC=${CLANG} CXX=${CXXLANG} ./configure --build=x86_64-linux-gnu --host=${HOST} --prefix=${PREFIX} --disable-rpath
|
||||
make
|
||||
make install
|
||||
|
||||
done
|
70
scripts/android/build_monero.sh
Executable file
70
scripts/android/build_monero.sh
Executable file
|
@ -0,0 +1,70 @@
|
|||
# /bin/bash
|
||||
|
||||
WORKDIR=/opt/android
|
||||
TOOLCHAIN_BASE_DIR=${WORKDIR}/toolchain
|
||||
ORIGINAL_PATH=$PATH
|
||||
MONERO_BRANCH=v0.17.1.9-android
|
||||
MONERO_SRC_DIR=${WORKDIR}/monero
|
||||
|
||||
git clone https://github.com/cake-tech/monero.git ${MONERO_SRC_DIR} --branch ${MONERO_BRANCH}
|
||||
cd $MONERO_SRC_DIR
|
||||
git submodule init
|
||||
git submodule update
|
||||
|
||||
for arch in "aarch" "aarch64" "i686" "x86_64"
|
||||
do
|
||||
FLAGS=""
|
||||
PREFIX=${WORKDIR}/prefix_${arch}
|
||||
ANDROID_STANDALONE_TOOLCHAIN_PATH="${TOOLCHAIN_BASE_DIR}_${arch}"
|
||||
PATH="${ANDROID_STANDALONE_TOOLCHAIN_PATH}/bin:${ORIGINAL_PATH}"
|
||||
DEST_LIB_DIR=${PREFIX}/lib/monero
|
||||
DEST_INCLUDE_DIR=${PREFIX}/include
|
||||
export CMAKE_INCLUDE_PATH="${PREFIX}/include"
|
||||
export CMAKE_LIBRARY_PATH="${PREFIX}/lib"
|
||||
|
||||
mkdir -p $DEST_LIB_DIR
|
||||
mkdir -p $DEST_INCLUDE_DIR
|
||||
|
||||
case $arch in
|
||||
"aarch" )
|
||||
CLANG=arm-linux-androideabi-clang
|
||||
CXXLANG=arm-linux-androideabi-clang++
|
||||
BUILD_64=OFF
|
||||
TAG="android-armv7"
|
||||
ARCH="armv7-a"
|
||||
ARCH_ABI="armeabi-v7a"
|
||||
FLAGS="-D CMAKE_ANDROID_ARM_MODE=ON -D NO_AES=true";;
|
||||
"aarch64" )
|
||||
CLANG=aarch64-linux-androideabi-clang
|
||||
CXXLANG=aarch64-linux-androideabi-clang++
|
||||
BUILD_64=ON
|
||||
TAG="android-armv8"
|
||||
ARCH="armv8-a"
|
||||
ARCH_ABI="arm64-v8a";;
|
||||
"i686" )
|
||||
CLANG=i686-linux-androideabi-clang
|
||||
CXXLANG=i686-linux-androideabi-clang++
|
||||
BUILD_64=OFF
|
||||
TAG="android-x86"
|
||||
ARCH="i686"
|
||||
ARCH_ABI="x86";;
|
||||
"x86_64" )
|
||||
CLANG=x86_64-linux-androideabi-clang
|
||||
CXXLANG=x86_64-linux-androideabi-clang++
|
||||
BUILD_64=ON
|
||||
TAG="android-x86_64"
|
||||
ARCH="x86-64"
|
||||
ARCH_ABI="x86_64";;
|
||||
esac
|
||||
|
||||
cd $MONERO_SRC_DIR
|
||||
rm -rf ./build/release
|
||||
mkdir -p ./build/release
|
||||
cd ./build/release
|
||||
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 ../..
|
||||
make wallet_api -j4
|
||||
find . -path ./lib -prune -o -name '*.a' -exec cp '{}' lib \;
|
||||
|
||||
cp -r ./lib/* $DEST_LIB_DIR
|
||||
cp ../../src/wallet/api/wallet2_api.h $DEST_INCLUDE_DIR
|
||||
done
|
44
scripts/android/build_openssl.sh
Executable file
44
scripts/android/build_openssl.sh
Executable file
|
@ -0,0 +1,44 @@
|
|||
# /bin/bash
|
||||
|
||||
WORKDIR=/opt/android
|
||||
OPENSSL_FILENAME=openssl-1.0.2p.tar.gz
|
||||
OPENSSL_FILE_PATH=$WORKDIR/$OPENSSL_FILENAME
|
||||
OPENSSL_SRC_DIR=$WORKDIR/openssl-1.0.2p
|
||||
ZLIB_FILENAME=zlib-1.2.11.tar.gz
|
||||
ZLIB_FILE_PATH=$WORKDIR/$ZLIB_FILENAME
|
||||
ZLIB_SRC_DIR=$WORKDIR/zlib-1.2.11
|
||||
ORIGINAL_PATH=$PATH
|
||||
TOOLCHAIN_BASE_DIR=${WORKDIR}/toolchain
|
||||
|
||||
wget https://zlib.net/$ZLIB_FILENAME -O $ZLIB_FILE_PATH
|
||||
tar -xzf $ZLIB_FILE_PATH -C $WORKDIR
|
||||
cd $ZLIB_SRC_DIR
|
||||
CC=clang CXX=clang++ ./configure --static
|
||||
make
|
||||
|
||||
wget https://www.openssl.org/source/$OPENSSL_FILENAME -O $OPENSSL_FILE_PATH
|
||||
|
||||
for arch in "aarch" "aarch64" "i686" "x86_64"
|
||||
do
|
||||
|
||||
PREFIX=$WORKDIR/prefix_${arch}
|
||||
PATH="${TOOLCHAIN_BASE_DIR}_${arch}/bin:${ORIGINAL_PATH}"
|
||||
|
||||
case $arch in
|
||||
"aarch" ) TARGET="armv7";;
|
||||
* ) TARGET="${arch}";;
|
||||
esac
|
||||
|
||||
cd $WORKDIR
|
||||
rm -rf $OPENSSL_SRC_DIR
|
||||
tar -xzf $OPENSSL_FILE_PATH -C $WORKDIR
|
||||
cd $OPENSSL_SRC_DIR
|
||||
sed -i -e "s/mandroid/target\ ${TARGET}\-linux\-android/" Configure
|
||||
CC=clang CXX=clang++ ./Configure android no-asm no-shared --static --with-zlib-include=${WORKDIR}/zlib --with-zlib-lib=${ZLIB_SRC_DIR} --prefix=${PREFIX} --openssldir=${PREFIX}
|
||||
make
|
||||
make install
|
||||
|
||||
|
||||
done
|
||||
|
||||
|
31
scripts/android/build_sodium.sh
Executable file
31
scripts/android/build_sodium.sh
Executable file
|
@ -0,0 +1,31 @@
|
|||
# /bin/bash
|
||||
|
||||
WORKDIR=/opt/android
|
||||
TOOLCHAIN_BASE_DIR=${WORKDIR}/toolchain
|
||||
SODIUM_SRC_DIR=${WORKDIR}/libsodium
|
||||
SODIUM_BRANCH=1.0.16
|
||||
ORIGINAL_PATH=$PATH
|
||||
|
||||
for arch in "aarch" "aarch64" "i686" "x86_64"
|
||||
do
|
||||
|
||||
PREFIX=$WORKDIR/prefix_${arch}
|
||||
PATH="${TOOLCHAIN_BASE_DIR}_${arch}/bin:${ORIGINAL_PATH}"
|
||||
|
||||
case $arch in
|
||||
"aarch" ) TARGET="arm";;
|
||||
"i686" ) TARGET="x86";;
|
||||
* ) TARGET="${arch}";;
|
||||
esac
|
||||
|
||||
HOST="${TARGET}-linux-android"
|
||||
cd $WORKDIR
|
||||
rm -rf $SODIUM_SRC_DIR
|
||||
git clone https://github.com/jedisct1/libsodium.git $SODIUM_SRC_DIR -b $SODIUM_BRANCH
|
||||
cd $SODIUM_SRC_DIR
|
||||
./autogen.sh
|
||||
CC=clang CXX=clang++ ./configure --prefix=${PREFIX} --host=${HOST} --enable-static --disable-shared
|
||||
make
|
||||
make install
|
||||
|
||||
done
|
34
scripts/android/build_zmq.sh
Executable file
34
scripts/android/build_zmq.sh
Executable file
|
@ -0,0 +1,34 @@
|
|||
# /bin/bash
|
||||
|
||||
WORKDIR=/opt/android
|
||||
TOOLCHAIN_BASE_DIR=${WORKDIR}/toolchain
|
||||
ZMQ_SRC_DIR=$WORKDIR/libzmq
|
||||
ZMQ_BRANCH=master
|
||||
ZMQ_COMMIT_HASH=501d0815bf2b0abb93be8214fc66519918ef6c40
|
||||
ORIGINAL_PATH=$PATH
|
||||
|
||||
|
||||
for arch in "aarch" "aarch64" "i686" "x86_64"
|
||||
do
|
||||
|
||||
PREFIX=$WORKDIR/prefix_${arch}
|
||||
PATH="${TOOLCHAIN_BASE_DIR}_${arch}/bin:${ORIGINAL_PATH}"
|
||||
|
||||
case $arch in
|
||||
"aarch" ) TARGET="arm";;
|
||||
"i686" ) TARGET="x86";;
|
||||
* ) TARGET="${arch}";;
|
||||
esac
|
||||
|
||||
HOST="${TARGET}-linux-android"
|
||||
cd $WORKDIR
|
||||
rm -rf $ZMQ_SRC_DIR
|
||||
git clone https://github.com/zeromq/libzmq.git ${ZMQ_SRC_DIR} -b ${ZMQ_BRANCH}
|
||||
cd $ZMQ_SRC_DIR
|
||||
git checkout ${ZMQ_COMMIT_HASH}
|
||||
./autogen.sh
|
||||
CC=clang CXX=clang++ ./configure --prefix=${PREFIX} --host=${HOST} --enable-static --disable-shared
|
||||
make
|
||||
make install
|
||||
|
||||
done
|
34
scripts/android/copy_monero_deps.sh
Executable file
34
scripts/android/copy_monero_deps.sh
Executable file
|
@ -0,0 +1,34 @@
|
|||
# /bin/bash
|
||||
|
||||
WORKDIR=/opt/android
|
||||
CW_DIR=${WORKDIR}/cake_wallet
|
||||
CW_EXRTERNAL_DIR=${CW_DIR}/cw_monero/ios/External/android
|
||||
|
||||
for arch in "aarch" "aarch64" "i686" "x86_64"
|
||||
do
|
||||
|
||||
PREFIX=${WORKDIR}/prefix_${arch}
|
||||
ABI=""
|
||||
|
||||
case $arch in
|
||||
"aarch" )
|
||||
ABI="armeabi-v7a";;
|
||||
"aarch64" )
|
||||
ABI="arm64-v8a";;
|
||||
"i686" )
|
||||
ABI="x86";;
|
||||
"x86_64" )
|
||||
ABI="x86_64";;
|
||||
esac
|
||||
|
||||
LIB_DIR=${CW_EXRTERNAL_DIR}/${ABI}/lib
|
||||
INCLUDE_DIR=${CW_EXRTERNAL_DIR}/${ABI}/include
|
||||
|
||||
mkdir -p $LIB_DIR
|
||||
mkdir -p $INCLUDE_DIR
|
||||
|
||||
cp -r ${PREFIX}/lib/* $LIB_DIR
|
||||
cp -r ${PREFIX}/include/* $INCLUDE_DIR
|
||||
|
||||
|
||||
done
|
9
scripts/android/finish_boost.sh
Executable file
9
scripts/android/finish_boost.sh
Executable file
|
@ -0,0 +1,9 @@
|
|||
# /bin/bash
|
||||
|
||||
WORKDIR=/opt/android
|
||||
ARCH=$1
|
||||
PREFIX="${WORKDIR}/prefix_${ARCH}"
|
||||
BOOST_SRC_DIR=$WORKDIR/boost_1_68_0
|
||||
|
||||
cd $BOOST_SRC_DIR
|
||||
./b2 --build-type=minimal link=static runtime-link=static --with-chrono --with-date_time --with-filesystem --with-program_options --with-regex --with-serialization --with-system --with-thread --with-locale --build-dir=android --stagedir=android toolset=clang threading=multi threadapi=pthread target-os=android -sICONV_PATH=${PREFIX} install
|
18
scripts/android/init_boost.sh
Executable file
18
scripts/android/init_boost.sh
Executable file
|
@ -0,0 +1,18 @@
|
|||
# /bin/bash
|
||||
|
||||
WORKDIR=/opt/android
|
||||
ARCH=$1
|
||||
PREFIX="${WORKDIR}/prefix_${ARCH}"
|
||||
BOOST_FILENAME=boost_1_68_0.tar.bz2
|
||||
BOOST_FILE_PATH=$WORKDIR/$BOOST_FILENAME
|
||||
BOOST_SRC_DIR=$WORKDIR/boost_1_68_0
|
||||
|
||||
if [ ! -e "$BOOST_FILE_PATH" ]; then
|
||||
wget https://dl.bintray.com/boostorg/release/1.68.0/source/$BOOST_FILENAME -O $BOOST_FILE_PATH
|
||||
fi
|
||||
|
||||
cd $WORKDIR
|
||||
rm -rf $BOOST_SRC_DIR
|
||||
tar -xvf $BOOST_FILE_PATH -C $WORKDIR
|
||||
cd $BOOST_SRC_DIR
|
||||
./bootstrap.sh --prefix=${PREFIX}
|
17
scripts/android/install_ndk.sh
Executable file
17
scripts/android/install_ndk.sh
Executable file
|
@ -0,0 +1,17 @@
|
|||
# /bin/bash
|
||||
|
||||
WORKDIR=/opt/android
|
||||
ANDROID_NDK_ZIP=${WORKDIR}/android-ndk-r17c.zip
|
||||
ANDROID_NDK_ROOT=${WORKDIR}/android-ndk-r17c
|
||||
TOOLCHAIN_DIR=${WORKDIR}/toolchain
|
||||
TOOLCHAIN_A32_DIR=${TOOLCHAIN_DIR}_aarch
|
||||
TOOLCHAIN_A64_DIR=${TOOLCHAIN_DIR}_aarch64
|
||||
TOOLCHAIN_x86_DIR=${TOOLCHAIN_DIR}_i686
|
||||
TOOLCHAIN_x86_64_DIR=${TOOLCHAIN_DIR}_x86_64
|
||||
|
||||
wget https://dl.google.com/android/repository/android-ndk-r17c-linux-x86_64.zip -O /opt/android/android-ndk-r17c.zip
|
||||
unzip /opt/android/android-ndk-r17c.zip -d $WORKDIR
|
||||
${ANDROID_NDK_ROOT}/build/tools/make_standalone_toolchain.py --arch arm64 --api 21 --install-dir ${TOOLCHAIN_A64_DIR} --stl=libc++
|
||||
${ANDROID_NDK_ROOT}/build/tools/make_standalone_toolchain.py --arch arm --api 21 --install-dir ${TOOLCHAIN_A32_DIR} --stl=libc++
|
||||
${ANDROID_NDK_ROOT}/build/tools/make_standalone_toolchain.py --arch x86 --api 21 --install-dir ${TOOLCHAIN_x86_DIR} --stl=libc++
|
||||
${ANDROID_NDK_ROOT}/build/tools/make_standalone_toolchain.py --arch x86_64 --api 21 --install-dir ${TOOLCHAIN_x86_64_DIR} --stl=libc++
|
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"salt": "",
|
||||
"keychainSalt": "",
|
||||
"key": "",
|
||||
"walletSalt": "",
|
||||
"shortKey": "",
|
||||
"change_now_api_key": ""
|
||||
}
|
14
tool/generate_android_key_properties.dart
Normal file
14
tool/generate_android_key_properties.dart
Normal file
|
@ -0,0 +1,14 @@
|
|||
import 'dart:io';
|
||||
|
||||
const outputPath = 'android/key.properties';
|
||||
|
||||
Future<void> main(List<String> args) async {
|
||||
final output = args.fold('', (String acc, String arg) => acc + arg + '\n');
|
||||
final outputFile = File(outputPath);
|
||||
|
||||
if (outputFile.existsSync()) {
|
||||
await outputFile.delete();
|
||||
}
|
||||
|
||||
await outputFile.writeAsString(output);
|
||||
}
|
12
tool/generate_new_secrets.dart
Normal file
12
tool/generate_new_secrets.dart
Normal file
|
@ -0,0 +1,12 @@
|
|||
import 'generate_secrets_config.dart';
|
||||
import 'import_secrets_config.dart';
|
||||
|
||||
const configPath = 'tool/.secrets-config.json';
|
||||
const outputPath = 'lib/.secrets.g.dart';
|
||||
|
||||
Future<void> main(List<String> args) async => generateSecrets(args);
|
||||
|
||||
Future<void> generateSecrets(List<String> args) async {
|
||||
await generateSecretsConfig(args);
|
||||
await importSecretsConfig();
|
||||
}
|
49
tool/generate_secrets_config.dart
Normal file
49
tool/generate_secrets_config.dart
Normal file
|
@ -0,0 +1,49 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'utils/secret_key.dart';
|
||||
import 'utils/utils.dart';
|
||||
|
||||
const configPath = 'tool/.secrets-config.json';
|
||||
|
||||
Future<void> main(List<String> args) async => generateSecretsConfig(args);
|
||||
|
||||
Future<void> generateSecretsConfig(List<String> args) async {
|
||||
final extraInfo =
|
||||
args.fold(<String, dynamic>{}, (Map<String, dynamic> acc, String arg) {
|
||||
final parts = arg.split('=');
|
||||
final key = normalizeKeyName(parts[0]);
|
||||
acc[key] = acc[key] = parts.length > 1 ? parts[1] : 1;
|
||||
return acc;
|
||||
});
|
||||
|
||||
final configFile = File(configPath);
|
||||
final secrets = <String, dynamic>{};
|
||||
|
||||
secrets.addAll(extraInfo);
|
||||
secrets.removeWhere((key, dynamic value) {
|
||||
if (key.contains('--')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if (configFile.existsSync()) {
|
||||
if (extraInfo['--force'] == 1) {
|
||||
await configFile.delete();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SecretKey.base.forEach((sec) {
|
||||
if (secrets[sec.name] != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
secrets[sec.name] = sec.generate();
|
||||
});
|
||||
|
||||
final secretsJson = JsonEncoder.withIndent(' ').convert(secrets);
|
||||
await configFile.writeAsString(secretsJson);
|
||||
}
|
23
tool/import_secrets_config.dart
Normal file
23
tool/import_secrets_config.dart
Normal file
|
@ -0,0 +1,23 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'utils/utils.dart';
|
||||
|
||||
const configPath = 'tool/.secrets-config.json';
|
||||
const outputPath = 'lib/.secrets.g.dart';
|
||||
|
||||
Future<void> main(List<String> args) async => importSecretsConfig();
|
||||
|
||||
Future<void> importSecretsConfig() async {
|
||||
final outputFile = File(outputPath);
|
||||
final input = json.decode(File(configPath).readAsStringSync())
|
||||
as Map<String, dynamic> ??
|
||||
<String, dynamic>{};
|
||||
final output = input.keys
|
||||
.fold('', (String acc, String val) => acc + generateConst(val, input));
|
||||
|
||||
if (outputFile.existsSync()) {
|
||||
await outputFile.delete();
|
||||
}
|
||||
|
||||
await outputFile.writeAsString(output);
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
const secretsProdPath = 'tool/.secrets-prod.json';
|
||||
const secretsTestPath = 'tool/.secrets-test.json';
|
||||
const outputPath = 'lib/.secrets.g.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
final inputPath = FileSystemEntity.typeSync(secretsProdPath) !=
|
||||
FileSystemEntityType.notFound
|
||||
? secretsProdPath
|
||||
: secretsTestPath;
|
||||
|
||||
final inoutContent = File(inputPath).readAsStringSync();
|
||||
final config = json.decode(inoutContent) as Map<String, dynamic>;
|
||||
final output =
|
||||
'const salt = \'${config["salt"]}\';const keychainSalt = \'${config["keychainSalt"]}\';\nconst key = \'${config["key"]}\';\nconst walletSalt = \'${config["walletSalt"]}\';\nconst shortKey = \'${config["shortKey"]}\';\nconst change_now_api_key = \'${config["change_now_api_key"]}\';';
|
||||
|
||||
await File(outputPath).writeAsString(output);
|
||||
}
|
47
tool/update_secrets.dart
Normal file
47
tool/update_secrets.dart
Normal file
|
@ -0,0 +1,47 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'generate_new_secrets.dart';
|
||||
import 'import_secrets_config.dart';
|
||||
import 'utils/utils.dart';
|
||||
|
||||
const configPath = 'tool/.secrets-config.json';
|
||||
|
||||
Future<void> main(List<String> args) async {
|
||||
await updateSecretsConfig(args);
|
||||
await importSecretsConfig();
|
||||
}
|
||||
|
||||
Future<void> updateSecretsConfig(List<String> args) async {
|
||||
final extraInfo =
|
||||
args.fold(<String, dynamic>{}, (Map<String, dynamic> acc, String arg) {
|
||||
final parts = arg.split('=');
|
||||
final key = normalizeKeyName(parts[0]);
|
||||
acc[key] = parts.length > 1 ? parts[1] : 1;
|
||||
return acc;
|
||||
});
|
||||
|
||||
final configFile = File(configPath);
|
||||
final secrets = <String, dynamic>{};
|
||||
|
||||
secrets.addAll(extraInfo);
|
||||
secrets.removeWhere((key, dynamic value) {
|
||||
if (key.contains('--')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
final fileConfig =
|
||||
json.decode(configFile.readAsStringSync()) as Map<String, dynamic> ??
|
||||
<String, dynamic>{};
|
||||
fileConfig.forEach((key, dynamic value) {
|
||||
if (secrets[key] == null) {
|
||||
secrets[key] = value;
|
||||
}
|
||||
});
|
||||
|
||||
final secretsJson = JsonEncoder.withIndent(' ').convert(secrets);
|
||||
await configFile.writeAsString(secretsJson);
|
||||
await generateSecrets(args);
|
||||
}
|
28
tool/utils/secret_key.dart
Normal file
28
tool/utils/secret_key.dart
Normal file
|
@ -0,0 +1,28 @@
|
|||
import 'package:encrypt/encrypt.dart' as encrypt;
|
||||
import 'package:convert/convert.dart';
|
||||
|
||||
class SecretKey {
|
||||
const SecretKey(this.name, this.generate);
|
||||
|
||||
static final base = [
|
||||
SecretKey('salt', () => hex.encode(encrypt.Key.fromSecureRandom(16).bytes)),
|
||||
SecretKey('keychainSalt',
|
||||
() => hex.encode(encrypt.Key.fromSecureRandom(12).bytes)),
|
||||
SecretKey('key', () => hex.encode(encrypt.Key.fromSecureRandom(16).bytes)),
|
||||
SecretKey(
|
||||
'walletSalt', () => hex.encode(encrypt.Key.fromSecureRandom(4).bytes)),
|
||||
SecretKey(
|
||||
'shortKey', () => hex.encode(encrypt.Key.fromSecureRandom(12).bytes)),
|
||||
SecretKey(
|
||||
'backupSalt', () => hex.encode(encrypt.Key.fromSecureRandom(8).bytes)),
|
||||
SecretKey('backupKeychainSalt',
|
||||
() => hex.encode(encrypt.Key.fromSecureRandom(12).bytes)),
|
||||
SecretKey('changeNowApiKey', () => ''),
|
||||
SecretKey('wyreSecretKey', () => ''),
|
||||
SecretKey('wyreApiKey', () => ''),
|
||||
SecretKey('wyreAccountId', () => ''),
|
||||
];
|
||||
|
||||
final String name;
|
||||
final String Function() generate;
|
||||
}
|
13
tool/utils/utils.dart
Normal file
13
tool/utils/utils.dart
Normal file
|
@ -0,0 +1,13 @@
|
|||
import 'package:intl/intl.dart';
|
||||
|
||||
String normalizeKeyName(String key) {
|
||||
final parts = key.split('_');
|
||||
final firstWord = parts.removeAt(0);
|
||||
final capitalized = parts
|
||||
.map((e) => toBeginningOfSentenceCase(e))
|
||||
.fold('', (String acc, String word) => acc + word);
|
||||
return firstWord + capitalized;
|
||||
}
|
||||
|
||||
String generateConst(String name, Map<String, dynamic> config) =>
|
||||
'const $name = \'${config["$name"]}\';\n';
|
Loading…
Reference in a new issue