Compare commits

..
240 changed files with 2107 additions and 2479 deletions
@@ -1,88 +0,0 @@
package im.status.ethereum
import android.util.Log
import com.facebook.react.modules.network.OkHttpClientFactory
import com.facebook.react.modules.network.OkHttpClientProvider
import okhttp3.OkHttpClient
import okhttp3.tls.HandshakeCertificates
import java.io.ByteArrayInputStream
import java.lang.RuntimeException
import java.lang.reflect.Field
import java.lang.reflect.Method
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
import im.status.ethereum.module.StatusPackage
class StatusOkHttpClientFactory : OkHttpClientFactory {
companion object {
private const val TAG = "StatusOkHttpClientFactory"
private const val SLEEP_DURATION = 500L // milliseconds
}
override fun createNewNetworkModuleClient(): OkHttpClient? {
val certPem = getCertificatePem().takeIf { it.isNotEmpty() }
?: return logAndReturnNull("Certificate is empty, cannot create OkHttpClient without a valid certificate")
val cert = try {
induceSleep()
// Convert PEM certificate string to X509Certificate object
CertificateFactory.getInstance("X.509")
.generateCertificate(ByteArrayInputStream(certPem.toByteArray())) as? X509Certificate
?: return logAndReturnNull("Certificate could not be parsed as non-null")
} catch (e: Exception) {
return logAndReturnNull("Could not parse certificate", e)
}
val clientCertificates = try {
induceSleep()
// Create HandshakeCertificates object with our certificate
HandshakeCertificates.Builder()
.addPlatformTrustedCertificates()
.addTrustedCertificate(cert)
.build()
} catch (e: Exception) {
return logAndReturnNull("Could not build HandshakeCertificates", e)
}
return try {
OkHttpClientProvider.createClientBuilder()
.sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager)
.build()
} catch (e: Exception) {
logAndReturnNull("Could not create OkHttpClient", e)
}
}
private fun getCertificatePem(): String {
return try {
// Create OkHttpClient with custom SSL socket factory and trust manager
StatusPackage.getImageTLSCert().takeIf { !it.isNullOrBlank() }
?: logAndReturnEmpty("Certificate PEM string is null or empty")
} catch (e: Exception) {
logAndReturnEmpty("Could not getImageTLSCert", e)
}
}
private fun induceSleep() {
try {
// induce half second sleep because sometimes a cert is not immediately available
// TODO : remove sleep if App no longer crashes on Android 10 devices with
// java.lang.RuntimeException: Could not invoke WebSocketModule.connect
Thread.sleep(SLEEP_DURATION)
} catch (e: InterruptedException) {
Log.e(TAG, "Sleep interrupted", e)
}
}
private fun logAndReturnNull(message: String, e: Exception? = null): Nothing? {
Log.e(TAG, message, e)
return null
}
private fun logAndReturnEmpty(message: String, e: Exception? = null): String {
Log.e(TAG, message, e)
return ""
}
}
@@ -0,0 +1,95 @@
package im.status.ethereum;
import android.util.Log;
import com.facebook.react.modules.network.OkHttpClientFactory;
import com.facebook.react.modules.network.OkHttpClientProvider;
import okhttp3.OkHttpClient;
import okhttp3.Interceptor;
import okhttp3.tls.HandshakeCertificates;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.RuntimeException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import im.status.ethereum.module.StatusPackage;
class StatusOkHttpClientFactory implements OkHttpClientFactory {
private static final String TAG = "StatusOkHttpClientFactory";
public OkHttpClient createNewNetworkModuleClient() {
X509Certificate cert = null;
HandshakeCertificates clientCertificates;
String certPem = "";
// Get TLS PEM certificate from status-go
try {
// induce half second sleep because sometimes a cert is not immediately available
// TODO : remove sleep if App no longer crashes on Android 10 devices with
// java.lang.RuntimeException: Could not invoke WebSocketModule.connect
Thread.sleep(500);
certPem = getCertificatePem();
} catch(Exception e) {
Log.e(TAG, "Could not getImageTLSCert",e);
}
if (certPem.isEmpty()) {
Log.e(TAG, "Certificate is empty, cannot create OkHttpClient without a valid certificate");
return null;
}
// Convert PEM certificate string to X509Certificate object
try {
// induce half second sleep because sometimes a cert is not immediately available
// TODO : remove sleep if App no longer crashes on Android 10 devices
// java.lang.RuntimeException: Could not invoke WebSocketModule.connect
Thread.sleep(500);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
cert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(certPem.getBytes()));
} catch(Exception e) {
Log.e(TAG, "Could not parse certificate",e);
}
// Create HandshakeCertificates object with our certificate
try {
// induce half second sleep because sometimes a cert is not immediately available
// TODO : remove sleep if App no longer crashes on Android 10 devices
// java.lang.RuntimeException: Could not invoke WebSocketModule.connect
Thread.sleep(500);
clientCertificates = new HandshakeCertificates.Builder()
.addPlatformTrustedCertificates()
.addTrustedCertificate(cert)
.build();
} catch(Exception e) {
Log.e(TAG, "Could not build HandshakeCertificates", e);
return null;
}
// Create OkHttpClient with custom SSL socket factory and trust manager
try {
return OkHttpClientProvider.createClientBuilder()
.sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager())
.build();
} catch(Exception e) {
Log.e(TAG, "Could not create OkHttpClient", e);
return null;
}
}
private String getCertificatePem() {
try {
String certPem = StatusPackage.getImageTLSCert();
if (certPem == null || certPem.trim().isEmpty()) {
Log.e(TAG, "Certificate PEM string is null or empty");
return "";
}
return certPem;
} catch (Exception e) {
Log.e(TAG, "Could not getImageTLSCert", e);
return "";
}
}
}
@@ -1,402 +0,0 @@
package im.status.ethereum.module;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import statusgo.Statusgo;
import android.net.Uri;
import android.os.Environment;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import org.json.JSONObject;
import org.json.JSONException;
import android.util.Log;
import android.content.Context;
import android.app.Activity;
public class AccountManager extends ReactContextBaseJavaModule {
private static final String TAG = "AccountManager";
private static final String gethLogFileName = "geth.log";
private ReactApplicationContext reactContext;
private Utils utils;
private LogManager logManager;
public AccountManager(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
this.utils = new Utils(reactContext);
this.logManager = new LogManager(reactContext);
}
@Override
public String getName() {
return "AccountManager";
}
private String getTestnetDataDir(final String absRootDirPath) {
return this.utils.pathCombine(absRootDirPath, "ethereum/testnet");
}
@ReactMethod
public void createAccountAndLogin(final String createAccountRequest) {
Log.d(TAG, "createAccountAndLogin");
String result = Statusgo.createAccountAndLogin(createAccountRequest);
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "createAccountAndLogin success: " + result);
Log.d(TAG, "Geth node started");
} else {
Log.e(TAG, "createAccountAndLogin failed: " + result);
}
}
@ReactMethod
public void restoreAccountAndLogin(final String restoreAccountRequest) {
Log.d(TAG, "restoreAccountAndLogin");
String result = Statusgo.restoreAccountAndLogin(restoreAccountRequest);
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "restoreAccountAndLogin success: " + result);
Log.d(TAG, "Geth node started");
} else {
Log.e(TAG, "restoreAccountAndLogin failed: " + result);
}
}
private String updateConfig(final String jsonConfigString, final String absRootDirPath, final String keystoreDirPath) throws JSONException {
final JSONObject jsonConfig = new JSONObject(jsonConfigString);
// retrieve parameters from app config, that will be applied onto the Go-side config later on
final String dataDirPath = jsonConfig.getString("DataDir");
final Boolean logEnabled = jsonConfig.getBoolean("LogEnabled");
final Context context = this.getReactApplicationContext();
final File gethLogFile = logEnabled ? this.logManager.prepareLogsFile(context) : null;
String gethLogDirPath = null;
if (gethLogFile != null) {
gethLogDirPath = gethLogFile.getParent();
}
Log.d(TAG, "log dir: " + gethLogDirPath + " log name: " + gethLogFileName);
jsonConfig.put("DataDir", dataDirPath);
jsonConfig.put("KeyStoreDir", keystoreDirPath);
jsonConfig.put("LogDir", gethLogDirPath);
jsonConfig.put("LogFile", gethLogFileName);
return jsonConfig.toString();
}
private static void prettyPrintConfig(final String config) {
Log.d(TAG, "startNode() with config (see below)");
String configOutput = config;
final int maxOutputLen = 4000;
Log.d(TAG, "********************** NODE CONFIG ****************************");
while (!configOutput.isEmpty()) {
Log.d(TAG, "Node config:" + configOutput.substring(0, Math.min(maxOutputLen, configOutput.length())));
if (configOutput.length() > maxOutputLen) {
configOutput = configOutput.substring(maxOutputLen);
} else {
break;
}
}
Log.d(TAG, "******************* ENDOF NODE CONFIG *************************");
}
private void copyDirectory(File sourceLocation, File targetLocation) throws IOException {
if (sourceLocation.isDirectory()) {
if (!targetLocation.exists() && !targetLocation.mkdirs()) {
throw new IOException("Cannot create dir " + targetLocation.getAbsolutePath());
}
String[] children = sourceLocation.list();
for (int i = 0; i < children.length; i++) {
copyDirectory(new File(sourceLocation, children[i]), new File(targetLocation, children[i]));
}
} else {
File directory = targetLocation.getParentFile();
if (directory != null && !directory.exists() && !directory.mkdirs()) {
throw new IOException("Cannot create dir " + directory.getAbsolutePath());
}
InputStream in = new FileInputStream(sourceLocation);
OutputStream out = new FileOutputStream(targetLocation);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
}
}
private String prepareDirAndUpdateConfig(final String jsonConfigString, final String keyUID) {
final String absRootDirPath = this.utils.getNoBackupDirectory();
final String dataFolder = this.getTestnetDataDir(absRootDirPath);
Log.d(TAG, "Starting Geth node in folder: " + dataFolder);
try {
final File newFile = new File(dataFolder);
// todo handle error?
newFile.mkdir();
} catch (Exception e) {
Log.e(TAG, "error making folder: " + dataFolder, e);
}
final String ropstenFlagPath = this.utils.pathCombine(absRootDirPath, "ropsten_flag");
final File ropstenFlag = new File(ropstenFlagPath);
if (!ropstenFlag.exists()) {
try {
final String chaindDataFolderPath = this.utils.pathCombine(dataFolder, "StatusIM/lightchaindata");
final File lightChainFolder = new File(chaindDataFolderPath);
if (lightChainFolder.isDirectory()) {
String[] children = lightChainFolder.list();
for (int i = 0; i < children.length; i++) {
new File(lightChainFolder, children[i]).delete();
}
}
lightChainFolder.delete();
ropstenFlag.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
String testnetDataDir = dataFolder;
String oldKeystoreDir = this.utils.pathCombine(testnetDataDir, "keystore");
String newKeystoreDir = this.utils.pathCombine(absRootDirPath, "keystore");
final File oldKeystore = new File(oldKeystoreDir);
if (oldKeystore.exists()) {
try {
final File newKeystore = new File(newKeystoreDir);
copyDirectory(oldKeystore, newKeystore);
if (oldKeystore.isDirectory()) {
String[] children = oldKeystore.list();
for (int i = 0; i < children.length; i++) {
new File(oldKeystoreDir, children[i]).delete();
}
}
oldKeystore.delete();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
final String multiaccountKeystoreDir = this.utils.pathCombine("/keystore", keyUID);
final String updatedJsonConfigString = this.updateConfig(jsonConfigString, absRootDirPath, multiaccountKeystoreDir);
prettyPrintConfig(updatedJsonConfigString);
return updatedJsonConfigString;
} catch (JSONException e) {
Log.e(TAG, "updateConfig failed: " + e.getMessage());
System.exit(1);
return "";
}
}
@ReactMethod
public void prepareDirAndUpdateConfig(final String keyUID, final String config, final Callback callback) {
Log.d(TAG, "prepareDirAndUpdateConfig");
String finalConfig = prepareDirAndUpdateConfig(config, keyUID);
callback.invoke(finalConfig);
}
//TODO : maybe nuke since it is not called anywhere in status-mobile code
@ReactMethod
public void saveAccountAndLogin(final String multiaccountData, final String password, final String settings, final String config, final String accountsData) {
try {
Log.d(TAG, "saveAccountAndLogin");
String finalConfig = prepareDirAndUpdateConfig(config, this.utils.getKeyUID(multiaccountData));
String result = Statusgo.saveAccountAndLogin(multiaccountData, password, settings, finalConfig, accountsData);
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "saveAccountAndLogin result: " + result);
Log.d(TAG, "Geth node started");
} else {
Log.e(TAG, "saveAccountAndLogin failed: " + result);
}
} catch (JSONException e) {
Log.e(TAG, "JSON conversion failed: " + e.getMessage());
}
}
@ReactMethod
public void saveAccountAndLoginWithKeycard(final String multiaccountData, final String password, final String settings, final String config, final String accountsData, final String chatKey) {
try {
Log.d(TAG, "saveAccountAndLoginWithKeycard");
String finalConfig = prepareDirAndUpdateConfig(config, this.utils.getKeyUID(multiaccountData));
String result = Statusgo.saveAccountAndLoginWithKeycard(multiaccountData, password, settings, finalConfig, accountsData, chatKey);
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "saveAccountAndLoginWithKeycard result: " + result);
Log.d(TAG, "Geth node started");
} else {
Log.e(TAG, "saveAccountAndLoginWithKeycard failed: " + result);
}
} catch (JSONException e) {
Log.e(TAG, "JSON conversion failed: " + e.getMessage());
}
}
//TODO : maybe nuke since it is not called anywhere in status-mobile code
@ReactMethod
public void login(final String accountData, final String password) {
Log.d(TAG, "login");
this.utils.migrateKeyStoreDir(accountData, password);
String result = Statusgo.login(accountData, password);
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "Login result: " + result);
} else {
Log.e(TAG, "Login failed: " + result);
}
}
@ReactMethod
public void loginWithKeycard(final String accountData, final String password, final String chatKey, final String nodeConfigJSON) {
Log.d(TAG, "loginWithKeycard");
this.utils.migrateKeyStoreDir(accountData, password);
String result = Statusgo.loginWithKeycard(accountData, password, chatKey, nodeConfigJSON);
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "LoginWithKeycard result: " + result);
} else {
Log.e(TAG, "LoginWithKeycard failed: " + result);
}
}
@ReactMethod
public void loginWithConfig(final String accountData, final String password, final String configJSON) {
Log.d(TAG, "loginWithConfig");
this.utils.migrateKeyStoreDir(accountData, password);
String result = Statusgo.loginWithConfig(accountData, password, configJSON);
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "LoginWithConfig result: " + result);
} else {
Log.e(TAG, "LoginWithConfig failed: " + result);
}
}
@ReactMethod
public void loginAccount(final String request) {
Log.d(TAG, "loginAccount");
String result = Statusgo.loginAccount(request);
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "loginAccount result: " + result);
} else {
Log.e(TAG, "loginAccount failed: " + result);
}
}
@ReactMethod
public void verify(final String address, final String password, final Callback callback) throws JSONException {
Activity currentActivity = getCurrentActivity();
final String absRootDirPath = this.utils.getNoBackupDirectory();
final String newKeystoreDir = this.utils.pathCombine(absRootDirPath, "keystore");
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.verifyAccountPassword(newKeystoreDir, address, password), callback);
}
@ReactMethod
public void verifyDatabasePassword(final String keyUID, final String password, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.verifyDatabasePassword(keyUID, password), callback);
}
//TODO : use this.utils.executeRunnableStatusGoMethod
@ReactMethod
private void openAccounts(final Callback callback) {
Activity currentActivity = getCurrentActivity();
final String rootDir = this.utils.getNoBackupDirectory();
Log.d(TAG, "openAccounts");
if (!this.utils.checkAvailability()) {
Log.e(TAG, "[openAccounts] Activity doesn't exist, cannot call openAccounts");
System.exit(0);
return;
}
Log.d(TAG, "[Opening accounts" + rootDir);
Runnable r = new Runnable() {
@Override
public void run() {
String result = Statusgo.openAccounts(rootDir);
callback.invoke(result);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
}
//TODO : use this.utils.executeRunnableStatusGoMethod
@ReactMethod
public void logout() {
Log.d(TAG, "logout");
Runnable r = new Runnable() {
@Override
public void run() {
String result = Statusgo.logout();
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "Logout result: " + result);
} else {
Log.e(TAG, "Logout failed: " + result);
}
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
}
@ReactMethod
public void multiAccountStoreAccount(final String json, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountStoreAccount(json), callback);
}
@ReactMethod
public void multiAccountLoadAccount(final String json, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountLoadAccount(json), callback);
}
//TODO: maybe nuke this method since this is not called anywhere in status-mobile
@ReactMethod
public void multiAccountReset(final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountReset(), callback);
}
@ReactMethod
public void multiAccountDeriveAddresses(final String json, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountDeriveAddresses(json), callback);
}
@ReactMethod
public void multiAccountGenerateAndDeriveAddresses(final String json, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountGenerateAndDeriveAddresses(json), callback);
}
@ReactMethod
public void multiAccountStoreDerived(final String json, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountStoreDerivedAccounts(json), callback);
}
@ReactMethod
public void multiAccountImportMnemonic(final String json, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountImportMnemonic(json), callback);
}
@ReactMethod
public void multiAccountImportPrivateKey(final String json, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountImportPrivateKey(json), callback);
}
@ReactMethod
public void deleteMultiaccount(final String keyUID, final Callback callback) throws JSONException {
final String keyStoreDir = this.utils.getKeyStorePath(keyUID);
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.deleteMultiaccount(keyUID, keyStoreDir), callback);
}
}
@@ -1,66 +0,0 @@
package im.status.ethereum.module;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Callback;
import statusgo.Statusgo;
import android.util.Log;
import java.io.File;
import android.os.Environment;
import android.content.Context;
public class DatabaseManager extends ReactContextBaseJavaModule {
private static final String TAG = "DatabaseManager";
private ReactApplicationContext reactContext;
private static final String exportDBFileName = "export.db";
private Utils utils;
public DatabaseManager(ReactApplicationContext reactContext) {
this.reactContext = reactContext;
this.utils = new Utils(reactContext);
}
@Override
public String getName() {
return "DatabaseManager";
}
private File getExportDBFile() {
final Context context = this.getReactApplicationContext();
// Environment.getExternalStoragePublicDirectory doesn't work as expected on Android Q
// https://developer.android.com/reference/android/os/Environment#getExternalStoragePublicDirectory(java.lang.String)
final File pubDirectory = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);
final File filename = new File(pubDirectory, exportDBFileName);
return filename;
}
@ReactMethod
public void exportUnencryptedDatabase(final String accountData, final String password, final Callback callback) {
Log.d(TAG, "login");
final File newFile = getExportDBFile();
this.utils.migrateKeyStoreDir(accountData, password);
String result = Statusgo.exportUnencryptedDatabase(accountData, password, newFile.getAbsolutePath());
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "Login result: " + result);
} else {
Log.e(TAG, "Login failed: " + result);
}
}
@ReactMethod
public void importUnencryptedDatabase(final String accountData, final String password) {
Log.d(TAG, "importUnencryptedDatabase");
final File newFile = getExportDBFile();
this.utils.migrateKeyStoreDir(accountData, password);
String result = Statusgo.importUnencryptedDatabase(accountData, password, newFile.getAbsolutePath());
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "import result: " + result);
} else {
Log.e(TAG, "import failed: " + result);
}
}
}
@@ -1,199 +0,0 @@
package im.status.ethereum.module;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.Callback;
import android.util.Log;
import statusgo.Statusgo;
import org.json.JSONException;
import java.util.function.Function;
import java.util.function.Supplier;
import android.app.Activity;
import android.view.WindowManager;
import android.os.Build;
import android.view.Window;
import android.preference.PreferenceManager;
import android.content.SharedPreferences;
public class EncryptionUtils extends ReactContextBaseJavaModule {
private static final String TAG = "EncryptionUtils";
private ReactApplicationContext reactContext;
private Utils utils;
public EncryptionUtils(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
this.utils = new Utils(reactContext);
}
@Override
public String getName() {
return "EncryptionUtils";
}
@ReactMethod
private void initKeystore(final String keyUID, final Callback callback) throws JSONException {
Log.d(TAG, "initKeystore");
final String commonKeydir = this.utils.pathCombine(this.utils.getNoBackupDirectory(), "/keystore");
final String keydir = this.utils.pathCombine(commonKeydir, keyUID);
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.initKeystore(keydir), callback);
}
@ReactMethod
public void reEncryptDbAndKeystore(final String keyUID, final String password, final String newPassword, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.changeDatabasePassword(keyUID, password, newPassword), callback);
}
@ReactMethod
public void convertToKeycardAccount(final String keyUID, final String accountData, final String options, final String keycardUID, final String password,
final String newPassword, final Callback callback) throws JSONException {
final String keyStoreDir = this.utils.getKeyStorePath(keyUID);
this.utils.executeRunnableStatusGoMethod(() -> {
Statusgo.initKeystore(keyStoreDir);
return Statusgo.convertToKeycardAccount(accountData, options, keycardUID, password, newPassword);
}, callback);
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String encodeTransfer(final String to, final String value) {
return Statusgo.encodeTransfer(to, value);
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String encodeFunctionCall(final String method, final String paramsJSON) {
return Statusgo.encodeFunctionCall(method, paramsJSON);
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String decodeParameters(final String decodeParamJSON) {
return Statusgo.decodeParameters(decodeParamJSON);
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String hexToNumber(final String hex) {
return Statusgo.hexToNumber(hex);
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String numberToHex(final String numString) {
return Statusgo.numberToHex(numString);
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String sha3(final String str) {
return Statusgo.sha3(str);
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String utf8ToHex(final String str) {
return Statusgo.utf8ToHex(str);
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String hexToUtf8(final String str) {
return Statusgo.hexToUtf8(str);
}
@ReactMethod
public void setBlankPreviewFlag(final Boolean blankPreview) {
final SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this.reactContext);
sharedPrefs.edit().putBoolean("BLANK_PREVIEW", blankPreview).commit();
setSecureFlag();
}
private void setSecureFlag() {
final SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this.reactContext);
final boolean setSecure = sharedPrefs.getBoolean("BLANK_PREVIEW", true);
final Activity activity = this.reactContext.getCurrentActivity();
if (activity != null) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
final Window window = activity.getWindow();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH && setSecure) {
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE);
} else {
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
}
}
});
}
}
@ReactMethod
public void hashTransaction(final String txArgsJSON, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.hashTransaction(txArgsJSON), callback);
}
@ReactMethod
public void hashMessage(final String message, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.hashMessage(message), callback);
}
@ReactMethod
public void multiformatSerializePublicKey(final String multiCodecKey, final String base58btc, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiformatSerializePublicKey(multiCodecKey,base58btc), callback);
}
@ReactMethod
public void multiformatDeserializePublicKey(final String multiCodecKey, final String base58btc, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiformatDeserializePublicKey(multiCodecKey,base58btc), callback);
}
@ReactMethod
public void compressPublicKey(final String multiCodecKey, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.compressPublicKey(multiCodecKey), callback);
}
@ReactMethod
public void decompressPublicKey(final String multiCodecKey, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.decompressPublicKey(multiCodecKey), callback);
}
@ReactMethod
public void deserializeAndCompressKey(final String desktopKey, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.deserializeAndCompressKey(desktopKey), callback);
}
@ReactMethod
public void hashTypedData(final String data, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.hashTypedData(data), callback);
}
@ReactMethod
public void hashTypedDataV4(final String data, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.hashTypedDataV4(data), callback);
}
@ReactMethod
public void signMessage(final String rpcParams, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.signMessage(rpcParams), callback);
}
@ReactMethod
public void signTypedData(final String data, final String account, final String password, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.signTypedData(data, account, password), callback);
}
@ReactMethod
public void signTypedDataV4(final String data, final String account, final String password, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.signTypedDataV4(data, account, password), callback);
}
@ReactMethod
public void extractGroupMembershipSignatures(final String signaturePairs, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.extractGroupMembershipSignatures(signaturePairs), callback);
}
@ReactMethod
public void signGroupMembership(final String content, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.signGroupMembership(content), callback);
}
}
@@ -1,228 +0,0 @@
package im.status.ethereum.module;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.Callback;
import java.io.File;
import java.util.Stack;
import android.util.Log;
import android.net.Uri;
import java.io.OutputStreamWriter;
import java.io.IOException;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import androidx.core.content.FileProvider;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.util.zip.ZipOutputStream;
import java.io.FileInputStream;
import java.util.zip.ZipEntry;
import org.json.JSONObject;
import statusgo.Statusgo;
import android.content.Context;
import org.json.JSONException;
public class LogManager extends ReactContextBaseJavaModule {
private static final String TAG = "LogManager";
private static final String gethLogFileName = "geth.log";
private static final String statusLogFileName = "Status.log";
private static final String logsZipFileName = "Status-debug-logs.zip";
private ReactApplicationContext reactContext;
private Utils utils;
public LogManager(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
this.utils = new Utils(reactContext);
}
@Override
public String getName() {
return "LogManager";
}
private File getLogsFile() {
final File pubDirectory = this.utils.getPublicStorageDirectory();
final File logFile = new File(pubDirectory, gethLogFileName);
return logFile;
}
public File prepareLogsFile(final Context context) {
final File logFile = this.utils.getLogsFile();
try {
logFile.setReadable(true);
File parent = logFile.getParentFile();
if (!parent.canWrite()) {
return null;
}
if (!parent.exists()) {
parent.mkdirs();
}
logFile.createNewFile();
logFile.setWritable(true);
Log.d(TAG, "Can write " + logFile.canWrite());
Uri gethLogUri = Uri.fromFile(logFile);
String gethLogFilePath = logFile.getAbsolutePath();
Log.d(TAG, gethLogFilePath);
return logFile;
} catch (Exception e) {
Log.d(TAG, "Can't create geth.log file! " + e.getMessage());
}
return null;
}
private void showErrorMessage(final String message) {
final Activity activity = getCurrentActivity();
new AlertDialog.Builder(activity)
.setTitle("Error")
.setMessage(message)
.setNegativeButton("Exit", new DialogInterface.OnClickListener() {
public void onClick(final DialogInterface dialog, final int id) {
dialog.dismiss();
}
}).show();
}
private void dumpAdbLogsTo(final FileOutputStream statusLogStream) throws IOException {
final String filter = "logcat -d -b main ReactNativeJS:D StatusModule:D StatusService:D StatusNativeLogs:D *:S";
final java.lang.Process p = Runtime.getRuntime().exec(filter);
final java.io.BufferedReader in = new java.io.BufferedReader(new java.io.InputStreamReader(p.getInputStream()));
final java.io.BufferedWriter out = new java.io.BufferedWriter(new java.io.OutputStreamWriter(statusLogStream));
String line;
while ((line = in.readLine()) != null) {
out.write(line);
out.newLine();
}
out.close();
in.close();
}
private Boolean zip(File[] _files, File zipFile, Stack<String> errorList) {
final int BUFFER = 0x8000;
try {
BufferedInputStream origin = null;
FileOutputStream dest = new FileOutputStream(zipFile);
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest));
byte data[] = new byte[BUFFER];
for (int i = 0; i < _files.length; i++) {
final File file = _files[i];
if (file == null || !file.exists()) {
continue;
}
Log.v("Compress", "Adding: " + file.getAbsolutePath());
try {
FileInputStream fi = new FileInputStream(file);
origin = new BufferedInputStream(fi, BUFFER);
ZipEntry entry = new ZipEntry(file.getName());
out.putNextEntry(entry);
int count;
while ((count = origin.read(data, 0, BUFFER)) != -1) {
out.write(data, 0, count);
}
origin.close();
} catch (IOException e) {
Log.e(TAG, e.getMessage());
errorList.push(e.getMessage());
}
}
out.close();
return true;
} catch (Exception e) {
Log.e(TAG, e.getMessage());
e.printStackTrace();
return false;
}
}
@ReactMethod
public void sendLogs(final String dbJson, final String jsLogs, final Callback callback) {
Log.d(TAG, "sendLogs");
if (!this.utils.checkAvailability()) {
return;
}
final Context context = this.getReactApplicationContext();
final File logsTempDir = new File(context.getCacheDir(), "logs"); // This path needs to be in sync with android/app/src/main/res/xml/file_provider_paths.xml
logsTempDir.mkdir();
final File dbFile = new File(logsTempDir, "db.json");
try {
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(dbFile));
outputStreamWriter.write(dbJson);
outputStreamWriter.close();
} catch (IOException e) {
Log.e(TAG, "File write failed: " + e.toString());
showErrorMessage(e.getLocalizedMessage());
}
final File zipFile = new File(logsTempDir, logsZipFileName);
final File statusLogFile = new File(logsTempDir, statusLogFileName);
final File gethLogFile = getLogsFile();
try {
if (zipFile.exists() || zipFile.createNewFile()) {
final long usableSpace = zipFile.getUsableSpace();
if (usableSpace < 20 * 1024 * 1024) {
final String message = String.format("Insufficient space available on device (%s) to write logs.\nPlease free up some space.", android.text.format.Formatter.formatShortFileSize(context, usableSpace));
Log.e(TAG, message);
showErrorMessage(message);
return;
}
}
dumpAdbLogsTo(new FileOutputStream(statusLogFile));
final Stack<String> errorList = new Stack<String>();
final Boolean zipped = zip(new File[]{dbFile, gethLogFile, statusLogFile}, zipFile, errorList);
if (zipped && zipFile.exists()) {
zipFile.setReadable(true, false);
Uri extUri = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", zipFile);
callback.invoke(extUri.toString());
} else {
Log.d(TAG, "File " + zipFile.getAbsolutePath() + " does not exist");
}
} catch (Exception e) {
Log.e(TAG, e.getMessage());
showErrorMessage(e.getLocalizedMessage());
e.printStackTrace();
return;
} finally {
dbFile.delete();
statusLogFile.delete();
zipFile.deleteOnExit();
}
}
@ReactMethod
public void initLogging(final boolean enabled, final boolean mobileSystem, final String logLevel, final Callback callback) throws JSONException {
final JSONObject jsonConfig = new JSONObject();
jsonConfig.put("Enabled", enabled);
jsonConfig.put("MobileSystem", mobileSystem);
jsonConfig.put("Level", logLevel);
jsonConfig.put("File", getLogsFile().getAbsolutePath());
final String config = jsonConfig.toString();
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.initLogging(config), callback);
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String logFileDirectory() {
return this.utils.getPublicStorageDirectory().getAbsolutePath();
}
}
@@ -1,84 +0,0 @@
package im.status.ethereum.module;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Callback;
import org.json.JSONException;
import statusgo.Statusgo;
import org.json.JSONObject;
public class NetworkManager extends ReactContextBaseJavaModule {
private static final String TAG = "NetworkManager";
private ReactApplicationContext reactContext;
private Utils utils;
public NetworkManager(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
this.utils = new Utils(reactContext);
}
@Override
public String getName() {
return "NetworkManager";
}
@ReactMethod
public void addPeer(final String enode, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.addPeer(enode), callback);
}
@ReactMethod
public void startSearchForLocalPairingPeers(final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.startSearchForLocalPairingPeers(), callback);
}
@ReactMethod
public void getConnectionStringForBootstrappingAnotherDevice(final String configJSON, final Callback callback) throws JSONException {
final JSONObject jsonConfig = new JSONObject(configJSON);
final JSONObject senderConfig = jsonConfig.getJSONObject("senderConfig");
final String keyUID = senderConfig.getString("keyUID");
final String keyStorePath = this.utils.getKeyStorePath(keyUID);
senderConfig.put("keystorePath", keyStorePath);
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.getConnectionStringForBootstrappingAnotherDevice(jsonConfig.toString()), callback);
}
@ReactMethod
public void inputConnectionStringForBootstrapping(final String connectionString, final String configJSON, final Callback callback) throws JSONException {
final JSONObject jsonConfig = new JSONObject(configJSON);
final JSONObject receiverConfig = jsonConfig.getJSONObject("receiverConfig");
final String keyStorePath = this.utils.pathCombine(this.utils.getNoBackupDirectory(), "/keystore");
receiverConfig.put("keystorePath", keyStorePath);
receiverConfig.getJSONObject("nodeConfig").put("rootDataDir", this.utils.getNoBackupDirectory());
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.inputConnectionStringForBootstrapping(connectionString, jsonConfig.toString()), callback);
}
@ReactMethod
public void sendTransactionWithSignature(final String txArgsJSON, final String signature, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.sendTransactionWithSignature(txArgsJSON, signature), callback);
}
@ReactMethod
public void sendTransaction(final String txArgsJSON, final String password, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.sendTransaction(txArgsJSON, password), callback);
}
@ReactMethod
public void callRPC(final String payload, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.callRPC(payload), callback);
}
@ReactMethod
public void callPrivateRPC(final String payload, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.callPrivateRPC(payload), callback);
}
@ReactMethod
public void recover(final String rpcParams, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.recover(rpcParams), callback);
}
}
@@ -30,13 +30,6 @@ public class StatusPackage implements ReactPackage {
List<NativeModule> modules = new ArrayList<>();
modules.add(new StatusModule(reactContext, this.rootedDevice));
modules.add(new AccountManager(reactContext));
modules.add(new EncryptionUtils(reactContext));
modules.add(new DatabaseManager(reactContext));
modules.add(new UIHelper(reactContext));
modules.add(new LogManager(reactContext));
modules.add(new Utils(reactContext));
modules.add(new NetworkManager(reactContext));
modules.add(new RNSelectableTextInputModule(reactContext));
return modules;
@@ -1,159 +0,0 @@
package im.status.ethereum.module;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import android.app.Activity;
import android.util.Log;
import android.os.Build;
import android.webkit.WebView;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
import android.webkit.WebStorage;
import android.view.WindowManager;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.UIBlock;
import com.facebook.react.uimanager.NativeViewHierarchyManager;
import android.view.inputmethod.InputMethodManager;
import android.view.View;
import android.widget.EditText;
import android.content.Context;
public class UIHelper extends ReactContextBaseJavaModule {
private static final String TAG = "UIHelper";
private ReactApplicationContext reactContext;
public UIHelper(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
}
@Override
public String getName() {
return "UIHelper";
}
//TODO : maybe nuke since it is not called anywhere in status-mobile code
@ReactMethod
public void setAdjustResize() {
Log.d(TAG, "setAdjustResize");
final Activity activity = getCurrentActivity();
if (activity == null) {
return;
}
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
}
});
}
//TODO : maybe nuke since it is not called anywhere in status-mobile code
@ReactMethod
public void setAdjustPan() {
Log.d(TAG, "setAdjustPan");
final Activity activity = getCurrentActivity();
if (activity == null) {
return;
}
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
}
});
}
@ReactMethod
public void setSoftInputMode(final int mode) {
Log.d(TAG, "setSoftInputMode");
final Activity activity = getCurrentActivity();
if (activity == null) {
return;
}
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
activity.getWindow().setSoftInputMode(mode);
}
});
}
@SuppressWarnings("deprecation")
@ReactMethod
public void clearCookies() {
Log.d(TAG, "clearCookies");
final Activity activity = getCurrentActivity();
if (activity == null) {
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
CookieManager.getInstance().removeAllCookies(null);
CookieManager.getInstance().flush();
} else {
CookieSyncManager cookieSyncManager = CookieSyncManager.createInstance(activity);
cookieSyncManager.startSync();
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.removeAllCookie();
cookieManager.removeSessionCookie();
cookieSyncManager.stopSync();
cookieSyncManager.sync();
}
}
@ReactMethod
public void toggleWebviewDebug(final boolean val) {
Log.d(TAG, "toggleWebviewDebug");
final Activity activity = getCurrentActivity();
if (activity == null) {
return;
}
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
WebView.setWebContentsDebuggingEnabled(val);
}
});
}
@ReactMethod
public void clearStorageAPIs() {
Log.d(TAG, "clearStorageAPIs");
final Activity activity = getCurrentActivity();
if (activity == null) {
return;
}
WebStorage storage = WebStorage.getInstance();
if (storage != null) {
storage.deleteAllData();
}
}
@ReactMethod
public void resetKeyboardInputCursor(final int reactTagToReset, final int selection) {
UIManagerModule uiManager = getReactApplicationContext().getNativeModule(UIManagerModule.class);
uiManager.addUIBlock(new UIBlock() {
@Override
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
InputMethodManager imm = (InputMethodManager) getReactApplicationContext().getBaseContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
View viewToReset = nativeViewHierarchyManager.resolveView(reactTagToReset);
imm.restartInput(viewToReset);
try {
EditText textView = (EditText) viewToReset;
textView.setSelection(selection);
} catch (Exception e) {}
}
}
});
}
}
@@ -1,155 +0,0 @@
package im.status.ethereum.module;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import android.util.Log;
import java.util.function.Supplier;
import java.io.File;
import android.content.Context;
import android.os.Environment;
import org.json.JSONObject;
import org.json.JSONException;
import statusgo.Statusgo;
public class Utils extends ReactContextBaseJavaModule {
private static final String gethLogFileName = "geth.log";
private static final String TAG = "Utils";
private ReactApplicationContext reactContext;
public Utils(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
}
@Override
public String getName() {
return "Utils";
}
public String getNoBackupDirectory() {
return this.getReactApplicationContext().getNoBackupFilesDir().getAbsolutePath();
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String backupDisabledDataDir() {
return getNoBackupDirectory();
}
public File getPublicStorageDirectory() {
final Context context = this.getReactApplicationContext();
// Environment.getExternalStoragePublicDirectory doesn't work as expected on Android Q
// https://developer.android.com/reference/android/os/Environment#getExternalStoragePublicDirectory(java.lang.String)
return context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);
}
public File getLogsFile() {
final File pubDirectory = getPublicStorageDirectory();
final File logFile = new File(pubDirectory, gethLogFileName);
return logFile;
}
public String getKeyUID(final String json) throws JSONException {
final JSONObject jsonObj = new JSONObject(json);
return jsonObj.getString("key-uid");
}
public String pathCombine(final String path1, final String path2) {
// Replace this logic with Paths.get(path1, path2) once API level 26+ becomes the minimum supported API level
final File file = new File(path1, path2);
return file.getAbsolutePath();
}
public String getKeyStorePath(String keyUID) {
final String commonKeydir = pathCombine(getNoBackupDirectory(), "/keystore");
final String keydir = pathCombine(commonKeydir, keyUID);
return keydir;
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String keystoreDir() {
final String absRootDirPath = getNoBackupDirectory();
return pathCombine(absRootDirPath, "keystore");
}
public void migrateKeyStoreDir(final String accountData, final String password) {
try {
final String commonKeydir = pathCombine(getNoBackupDirectory(), "/keystore");
final String keydir = getKeyStorePath(getKeyUID(accountData));
Log.d(TAG, "before migrateKeyStoreDir " + keydir);
File keydirFile = new File(keydir);
if(!keydirFile.exists() || keydirFile.list().length == 0) {
Log.d(TAG, "migrateKeyStoreDir");
Statusgo.migrateKeyStoreDir(accountData, password, commonKeydir, keydir);
Statusgo.initKeystore(keydir);
}
} catch (JSONException e) {
Log.e(TAG, "JSON conversion failed: " + e.getMessage());
}
}
public boolean checkAvailability() {
// We wait at least 10s for getCurrentActivity to return a value,
// otherwise we give up
for (int attempts = 0; attempts < 100; attempts++) {
if (getCurrentActivity() != null) {
return true;
}
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
if (getCurrentActivity() != null) {
return true;
}
Log.d(TAG, "Activity doesn't exist");
return false;
}
}
Log.d(TAG, "Activity doesn't exist");
return false;
}
public void executeRunnableStatusGoMethod(Supplier<String> method, Callback callback) throws JSONException {
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable runnableTask = () -> {
String res = method.get();
callback.invoke(res);
};
StatusThreadPoolExecutor.getInstance().execute(runnableTask);
}
@ReactMethod
public void validateMnemonic(final String seed, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.validateMnemonic(seed), callback);
}
public Boolean is24Hour() {
return android.text.format.DateFormat.is24HourFormat(this.reactContext.getApplicationContext());
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String checkAddressChecksum(final String address) {
return Statusgo.checkAddressChecksum(address);
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String isAddress(final String address) {
return Statusgo.isAddress(address);
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String toChecksumAddress(final String address) {
return Statusgo.toChecksumAddress(address);
}
}
+1 -1
View File
@@ -4,8 +4,8 @@
[legacy.status-im.data-store.chats :as chats-store]
[legacy.status-im.utils.deprecated-types :as types]
[re-frame.core :as re-frame]
[status-im.contexts.chat.contacts.events :as contacts-store]
[status-im.contexts.chat.messages.list.events :as message-list]
[status-im.contexts.contacts.events :as contacts-store]
[status-im.contexts.shell.activity-center.events :as activity-center]
[status-im.navigation.events :as navigation]
[utils.re-frame :as rf]))
@@ -6,7 +6,7 @@
[legacy.status-im.multiaccounts.update.core :as multiaccounts.update]
[legacy.status-im.utils.mobile-sync :as utils]
[legacy.status-im.wallet.core :as wallet]
[status-im.contexts.chat.home.add-new-contact.events :as add-new-contact]
[status-im.contexts.add-new-contact.events :as add-new-contact]
[status-im.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
+64 -99
View File
@@ -11,41 +11,6 @@
(when (exists? (.-NativeModules react-native))
(.-Status ^js (.-NativeModules react-native))))
(defn account
[]
(when (exists? (.-NativeModules react-native))
(.-AccountManager ^js (.-NativeModules react-native))))
(defn encryption
[]
(when (exists? (.-NativeModules react-native))
(.-EncryptionUtils ^js (.-NativeModules react-native))))
(defn database
[]
(when (exists? (.-NativeModules react-native))
(.-DatabaseManager ^js (.-NativeModules react-native))))
(defn ui-helper
[]
(when (exists? (.-NativeModules react-native))
(.-UIHelper ^js (.-NativeModules react-native))))
(defn log-manager
[]
(when (exists? (.-NativeModules react-native))
(.-LogManager ^js (.-NativeModules react-native))))
(defn utils
[]
(when (exists? (.-NativeModules react-native))
(.-Utils ^js (.-NativeModules react-native))))
(defn network
[]
(when (exists? (.-NativeModules react-native))
(.-NetworkManager ^js (.-NativeModules react-native))))
(defn init
[handler]
(.addListener ^js (.-DeviceEventEmitter ^js react-native) "gethEvent" #(handler (.-jsonEvent ^js %))))
@@ -54,23 +19,23 @@
[]
(log/debug "[native-module] clear-web-data")
(when (status)
(.clearCookies ^js (ui-helper))
(.clearStorageAPIs ^js (ui-helper))))
(.clearCookies ^js (status))
(.clearStorageAPIs ^js (status))))
(defn init-keystore
[key-uid callback]
(log/debug "[native-module] init-keystore" key-uid)
(.initKeystore ^js (encryption) key-uid callback))
(.initKeystore ^js (status) key-uid callback))
(defn open-accounts
[callback]
(log/debug "[native-module] open-accounts")
(.openAccounts ^js (account) #(callback (types/json->clj %))))
(.openAccounts ^js (status) #(callback (types/json->clj %))))
(defn prepare-dir-and-update-config
[key-uid config callback]
(log/debug "[native-module] prepare-dir-and-update-config")
(.prepareDirAndUpdateConfig ^js (account)
(.prepareDirAndUpdateConfig ^js (status)
key-uid
config
#(callback (types/json->clj %))))
@@ -82,7 +47,7 @@
(init-keystore
key-uid
#(.saveAccountAndLoginWithKeycard
^js (account)
^js (status)
multiaccount-data
password
settings
@@ -98,24 +63,24 @@
(let [config (if config (types/clj->json config) "")]
(init-keystore
key-uid
#(.loginWithConfig ^js (account) account-data hashed-password config))))
#(.loginWithConfig ^js (status) account-data hashed-password config))))
(defn login-account
"NOTE: beware, the password has to be sha3 hashed"
[{:keys [keyUid] :as request}]
(log/debug "[native-module] loginAccount")
(log/debug "[native-module] loginWithConfig")
(clear-web-data)
(init-keystore
keyUid
#(.loginAccount ^js (account) (types/clj->json request))))
#(.loginAccount ^js (status) (types/clj->json request))))
(defn create-account-and-login
[request]
(.createAccountAndLogin ^js (account) (types/clj->json request)))
(.createAccountAndLogin ^js (status) (types/clj->json request)))
(defn restore-account-and-login
[request]
(.restoreAccountAndLogin ^js (account) (types/clj->json request)))
(.restoreAccountAndLogin ^js (status) (types/clj->json request)))
(defn export-db
"NOTE: beware, the password has to be sha3 hashed"
@@ -124,7 +89,7 @@
(clear-web-data)
(init-keystore
key-uid
#(.exportUnencryptedDatabase ^js (database) account-data hashed-password callback)))
#(.exportUnencryptedDatabase ^js (status) account-data hashed-password callback)))
(defn import-db
"NOTE: beware, the password has to be sha3 hashed"
@@ -133,13 +98,13 @@
(clear-web-data)
(init-keystore
key-uid
#(.importUnencryptedDatabase ^js (database) account-data hashed-password)))
#(.importUnencryptedDatabase ^js (status) account-data hashed-password)))
(defn logout
[]
(log/debug "[native-module] logout")
(clear-web-data)
(.logout ^js (account)))
(.logout ^js (status)))
(defn multiaccount-load-account
"NOTE: beware, the password has to be sha3 hashed
@@ -149,7 +114,7 @@
from memory"
[address hashed-password callback]
(log/debug "[native-module] multiaccount-load-account")
(.multiAccountLoadAccount ^js (account)
(.multiAccountLoadAccount ^js (status)
(types/clj->json {:address address
:password hashed-password})
callback))
@@ -162,7 +127,7 @@
[account-id paths callback]
(log/debug "[native-module] multiaccount-derive-addresses")
(when (status)
(.multiAccountDeriveAddresses ^js (account)
(.multiAccountDeriveAddresses ^js (status)
(types/clj->json {:accountID account-id
:paths paths})
callback)))
@@ -180,7 +145,7 @@
(when (status)
(init-keystore
key-uid
#(.multiAccountStoreAccount ^js (account)
#(.multiAccountStoreAccount ^js (status)
(types/clj->json {:accountID account-id
:password hashed-password})
callback))))
@@ -193,7 +158,7 @@
account-id)
(init-keystore
key-uid
#(.multiAccountStoreDerived ^js (account)
#(.multiAccountStoreDerived ^js (status)
(types/clj->json {:accountID account-id
:paths paths
:password hashed-password})
@@ -206,7 +171,7 @@
to store the key"
[n mnemonic-length paths callback]
(log/debug "[native-module] multiaccount-generate-and-derive-addresses")
(.multiAccountGenerateAndDeriveAddresses ^js (account)
(.multiAccountGenerateAndDeriveAddresses ^js (status)
(types/clj->json {:n n
:mnemonicPhraseLength mnemonic-length
:bip39Passphrase ""
@@ -216,7 +181,7 @@
(defn multiaccount-import-mnemonic
[mnemonic password callback]
(log/debug "[native-module] multiaccount-import-mnemonic")
(.multiAccountImportMnemonic ^js (account)
(.multiAccountImportMnemonic ^js (status)
(types/clj->json {:mnemonicPhrase mnemonic
;;NOTE this is not the multiaccount password
:Bip39Passphrase password})
@@ -225,7 +190,7 @@
(defn multiaccount-import-private-key
[private-key callback]
(log/debug "[native-module] multiaccount-import-private-key")
(.multiAccountImportPrivateKey ^js (account)
(.multiAccountImportPrivateKey ^js (status)
(types/clj->json {:privateKey private-key})
callback))
@@ -233,13 +198,13 @@
"NOTE: beware, the password has to be sha3 hashed"
[address hashed-password callback]
(log/debug "[native-module] verify")
(.verify ^js (account) address hashed-password callback))
(.verify ^js (status) address hashed-password callback))
(defn verify-database-password
"NOTE: beware, the password has to be sha3 hashed"
[key-uid hashed-password callback]
(log/debug "[native-module] verify-database-password")
(.verifyDatabasePassword ^js (account) key-uid hashed-password callback))
(.verifyDatabasePassword ^js (status) key-uid hashed-password callback))
(defn login-with-keycard
[{:keys [key-uid multiaccount-data password chat-key node-config]}]
@@ -247,40 +212,40 @@
(clear-web-data)
(init-keystore
key-uid
#(.loginWithKeycard ^js (account) multiaccount-data password chat-key (types/clj->json node-config))))
#(.loginWithKeycard ^js (status) multiaccount-data password chat-key (types/clj->json node-config))))
(defn set-soft-input-mode
[mode]
(log/debug "[native-module] set-soft-input-mode")
(.setSoftInputMode ^js (ui-helper) mode))
(.setSoftInputMode ^js (status) mode))
(defn call-rpc
[payload callback]
(log/debug "[native-module] call-rpc")
(.callRPC ^js (network) payload callback))
(.callRPC ^js (status) payload callback))
(defn call-private-rpc
[payload callback]
(.callPrivateRPC ^js (network) payload callback))
(.callPrivateRPC ^js (status) payload callback))
(defn hash-transaction
"used for keycard"
[rpcParams callback]
(log/debug "[native-module] hash-transaction")
(.hashTransaction ^js (encryption) rpcParams callback))
(.hashTransaction ^js (status) rpcParams callback))
(defn hash-message
"used for keycard"
[message callback]
(log/debug "[native-module] hash-message")
(.hashMessage ^js (encryption) message callback))
(.hashMessage ^js (status) message callback))
(defn start-searching-for-local-pairing-peers
"starts a UDP multicast beacon that both listens for and broadcasts to LAN peers"
[callback]
(log/info "[native-module] Start Searching for Local Pairing Peers"
{:fn :start-searching-for-local-pairing-peers})
(.startSearchForLocalPairingPeers ^js (network) callback))
(.startSearchForLocalPairingPeers ^js (status) callback))
(defn local-pairing-preflight-outbound-check
"Checks whether the device has allows connecting to the local server"
@@ -295,7 +260,7 @@
(log/info "[native-module] Fetching Connection String"
{:fn :get-connection-string-for-bootstrapping-another-device
:config-json config-json})
(.getConnectionStringForBootstrappingAnotherDevice ^js (network) config-json callback))
(.getConnectionStringForBootstrappingAnotherDevice ^js (status) config-json callback))
(defn input-connection-string-for-bootstrapping
"Provides connection string to status-go for the purpose of local pairing on the receiver end"
@@ -304,7 +269,7 @@
{:fn :input-connection-string-for-bootstrapping
:config-json config-json
:connection-string connection-string})
(.inputConnectionStringForBootstrapping ^js (network) connection-string config-json callback))
(.inputConnectionStringForBootstrapping ^js (status) connection-string config-json callback))
(defn deserialize-and-compress-key
"Provides a community id (public key) to status-go which is first deserialized
@@ -315,7 +280,7 @@
(log/info "[native-module] Deserializing and then compressing public key"
{:fn :deserialize-and-compress-key
:key input-key})
(.deserializeAndCompressKey ^js (encryption) input-key callback))
(.deserializeAndCompressKey ^js (status) input-key callback))
(defn compressed-key->public-key
"Provides compressed key to status-go and gets back the uncompressed public key via deserialization"
@@ -323,59 +288,59 @@
(log/info "[native-module] Deserializing compressed key"
{:fn :compressed-key->public-key
:public-key public-key})
(.multiformatDeserializePublicKey ^js (encryption) public-key deserialization-key callback))
(.multiformatDeserializePublicKey ^js (status) public-key deserialization-key callback))
(defn hash-typed-data
"used for keycard"
[data callback]
(log/debug "[native-module] hash-typed-data")
(.hashTypedData ^js (encryption) data callback))
(.hashTypedData ^js (status) data callback))
(defn hash-typed-data-v4
"used for keycard"
[data callback]
(log/debug "[native-module] hash-typed-data-v4")
(.hashTypedDataV4 ^js (encryption) data callback))
(.hashTypedDataV4 ^js (status) data callback))
(defn send-transaction-with-signature
"used for keycard"
[rpcParams sig callback]
(log/debug "[native-module] send-transaction-with-signature")
(.sendTransactionWithSignature ^js (network) rpcParams sig callback))
(.sendTransactionWithSignature ^js (status) rpcParams sig callback))
(defn sign-message
"NOTE: beware, the password in rpcParams has to be sha3 hashed"
[rpcParams callback]
(log/debug "[native-module] sign-message")
(.signMessage ^js (encryption) rpcParams callback))
(.signMessage ^js (status) rpcParams callback))
(defn recover-message
[rpcParams callback]
(log/debug "[native-module] recover")
(.recover ^js (network) rpcParams callback))
(.recover ^js (status) rpcParams callback))
(defn send-transaction
"NOTE: beware, the password has to be sha3 hashed"
[rpcParams hashed-password callback]
(log/debug "[native-module] send-transaction")
(.sendTransaction ^js (network) rpcParams hashed-password callback))
(.sendTransaction ^js (status) rpcParams hashed-password callback))
(defn sign-typed-data
"NOTE: beware, the password has to be sha3 hashed"
[data account hashed-password callback]
(log/debug "[native-module] sign-typed-data")
(.signTypedData ^js (encryption) data account hashed-password callback))
(.signTypedData ^js (status) data account hashed-password callback))
(defn sign-typed-data-v4
"NOTE: beware, the password has to be sha3 hashed"
[data account hashed-password callback]
(log/debug "[native-module] sign-typed-data-v4")
(.signTypedDataV4 ^js (encryption) data account hashed-password callback))
(.signTypedDataV4 ^js (status) data account hashed-password callback))
(defn send-logs
[dbJson js-logs callback]
(log/debug "[native-module] send-logs")
(.sendLogs ^js (log-manager) dbJson js-logs callback))
(.sendLogs ^js (status) dbJson js-logs callback))
(defn close-application
[]
@@ -400,7 +365,7 @@
(defn set-blank-preview-flag
[flag]
(log/debug "[native-module] set-blank-preview-flag")
(.setBlankPreviewFlag ^js (encryption) flag))
(.setBlankPreviewFlag ^js (status) flag))
(defn get-device-model-info
[]
@@ -428,7 +393,7 @@
(defn toggle-webview-debug
[on]
(log/debug "[native-module] toggle-webview-debug" on)
(.toggleWebviewDebug ^js (ui-helper) on))
(.toggleWebviewDebug ^js (status) on))
(defn rooted-device?
[callback]
@@ -451,72 +416,72 @@
(defn encode-transfer
[to-norm amount-hex]
(log/debug "[native-module] encode-transfer")
(.encodeTransfer ^js (encryption) to-norm amount-hex))
(.encodeTransfer ^js (status) to-norm amount-hex))
(defn decode-parameters
[bytes-string types]
(log/debug "[native-module] decode-parameters")
(let [json-str (.decodeParameters ^js (encryption)
(let [json-str (.decodeParameters ^js (status)
(types/clj->json {:bytesString bytes-string :types types}))]
(types/json->clj json-str)))
(defn hex-to-number
[hex]
(log/debug "[native-module] hex-to-number")
(let [json-str (.hexToNumber ^js (encryption) hex)]
(let [json-str (.hexToNumber ^js (status) hex)]
(types/json->clj json-str)))
(defn number-to-hex
[num]
(log/debug "[native-module] number-to-hex")
(.numberToHex ^js (encryption) (str num)))
(.numberToHex ^js (status) (str num)))
(defn sha3
[s]
(log/debug "[native-module] sha3")
(when s
(.sha3 ^js (encryption) (str s))))
(.sha3 ^js (status) (str s))))
(defn utf8-to-hex
[s]
(log/debug "[native-module] utf8-to-hex")
(.utf8ToHex ^js (encryption) s))
(.utf8ToHex ^js (status) s))
(defn hex-to-utf8
[s]
(log/debug "[native-module] hex-to-utf8")
(.hexToUtf8 ^js (encryption) s))
(.hexToUtf8 ^js (status) s))
(defn check-address-checksum
[address]
(log/debug "[native-module] check-address-checksum")
(let [result (.checkAddressChecksum ^js (utils) address)]
(let [result (.checkAddressChecksum ^js (status) address)]
(types/json->clj result)))
(defn address?
[address]
(log/debug "[native-module] address?")
(when address
(let [result (.isAddress ^js (utils) address)]
(let [result (.isAddress ^js (status) address)]
(types/json->clj result))))
(defn to-checksum-address
[address]
(log/debug "[native-module] to-checksum-address")
(.toChecksumAddress ^js (utils) address))
(.toChecksumAddress ^js (status) address))
(defn validate-mnemonic
"Validate that a mnemonic conforms to BIP39 dictionary/checksum standards"
[mnemonic callback]
(log/debug "[native-module] validate-mnemonic")
(.validateMnemonic ^js (utils) mnemonic callback))
(.validateMnemonic ^js (status) mnemonic callback))
(defn delete-multiaccount
"Delete multiaccount from database, deletes multiaccount's database and
key files."
[key-uid callback]
(log/debug "[native-module] delete-multiaccount")
(.deleteMultiaccount ^js (account) key-uid callback))
(.deleteMultiaccount ^js (status) key-uid callback))
(defn delete-imported-key
"Delete imported key file."
@@ -528,7 +493,7 @@
[input selection]
(log/debug "[native-module] resetKeyboardInput")
(when platform/android?
(.resetKeyboardInputCursor ^js (ui-helper) input selection)))
(.resetKeyboardInputCursor ^js (status) input selection)))
;; passwords are hashed
(defn reset-password
@@ -536,12 +501,12 @@
(log/debug "[native-module] change-database-password")
(init-keystore
key-uid
#(.reEncryptDbAndKeystore ^js (encryption) key-uid current-password# new-password# callback)))
#(.reEncryptDbAndKeystore ^js (status) key-uid current-password# new-password# callback)))
(defn convert-to-keycard-account
[{:keys [key-uid] :as multiaccount-data} settings current-password# new-password callback]
(log/debug "[native-module] convert-to-keycard-account")
(.convertToKeycardAccount ^js (encryption)
(.convertToKeycardAccount ^js (status)
key-uid
(types/clj->json multiaccount-data)
(types/clj->json settings)
@@ -552,7 +517,7 @@
(defn backup-disabled-data-dir
[]
(.backupDisabledDataDir ^js (utils)))
(.backupDisabledDataDir ^js (status)))
(defn fleets
[]
@@ -560,12 +525,12 @@
(defn keystore-dir
[]
(.keystoreDir ^js (utils)))
(.keystoreDir ^js (status)))
(defn log-file-directory
[]
(.logFileDirectory ^js (log-manager)))
(.logFileDirectory ^js (status)))
(defn init-status-go-logging
[{:keys [enable? mobile-system? log-level callback]}]
(.initLogging ^js (log-manager) enable? mobile-system? log-level callback))
(.initLogging ^js (status) enable? mobile-system? log-level callback))
@@ -1,24 +0,0 @@
(ns quo.components.list-items.quiz-item.component-spec
(:require
[quo.components.list-items.quiz-item.view :as quiz-item]
[test-helpers.component :as h]))
(h/describe "List Items: Token Value"
(h/test "Number label renders"
(h/render [quiz-item/view
{:state :empty
:word "collapse"
:number 2}])
(h/is-truthy (h/get-by-label-text :number-container)))
(h/test "Success icon renders"
(h/render [quiz-item/view
{:state :success
:word "collapse"
:number 2}])
(h/is-truthy (h/get-by-label-text :success-icon)))
(h/test "Error icon renders"
(h/render [quiz-item/view
{:state :error
:word "collapse"
:number 2}])
(h/is-truthy (h/get-by-label-text :error-icon))))
@@ -1,45 +0,0 @@
(ns quo.components.list-items.quiz-item.style
(:require [quo.foundations.colors :as colors]))
(defn container
[{:keys [blur? theme state]}]
{:flex 1
:flex-direction :row
:justify-content :space-between
:align-items :center
:max-height 56
:padding 12
:border-radius 12
:opacity (if (= state :disabled) 0.3 1)
:border-width (if (and blur? (or (= state :empty) (= state :disabled))) 0 1)
:border-color (case state
:success colors/success-50-opa-20
:error colors/danger-50-opa-20
(colors/theme-colors colors/neutral-20 colors/neutral-80 theme))
:background-color (case state
:empty (if blur?
colors/white-opa-5
(colors/theme-colors colors/white colors/neutral-80-opa-40 theme))
:disabled (if blur?
colors/white-opa-5
(colors/theme-colors colors/neutral-5 colors/neutral-80-opa-40 theme))
:success (colors/resolve-color :success theme 10)
:error (colors/resolve-color :danger theme 10))})
(defn num-container
[{:keys [blur? theme]}]
{:width 32
:height 32
:justify-content :center
:align-items :center
:border-radius 10
:border-width 1
:border-color (if blur?
colors/white-opa-10
(colors/theme-colors colors/neutral-20 colors/neutral-70 theme))})
(defn text
[{:keys [theme state]}]
{:color (case state
:success (colors/theme-colors colors/success-50 colors/success-60 theme)
:error (colors/theme-colors colors/danger-50 colors/danger-60 theme))})
@@ -1,30 +0,0 @@
(ns quo.components.list-items.quiz-item.view
(:require
[quo.components.icon :as icon]
[quo.components.list-items.quiz-item.style :as style]
[quo.components.markdown.text :as text]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[utils.i18n :as i18n]))
(defn- view-internal
[{:keys [state theme number word] :as props}]
[rn/view {:style (style/container props)}
(if (or (= state :empty) (= state :disabled))
[rn/view
{:style (style/num-container props)
:accessibility-label :number-container}
[text/text {:weight :semi-bold} number]]
[text/text {:style (style/text props)}
(if (= state :success) word (i18n/label :t/oops-wrong-word))])
(when (= state :success)
[icon/icon :i/check
{:color (colors/theme-colors colors/success-50 colors/success-60 theme)
:accessibility-label :success-icon}])
(when (= state :error)
[icon/icon :i/incorrect
{:color (colors/theme-colors colors/danger-50 colors/danger-60 theme)
:accessibility-label :error-icon}])])
(def view (quo.theme/with-theme view-internal))
+2 -4
View File
@@ -80,7 +80,6 @@
quo.components.list-items.dapp.view
quo.components.list-items.menu-item
quo.components.list-items.preview-list.view
quo.components.list-items.quiz-item.view
quo.components.list-items.saved-address.view
quo.components.list-items.saved-contact-address.view
quo.components.list-items.token-network.view
@@ -297,16 +296,15 @@
(def account-list-card quo.components.list-items.account-list-card.view/view)
(def address quo.components.list-items.address.view/view)
(def channel quo.components.list-items.channel.view/view)
(def community-list-item quo.components.list-items.community.view/view)
(def dapp quo.components.list-items.dapp.view/view)
(def menu-item quo.components.list-items.menu-item/menu-item)
(def preview-list quo.components.list-items.preview-list.view/view)
(def quiz-item quo.components.list-items.quiz-item.view/view)
(def user-list quo.components.list-items.user-list/user-list)
(def community-list-item quo.components.list-items.community.view/view)
(def saved-address quo.components.list-items.saved-address.view/view)
(def saved-contact-address quo.components.list-items.saved-contact-address.view/view)
(def token-network quo.components.list-items.token-network.view/view)
(def token-value quo.components.list-items.token-value.view/view)
(def user-list quo.components.list-items.user-list/user-list)
;;;; Loaders
(def skeleton-list quo.components.loaders.skeleton-list.view/view)
-1
View File
@@ -47,7 +47,6 @@
quo.components.list-items.channel.component-spec
quo.components.list-items.community.component-spec
quo.components.list-items.dapp.component-spec
quo.components.list-items.quiz-item.component-spec
quo.components.list-items.saved-address.component-spec
quo.components.list-items.saved-contact-address.component-spec
quo.components.list-items.token-network.component-spec
-3
View File
@@ -203,9 +203,6 @@
(def danger-50-opa-30 (alpha danger-50 0.3))
(def danger-50-opa-40 (alpha danger-50 0.4))
;;60 with transparency
(def danger-60-opa-10 (alpha danger-60 0.1))
;;;;Warning
(def warning-50 "#FF7D46")
(def warning-60 "#CC6438")
+1 -1
View File
@@ -8,8 +8,8 @@
[status-im.config :as config]
[status-im.constants :as constants]
[status-im.contexts.chat.actions.view :as chat-actions]
[status-im.contexts.chat.contacts.drawers.nickname-drawer.view :as nickname-drawer]
[status-im.contexts.communities.actions.chat.view :as communities-chat-actions]
[status-im.contexts.contacts.drawers.nickname-drawer.view :as nickname-drawer]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
+6 -12
View File
@@ -180,11 +180,6 @@
app-state-listener (.addEventListener rn/app-state "change" set-torch-off-fn)]
#(.remove app-state-listener)))
(defn- navigate-back-handler
[]
(rf/dispatch [:navigate-back])
true)
(defn f-view-internal
[{:keys [title subtitle validate-fn on-success-scan error-message]}]
(let [insets (safe-area/get-insets)
@@ -202,16 +197,15 @@
(boolean (not-empty @qr-view-finder)))
camera-ready-to-scan? (and show-camera?
(not @qr-code-succeed?))]
(rn/use-effect
#(set-listener-torch-off-on-app-inactive torch?))
(rn/use-effect
(fn []
(rn/hw-back-add-listener navigate-back-handler)
(set-listener-torch-off-on-app-inactive torch?)
(when-not @camera-permission-granted?
(permissions/permission-granted?
:camera
#(reset! camera-permission-granted? %)
#(reset! camera-permission-granted? false)))
#(rn/hw-back-remove-listener navigate-back-handler)))
(permissions/permission-granted? :camera
#(reset! camera-permission-granted? %)
#(reset! camera-permission-granted? false)))))
[:<>
[rn/view {:style style/background}]
(when camera-ready-to-scan?
+1 -1
View File
@@ -9,7 +9,7 @@
[status-im.contexts.chat.messages.transport.events :as messages.transport]
[status-im.contexts.communities.discover.events]
[status-im.contexts.profile.login.events :as profile.login]
[status-im.contexts.profile.push-notifications.local.events :as local-notifications]
[status-im.contexts.push-notifications.local.events :as local-notifications]
[taoensso.timbre :as log]
[utils.re-frame :as rf]
[utils.transforms :as transforms]))
@@ -1,4 +1,4 @@
(ns status-im.contexts.chat.home.add-new-contact.effects
(ns status-im.contexts.add-new-contact.effects
(:require
[legacy.status-im.ethereum.ens :as ens]
[native-module.core :as native-module]
@@ -1,9 +1,9 @@
(ns status-im.contexts.chat.home.add-new-contact.events
(ns status-im.contexts.add-new-contact.events
(:require
[clojure.string :as string]
[status-im.common.validators :as validators]
[status-im.contexts.chat.contacts.events :as data-store.contacts]
status-im.contexts.chat.home.add-new-contact.effects
status-im.contexts.add-new-contact.effects
[status-im.contexts.contacts.events :as data-store.contacts]
[status-im.navigation.events :as navigation]
[utils.ens.stateofus :as stateofus]
[utils.ethereum.chain :as chain]
@@ -1,8 +1,8 @@
(ns status-im.contexts.chat.home.add-new-contact.events-test
(ns status-im.contexts.add-new-contact.events-test
(:require
[cljs.test :refer-macros [deftest are]]
matcher-combinators.test
[status-im.contexts.chat.home.add-new-contact.events :as events]))
[status-im.contexts.add-new-contact.events :as events]))
(def user-ukey
"0x04ca27ed9c7c4099d230c6d8853ad0cfaf084a019c543e9e433d3c04fac6de9147cf572b10e247cfe52f396b5aa10456b56dd1cf1d8a681e2b93993d44594b2e85")
@@ -1,4 +1,4 @@
(ns status-im.contexts.chat.home.add-new-contact.scan.scan-profile-qr-page
(ns status-im.contexts.add-new-contact.scan.scan-profile-qr-page
(:require [react-native.core :as rn]
[react-native.hooks :as hooks]
[status-im.common.scan-qr-code.view :as scan-qr-code]
@@ -1,4 +1,4 @@
(ns status-im.contexts.chat.home.add-new-contact.style
(ns status-im.contexts.add-new-contact.style
(:require [quo.foundations.colors :as colors]
[react-native.safe-area :as safe-area]))
@@ -1,10 +1,10 @@
(ns status-im.contexts.chat.home.add-new-contact.views
(ns status-im.contexts.add-new-contact.views
(:require [clojure.string :as string]
[quo.core :as quo]
[react-native.clipboard :as clipboard]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.contexts.chat.home.add-new-contact.style :as style]
[status-im.contexts.add-new-contact.style :as style]
[utils.address :as address]
[utils.debounce :as debounce]
[utils.i18n :as i18n]
+1 -1
View File
@@ -8,13 +8,13 @@
[status-im.common.muting.helpers :refer [format-mute-till]]
[status-im.constants :as constants]
[status-im.contexts.chat.composer.link-preview.events :as link-preview]
[status-im.contexts.chat.contacts.events :as contacts-store]
status-im.contexts.chat.effects
status-im.contexts.chat.lightbox.events
status-im.contexts.chat.messages.content.reactions.events
[status-im.contexts.chat.messages.delete-message-for-me.events :as delete-for-me]
[status-im.contexts.chat.messages.delete-message.events :as delete-message]
[status-im.contexts.chat.messages.list.state :as chat.state]
[status-im.contexts.contacts.events :as contacts-store]
[status-im.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.datetime :as datetime]
@@ -64,10 +64,9 @@
:use-case (when pinned-by :pinned)
:on-press #(on-press (assoc % :message-id message-id))
:on-long-press #(on-long-press (assoc %
:message-id message-id
:theme theme
:reactions-order (map :emoji-id reactions)
:user-message-content user-message-content))
:message-id message-id
:theme theme
:reactions-order (map :emoji-id reactions)))
:on-press-add #(on-press-add {:chat-id chat-id
:message-id message-id
:user-message-content user-message-content})}])]))
@@ -14,11 +14,11 @@
[legacy.status-im.visibility-status-updates.core :as models.visibility-status-updates]
[legacy.status-im.wallet.core :as wallet]
[status-im.constants :as constants]
[status-im.contexts.chat.contacts.events :as models.contact]
[status-im.contexts.chat.events :as chat.events]
[status-im.contexts.chat.messages.content.reactions.events :as reactions]
[status-im.contexts.chat.messages.pin.events :as messages.pin]
[status-im.contexts.communities.events :as communities]
[status-im.contexts.contacts.events :as models.contact]
[status-im.contexts.shell.activity-center.events :as activity-center]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
@@ -13,7 +13,8 @@
;; NOTE(parvesh) - I am working on refactoring/optimization of the chat screen for performance
;; improvement. Please avoid refactoring these files. Also if you are not already working on bug
;; fixes related to the composer, please skip them. And ping me, so I can address them while refactoring
;; fixes related to the chat navigation bar, please skip them.
;; And ping me, so I can address them while refactoring
(defn- f-chat-screen
[calculations-complete?]
(let [insets (safe-area/get-insets)
@@ -46,8 +47,6 @@
(defn lazy-chat-screen
[calculations-complete?]
(let [screen-loaded? (rf/sub [:shell/chat-screen-loaded?])]
(when-not screen-loaded?
(reanimated/set-shared-value calculations-complete? false))
(when screen-loaded?
[:f> f-chat-screen calculations-complete?])))
@@ -1,4 +1,4 @@
(ns status-im.contexts.chat.contacts.drawers.nickname-drawer.style
(ns status-im.contexts.contacts.drawers.nickname-drawer.style
(:require
[quo.foundations.colors :as colors]
[react-native.platform :as platform]))
@@ -1,4 +1,4 @@
(ns status-im.contexts.chat.contacts.drawers.nickname-drawer.view
(ns status-im.contexts.contacts.drawers.nickname-drawer.view
(:require
[clojure.string :as string]
[quo.core :as quo]
@@ -7,7 +7,7 @@
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[status-im.constants :as constants]
[status-im.contexts.chat.contacts.drawers.nickname-drawer.style :as style]
[status-im.contexts.contacts.drawers.nickname-drawer.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@@ -1,4 +1,4 @@
(ns status-im.contexts.chat.contacts.events
(ns status-im.contexts.contacts.events
(:require
[oops.core :as oops]
[status-im.constants :as constants]
@@ -1,4 +1,4 @@
(ns status-im.common.emoji-picker.constants
(ns status-im.contexts.emoji-picker.constants
(:require
[react-native.core :as rn]))
@@ -1,6 +1,6 @@
(ns status-im.common.emoji-picker.data
(ns status-im.contexts.emoji-picker.data
(:require
[status-im.common.emoji-picker.constants :as constants]
[status-im.contexts.emoji-picker.constants :as constants]
[utils.transforms :as transforms]))
;; Emoji data is pulled from the `emojibase` (https://emojibase.dev).
@@ -1,4 +1,4 @@
(ns status-im.common.emoji-picker.events
(ns status-im.contexts.emoji-picker.events
(:require
[utils.re-frame :as rf]))
@@ -1,8 +1,8 @@
(ns status-im.common.emoji-picker.style
(ns status-im.contexts.emoji-picker.style
(:require
[quo.foundations.colors :as colors]
[react-native.safe-area :as safe-area]
[status-im.common.emoji-picker.constants :as constants]))
[status-im.contexts.emoji-picker.constants :as constants]))
(def flex-spacer {:flex 1})
@@ -1,8 +1,8 @@
(ns status-im.common.emoji-picker.utils
(ns status-im.contexts.emoji-picker.utils
(:require
[clojure.string :as string]
[status-im.common.emoji-picker.constants :as constants]
[status-im.common.emoji-picker.data :refer [emoji-data]]))
[status-im.contexts.emoji-picker.constants :as constants]
[status-im.contexts.emoji-picker.data :refer [emoji-data]]))
(defn search-emoji
[search-query]
@@ -1,7 +1,7 @@
(ns status-im.common.emoji-picker.utils-test
(ns status-im.contexts.emoji-picker.utils-test
(:require
[cljs.test :refer [deftest is testing]]
[status-im.common.emoji-picker.utils :as utils]))
[status-im.contexts.emoji-picker.utils :as utils]))
(deftest emoji-search-test
(testing "search for emojis with name"
@@ -1,4 +1,4 @@
(ns status-im.common.emoji-picker.view
(ns status-im.contexts.emoji-picker.view
(:require
[clojure.string :as string]
[oops.core :as oops]
@@ -10,10 +10,10 @@
[react-native.gesture :as gesture]
[react-native.platform :as platform]
[reagent.core :as reagent]
[status-im.common.emoji-picker.constants :as constants]
[status-im.common.emoji-picker.data :as emoji-picker.data]
[status-im.common.emoji-picker.style :as style]
[status-im.common.emoji-picker.utils :as emoji-picker.utils]
[status-im.contexts.emoji-picker.constants :as constants]
[status-im.contexts.emoji-picker.data :as emoji-picker.data]
[status-im.contexts.emoji-picker.style :as style]
[status-im.contexts.emoji-picker.utils :as emoji-picker.utils]
[utils.debounce :as debounce]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@@ -1,9 +0,0 @@
(ns status-im.contexts.preview.quo.ios.drawer-bar
(:require
[quo.core :as quo]
[status-im.contexts.preview.quo.preview :as preview]))
(defn view
[]
[preview/preview-container {}
[quo/drawer-bar]])
@@ -1,28 +0,0 @@
(ns status-im.contexts.preview.quo.list-items.quiz-item
(:require [quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
(def descriptor
[{:key :state
:type :select
:options [{:key :empty}
{:key :disabled}
{:key :success}
{:key :error}]}
{:key :blur? :type :boolean}])
(defn view
[]
(let [state (reagent/atom {:state :empty
:word "collapse"
:number 8
:blur? false})]
(fn []
[preview/preview-container
{:state state
:descriptor descriptor
:blur? (:blur? @state)
:show-blur-background? true
:blur-dark-only? true}
[quo/quiz-item @state]])))
@@ -1,7 +1,7 @@
(ns status-im.contexts.profile.create.events
(:require
[native-module.core :as native-module]
[status-im.common.emoji-picker.utils :as emoji-picker.utils]
[status-im.contexts.emoji-picker.utils :as emoji-picker.utils]
[status-im.contexts.profile.config :as profile.config]
status-im.contexts.profile.create.effects
[utils.re-frame :as rf]
@@ -17,13 +17,13 @@
[status-im.common.universal-links :as universal-links]
[status-im.config :as config]
[status-im.constants :as constants]
[status-im.contexts.chat.contacts.events :as contacts]
[status-im.contexts.chat.messages.link-preview.events :as link-preview]
[status-im.contexts.contacts.events :as contacts]
[status-im.contexts.profile.config :as profile.config]
status-im.contexts.profile.login.effects
[status-im.contexts.profile.push-notifications.events :as notifications]
[status-im.contexts.profile.rpc :as profile.rpc]
[status-im.contexts.profile.settings.events :as profile.settings.events]
[status-im.contexts.push-notifications.events :as notifications]
[status-im.contexts.shell.activity-center.events :as activity-center]
[status-im.navigation.events :as navigation]
[taoensso.timbre :as log]
@@ -1,7 +1,7 @@
(ns status-im.contexts.profile.recover.events
(:require
[native-module.core :as native-module]
[status-im.common.emoji-picker.utils :as emoji-picker.utils]
[status-im.contexts.emoji-picker.utils :as emoji-picker.utils]
[status-im.contexts.profile.config :as profile.config]
status-im.contexts.profile.recover.effects
[utils.re-frame :as rf]
@@ -1,4 +1,4 @@
(ns status-im.contexts.profile.push-notifications.effects
(ns status-im.contexts.push-notifications.effects
(:require
[native-module.push-notifications :as native-module.pn]
[react-native.platform :as platform]
@@ -1,4 +1,4 @@
(ns status-im.contexts.profile.push-notifications.events
(ns status-im.contexts.push-notifications.events
(:require
[cljs-bean.core :as bean]
[native-module.push-notifications :as native-module.pn]
@@ -6,7 +6,7 @@
[react-native.platform :as platform]
[react-native.push-notification-ios :as pn-ios]
[status-im.config :as config]
status-im.contexts.profile.push-notifications.effects
status-im.contexts.push-notifications.effects
[taoensso.timbre :as log]
[utils.re-frame :as rf]
[utils.transforms :as transforms]))
@@ -1,4 +1,4 @@
(ns status-im.contexts.profile.push-notifications.local.effects
(ns status-im.contexts.push-notifications.local.effects
(:require
[cljs-bean.core :as bean]
[native-module.push-notifications :as native-module.pn]
@@ -1,8 +1,8 @@
(ns status-im.contexts.profile.push-notifications.local.events
(ns status-im.contexts.push-notifications.local.events
(:require
[legacy.status-im.notifications.wallet :as notifications.wallet]
[react-native.platform :as platform]
status-im.contexts.profile.push-notifications.local.effects
status-im.contexts.push-notifications.local.effects
[utils.re-frame :as rf]))
@@ -1,4 +1,4 @@
(ns status-im.contexts.preview.quo.animated-header-list.animated-header-list
(ns status-im.contexts.quo-preview.animated-header-list.animated-header-list
(:require
[quo.core :as quo]
[quo.foundations.colors :as colors]
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.avatars.account-avatar
(ns status-im.contexts.quo-preview.avatars.account-avatar
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]
[status-im.contexts.quo-preview.preview :as preview]
[utils.re-frame :as rf]))
(def descriptor
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.avatars.channel-avatar
(ns status-im.contexts.quo-preview.avatars.channel-avatar
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :size
@@ -1,10 +1,10 @@
(ns status-im.contexts.preview.quo.avatars.collection-avatar
(ns status-im.contexts.quo-preview.avatars.collection-avatar
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.common.resources :as resources]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :image
@@ -1,9 +1,9 @@
(ns status-im.contexts.preview.quo.avatars.group-avatar
(ns status-im.contexts.quo-preview.avatars.group-avatar
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.common.resources :as resources]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :size
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.avatars.icon-avatar
(ns status-im.contexts.quo-preview.avatars.icon-avatar
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :size
@@ -1,9 +1,9 @@
(ns status-im.contexts.preview.quo.avatars.user-avatar
(ns status-im.contexts.quo-preview.avatars.user-avatar
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.common.resources :as resources]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :size
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.avatars.wallet-user-avatar
(ns status-im.contexts.quo-preview.avatars.wallet-user-avatar
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :full-name
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.banners.banner
(ns status-im.contexts.quo-preview.banners.banner
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :latest-pin-text
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.browser.browser-input
(ns status-im.contexts.quo-preview.browser.browser-input
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :favicon? :type :boolean}
@@ -1,10 +1,10 @@
(ns status-im.contexts.preview.quo.buttons.button
(ns status-im.contexts.quo-preview.buttons.button
(:require
[quo.core :as quo]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.common.resources :as resources]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :type
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.buttons.composer-button
(ns status-im.contexts.quo-preview.buttons.composer-button
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :blur?
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.buttons.dynamic-button
(ns status-im.contexts.quo-preview.buttons.dynamic-button
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]
[status-im.contexts.quo-preview.preview :as preview]
[utils.i18n :as i18n]))
(def descriptor
@@ -1,9 +1,9 @@
(ns status-im.contexts.preview.quo.buttons.predictive-keyboard
(ns status-im.contexts.quo-preview.buttons.predictive-keyboard
(:require
[quo.core :as quo]
[quo.foundations.colors :as colors]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :type
@@ -1,9 +1,9 @@
(ns status-im.contexts.preview.quo.buttons.slide-button
(ns status-im.contexts.quo-preview.buttons.slide-button
(:require
[quo.core :as quo]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :size
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.buttons.wallet-button
(ns status-im.contexts.quo-preview.buttons.wallet-button
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :disabled? :type :boolean}])
@@ -1,7 +1,7 @@
(ns status-im.contexts.preview.quo.buttons.wallet-ctas
(ns status-im.contexts.quo-preview.buttons.wallet-ctas
(:require
[quo.core :as quo]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(defn view
[]
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.calendar.calendar
(ns status-im.contexts.quo-preview.calendar.calendar
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]
[status-im.contexts.quo-preview.preview :as preview]
[utils.datetime :as datetime]))
(def descriptor
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.calendar.calendar-day
(ns status-im.contexts.quo-preview.calendar.calendar-day
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[(preview/customization-color-option)
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.calendar.calendar-year
(ns status-im.contexts.quo-preview.calendar.calendar-year
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :selected? :type :boolean}
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.code.snippet
(ns status-im.contexts.quo-preview.code.snippet
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def go-example
"func (s *Server) listenAndServe() {
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.code.snippet-preview
(ns status-im.contexts.quo-preview.code.snippet-preview
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def go-example
"for(let ind")
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.colors.color
(ns status-im.contexts.quo-preview.colors.color
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[(preview/customization-color-option {:feng-shui? true})
@@ -1,9 +1,9 @@
(ns status-im.contexts.preview.quo.colors.color-picker
(ns status-im.contexts.quo-preview.colors.color-picker
(:require
[quo.core :as quo]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :blur?
@@ -1,4 +1,4 @@
(ns status-im.contexts.preview.quo.common
(ns status-im.contexts.quo-preview.common
(:require
[quo.core :as quo]
[quo.theme :as quo.theme]
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.community.channel-actions
(ns status-im.contexts.quo-preview.community.channel-actions
(:require
[quo.core :as quo]
[react-native.core :as rn]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(defn view
[]
@@ -1,9 +1,9 @@
(ns status-im.contexts.preview.quo.community.community-card-view
(ns status-im.contexts.quo-preview.community.community-card-view
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.common.resources :as resources]
[status-im.contexts.preview.quo.preview :as preview]
[status-im.contexts.quo-preview.preview :as preview]
[utils.i18n :as i18n]))
(def community-data
@@ -1,9 +1,9 @@
(ns status-im.contexts.preview.quo.community.community-membership-list-view
(ns status-im.contexts.quo-preview.community.community-membership-list-view
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.community.data :as data]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.community.data :as data]
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :notifications
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.community.community-stat
(ns status-im.contexts.quo-preview.community.community-stat
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :value
@@ -1,4 +1,4 @@
(ns status-im.contexts.preview.quo.community.data
(ns status-im.contexts.quo-preview.community.data
(:require
[status-im.common.resources :as resources]
[utils.i18n :as i18n]))
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.community.discover-card
(ns status-im.contexts.quo-preview.community.discover-card
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :title :type :text}
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.community.token-gating
(ns status-im.contexts.quo-preview.community.token-gating
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:label "Tokens sufficient?"
@@ -1,4 +1,4 @@
(ns status-im.contexts.preview.quo.component-preview.events
(ns status-im.contexts.quo-preview.component-preview.events
(:require
[quo.core :as quo]
[re-frame.core :as re-frame]))
@@ -1,4 +1,4 @@
(ns status-im.contexts.preview.quo.component-preview.view
(ns status-im.contexts.quo-preview.component-preview.view
(:require
[react-native.core :as rn]
[utils.re-frame :as rf]))
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.counter.counter
(ns status-im.contexts.quo-preview.counter.counter
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :type
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.counter.step
(ns status-im.contexts.quo-preview.counter.step
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :type
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.dividers.date
(ns status-im.contexts.quo-preview.dividers.date
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :label :type :text}])
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.dividers.divider-label
(ns status-im.contexts.quo-preview.dividers.divider-label
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :label
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.dividers.divider-line
(ns status-im.contexts.quo-preview.dividers.divider-line
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :blur?
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.dividers.new-messages
(ns status-im.contexts.quo-preview.dividers.new-messages
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :label
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.dividers.strength-divider
(ns status-im.contexts.quo-preview.dividers.strength-divider
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :type
@@ -1,9 +1,9 @@
(ns status-im.contexts.preview.quo.drawers.action-drawers
(ns status-im.contexts.quo-preview.drawers.action-drawers
(:require
[quo.core :as quo]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]
[status-im.contexts.quo-preview.preview :as preview]
[utils.re-frame :as rf]))
(def descriptor
@@ -1,8 +1,8 @@
(ns status-im.contexts.preview.quo.drawers.bottom-actions
(ns status-im.contexts.quo-preview.drawers.bottom-actions
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def button-two "Cancel")
(def button-one "Request to join")
@@ -1,10 +1,10 @@
(ns status-im.contexts.preview.quo.drawers.documentation-drawers
(ns status-im.contexts.quo-preview.drawers.documentation-drawers
(:require
[quo.core :as quo]
[quo.foundations.colors :as colors]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]
[status-im.contexts.quo-preview.preview :as preview]
[utils.re-frame :as rf]))
(def descriptor
@@ -1,9 +1,9 @@
(ns status-im.contexts.preview.quo.drawers.drawer-buttons
(ns status-im.contexts.quo-preview.drawers.drawer-buttons
(:require
[quo.core :as quo]
[quo.foundations.colors :as colors]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :top-heading
@@ -1,11 +1,11 @@
(ns status-im.contexts.preview.quo.drawers.drawer-top
(ns status-im.contexts.quo-preview.drawers.drawer-top
(:require
[quo.core :as quo]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.common.resources :as resources]
[status-im.contexts.preview.quo.preview :as preview]
[status-im.contexts.profile.utils :as profile.utils]
[status-im.contexts.quo-preview.preview :as preview]
[utils.re-frame :as rf]))
(def descriptor
@@ -1,4 +1,4 @@
(ns status-im.contexts.preview.quo.drawers.permission-drawers
(ns status-im.contexts.quo-preview.drawers.permission-drawers
(:require
[quo.core :as quo]
[quo.foundations.colors :as colors]
@@ -1,10 +1,10 @@
(ns status-im.contexts.preview.quo.dropdowns.dropdown
(ns status-im.contexts.quo-preview.dropdowns.dropdown
(:require
[quo.core :as quo]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.common.resources :as resources]
[status-im.contexts.preview.quo.preview :as preview]))
[status-im.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:key :type

Some files were not shown because too many files have changed in this diff Show More