diff --git a/android/app/build.gradle b/android/app/build.gradle
index 13d3259bf9..91fe9a7289 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -106,7 +106,7 @@ android {
defaultConfig {
applicationId "im.status.ethereum"
minSdkVersion 18
- targetSdkVersion 22
+ targetSdkVersion 23
versionCode getVersionCode()
versionName getVersionName()
ndk {
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index edf372426e..03f6175655 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -1,12 +1,31 @@
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/bots/console/bot.js b/bots/console/bot.js
index f4463508c8..4e9960030a 100644
--- a/bots/console/bot.js
+++ b/bots/console/bot.js
@@ -705,6 +705,14 @@ status.response({
}
});
+status.response({
+ name: "grant-permissions",
+ color: "#7099e6",
+ description: "Grant permissions",
+ icon: "lock_white",
+ executeImmediately: true
+});
+
status.addListener("on-message-input-change", function (params, context) {
return jsSuggestions({code: params.message}, context);
});
diff --git a/ios/StatusIm.xcodeproj/project.pbxproj b/ios/StatusIm.xcodeproj/project.pbxproj
index 84f8b6096f..e8134e35a9 100644
--- a/ios/StatusIm.xcodeproj/project.pbxproj
+++ b/ios/StatusIm.xcodeproj/project.pbxproj
@@ -53,7 +53,6 @@
9EE89E271E03FCB7007D3C25 /* libSplashScreen.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B24FC7F21DE718EF00D694FF /* libSplashScreen.a */; };
9EE89E2D1E03FD9F007D3C25 /* libimageCropPicker.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 20A5C9531D927137002C4965 /* libimageCropPicker.a */; };
A6AF670051B842249D520C7B /* Foundation.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7ED174A34D7D42358313368B /* Foundation.ttf */; };
- AD5063BC2B2A4C52ACE0A0B4 /* libUdpSockets.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A96279092BEC4C4B93914F48 /* libUdpSockets.a */; };
AE97D4B08C9F4821B8E9C50B /* Ionicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 359B076A658B4FBAB5128B03 /* Ionicons.ttf */; };
B23B48FF1E76917B006D4535 /* RobotoMono-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = B23B48FE1E76917B006D4535 /* RobotoMono-Medium.ttf */; };
B24FC7FD1DE7195700D694FF /* Social.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B24FC7FC1DE7195700D694FF /* Social.framework */; };
@@ -143,13 +142,6 @@
remoteGlobalIDString = 134814201AA4EA6300B7C361;
remoteInfo = TcpSockets;
};
- 201067711D477F5E00FA83B6 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 2F0276A9E90843E996A0E762 /* UdpSockets.xcodeproj */;
- proxyType = 2;
- remoteGlobalIDString = 134814201AA4EA6300B7C361;
- remoteInfo = UdpSockets;
- };
201067C31D4789F700FA83B6 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 439B6B4B407A4E2AACAFE5BE /* RCTStatus.xcodeproj */;
@@ -452,7 +444,6 @@
20B6B6861D92C42600CC5C6A /* QBImagePicker.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = QBImagePicker.framework; sourceTree = BUILT_PRODUCTS_DIR; };
2756305FAFF144C4A6B0A039 /* Zocial.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Zocial.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Zocial.ttf"; sourceTree = ""; };
2BEE3436791D42248F853999 /* libRCTImageResizer.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRCTImageResizer.a; sourceTree = ""; };
- 2F0276A9E90843E996A0E762 /* UdpSockets.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = UdpSockets.xcodeproj; path = "../node_modules/react-native-udp/ios/UdpSockets.xcodeproj"; sourceTree = ""; };
305F194186D848FDB07AF34C /* RNFS.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNFS.xcodeproj; path = "../node_modules/react-native-fs/RNFS.xcodeproj"; sourceTree = ""; };
359B076A658B4FBAB5128B03 /* Ionicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Ionicons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Ionicons.ttf"; sourceTree = ""; };
38A44830EC5708E89387F641 /* Pods-StatusIm.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-StatusIm.release.xcconfig"; path = "Pods/Target Support Files/Pods-StatusIm/Pods-StatusIm.release.xcconfig"; sourceTree = ""; };
@@ -486,7 +477,6 @@
9ED2F45D1D9D52DD00B36508 /* SF-UI-Text-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SF-UI-Text-Regular.otf"; sourceTree = ""; };
9ED2F4601D9D577B00B36508 /* SF-UI-Text-Bold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SF-UI-Text-Bold.otf"; sourceTree = ""; };
9F1854E6D9654226B1FC8308 /* RCTCamera.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RCTCamera.xcodeproj; path = "../node_modules/react-native-camera/ios/RCTCamera.xcodeproj"; sourceTree = ""; };
- A96279092BEC4C4B93914F48 /* libUdpSockets.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libUdpSockets.a; sourceTree = ""; };
ACA66A8F16CD2FE21F38738B /* Pods-StatusIm.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-StatusIm.debug.xcconfig"; path = "Pods/Target Support Files/Pods-StatusIm/Pods-StatusIm.debug.xcconfig"; sourceTree = ""; };
B23B48FE1E76917B006D4535 /* RobotoMono-Medium.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "RobotoMono-Medium.ttf"; sourceTree = ""; };
B24FC7FC1DE7195700D694FF /* Social.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Social.framework; path = System/Library/Frameworks/Social.framework; sourceTree = SDKROOT; };
@@ -554,7 +544,6 @@
25DC9C9DC25846BD8D084888 /* libc++.tbd in Frameworks */,
BA68A2377A20496EA737000D /* libz.tbd in Frameworks */,
3E15DFEC1F6F4D7CAE088F49 /* libTcpSockets.a in Frameworks */,
- AD5063BC2B2A4C52ACE0A0B4 /* libUdpSockets.a in Frameworks */,
E0AD9E8F495A4907B65104BF /* libRCTImageResizer.a in Frameworks */,
5F8585D411844E5981B94F40 /* libRNInstabug.a in Frameworks */,
8E55E6877F950B81C8D711C5 /* libPods-StatusIm.a in Frameworks */,
@@ -695,14 +684,6 @@
name = Products;
sourceTree = "";
};
- 2010676E1D477F5E00FA83B6 /* Products */ = {
- isa = PBXGroup;
- children = (
- 201067721D477F5E00FA83B6 /* libUdpSockets.a */,
- );
- name = Products;
- sourceTree = "";
- };
201067BA1D4789F700FA83B6 /* Products */ = {
isa = PBXGroup;
children = (
@@ -857,7 +838,6 @@
8AE71EE8751F4652B13BFE83 /* RNVectorIcons.xcodeproj */,
F090E261B9854867A728CE4F /* RealmReact.xcodeproj */,
38E1A2C8D0734EE99E2B16CE /* TcpSockets.xcodeproj */,
- 2F0276A9E90843E996A0E762 /* UdpSockets.xcodeproj */,
439B6B4B407A4E2AACAFE5BE /* RCTStatus.xcodeproj */,
5E5A7625B76441D984EA8C0D /* RCTImageResizer.xcodeproj */,
F3548417D8DA4362B6796A54 /* RNInstabug.xcodeproj */,
@@ -1181,10 +1161,6 @@
ProductGroup = 201067551D477F5E00FA83B6 /* Products */;
ProjectRef = 38E1A2C8D0734EE99E2B16CE /* TcpSockets.xcodeproj */;
},
- {
- ProductGroup = 2010676E1D477F5E00FA83B6 /* Products */;
- ProjectRef = 2F0276A9E90843E996A0E762 /* UdpSockets.xcodeproj */;
- },
);
projectRoot = "";
targets = (
@@ -1258,13 +1234,6 @@
remoteRef = 2010676C1D477F5E00FA83B6 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
- 201067721D477F5E00FA83B6 /* libUdpSockets.a */ = {
- isa = PBXReferenceProxy;
- fileType = archive.ar;
- path = libUdpSockets.a;
- remoteRef = 201067711D477F5E00FA83B6 /* PBXContainerItemProxy */;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
201067C41D4789F700FA83B6 /* libRCTStatus.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
@@ -1813,7 +1782,6 @@
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
"$(SRCROOT)/../node_modules/realm/src/**",
"$(SRCROOT)/../node_modules/react-native-tcp/ios/**",
- "$(SRCROOT)/../node_modules/react-native-udp/ios/**",
"$(SRCROOT)/../modules/react-native-status/ios/RCTStatus/**",
"$(SRCROOT)/../node_modules/react-native-image-resizer/ios/RCTImageResizer",
"$(SRCROOT)/../node_modules/instabug-reactnative/ios/RNInstabug",
@@ -1863,7 +1831,6 @@
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
"$(SRCROOT)/../node_modules/realm/src/**",
"$(SRCROOT)/../node_modules/react-native-tcp/ios/**",
- "$(SRCROOT)/../node_modules/react-native-udp/ios/**",
"$(SRCROOT)/../modules/react-native-status/ios/RCTStatus/**",
"$(SRCROOT)/../node_modules/react-native-image-resizer/ios/RCTImageResizer",
"$(SRCROOT)/../node_modules/instabug-reactnative/ios/RNInstabug",
@@ -1934,7 +1901,6 @@
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
"$(SRCROOT)/../node_modules/realm/src/**",
"$(SRCROOT)/../node_modules/react-native-tcp/ios/**",
- "$(SRCROOT)/../node_modules/react-native-udp/ios/**",
"$(SRCROOT)/../modules/react-native-status/ios/RCTStatus/**",
"$(SRCROOT)/../modules/react-native-status/ios/RCTStatus/**",
"$(SRCROOT)/../node_modules/react-native-image-resizer/ios/RCTImageResizer",
@@ -1993,7 +1959,6 @@
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
"$(SRCROOT)/../node_modules/realm/src/**",
"$(SRCROOT)/../node_modules/react-native-tcp/ios/**",
- "$(SRCROOT)/../node_modules/react-native-udp/ios/**",
"$(SRCROOT)/../modules/react-native-status/ios/RCTStatus/**",
"$(SRCROOT)/../modules/react-native-status/ios/RCTStatus/**",
"$(SRCROOT)/../node_modules/react-native-image-resizer/ios/RCTImageResizer",
diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusModule.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusModule.java
index a0e1503fe0..1564c59775 100644
--- a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusModule.java
+++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusModule.java
@@ -14,6 +14,10 @@ import com.github.status_im.status_go.cmd.Statusgo;
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.OutputStream;
+import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
@@ -103,10 +107,7 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
Activity currentActivity = getCurrentActivity();
- File extStore = Environment.getExternalStorageDirectory();
- String dataFolder = extStore.exists() ?
- extStore.getAbsolutePath() + "/ethereum/testnet" :
- currentActivity.getApplicationInfo().dataDir + "/ethereum/testnet";
+ String dataFolder = currentActivity.getApplicationInfo().dataDir + "/ethereum/testnet";
Log.d(TAG, "Starting Geth node in folder: " + dataFolder);
try {
@@ -158,6 +159,86 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
Log.d(TAG, "Geth node started");
}
+ private String getOldExternalDir() {
+ File extStore = Environment.getExternalStorageDirectory();
+ return extStore.exists() ? extStore.getAbsolutePath() + "/ethereum/testnet" : getNewInternalDir();
+ }
+
+ private String getNewInternalDir() {
+ Activity currentActivity = getCurrentActivity();
+ return currentActivity.getApplicationInfo().dataDir + "/ethereum/testnet";
+ }
+
+ private void deleteDirectory(File folder) {
+ File[] files = folder.listFiles();
+ if (files != null) {
+ for (File f : files) {
+ if (f.isDirectory()) {
+ deleteDirectory(f);
+ } else {
+ f.delete();
+ }
+ }
+ }
+ folder.delete();
+ }
+
+ 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();
+ }
+ }
+
+ @ReactMethod
+ public void shouldMoveToInternalStorage(Callback callback) {
+ String oldDir = getOldExternalDir();
+ String newDir = getNewInternalDir();
+
+ File oldDirFile = new File(oldDir);
+ File newDirFile = new File(newDir);
+
+ callback.invoke(oldDirFile.exists() && !newDirFile.exists());
+ }
+
+ @ReactMethod
+ public void moveToInternalStorage(Callback callback) {
+ String oldDir = getOldExternalDir();
+ String newDir = getNewInternalDir();
+
+ try {
+ File oldDirFile = new File(oldDir);
+ copyDirectory(oldDirFile, new File(newDir));
+ deleteDirectory(oldDirFile);
+ } catch (IOException e) {
+ Log.d(TAG, "Moving error: " + e);
+ }
+
+ callback.invoke();
+ }
+
@ReactMethod
public void startNode(Callback callback) {
Log.d(TAG, "startNode");
diff --git a/modules/react-native-status/ios/RCTStatus/RCTStatus.m b/modules/react-native-status/ios/RCTStatus/RCTStatus.m
index 2b0ae1d895..90dbc22676 100644
--- a/modules/react-native-status/ios/RCTStatus/RCTStatus.m
+++ b/modules/react-native-status/ios/RCTStatus/RCTStatus.m
@@ -185,6 +185,22 @@ RCT_EXPORT_METHOD(startNode:(RCTResponseSenderBlock)onResultCallback) {
}
}
+////////////////////////////////////////////////////////////////////
+#pragma mark - shouldMoveToInternalStorage
+//////////////////////////////////////////////////////////////////// shouldMoveToInternalStorage
+RCT_EXPORT_METHOD(shouldMoveToInternalStorage:(RCTResponseSenderBlock)onResultCallback) {
+ // Android only
+ onResultCallback(@[[NSNull null]]);
+}
+
+////////////////////////////////////////////////////////////////////
+#pragma mark - moveToInternalStorage
+//////////////////////////////////////////////////////////////////// moveToInternalStorage
+RCT_EXPORT_METHOD(moveToInternalStorage:(RCTResponseSenderBlock)onResultCallback) {
+ // Android only
+ onResultCallback(@[[NSNull null]]);
+}
+
////////////////////////////////////////////////////////////////////
#pragma mark - StartNodeRPCServer method
//////////////////////////////////////////////////////////////////// createAccount
diff --git a/package.json b/package.json
index 02535c727b..61707e294f 100644
--- a/package.json
+++ b/package.json
@@ -75,7 +75,7 @@
"react-native-udp": "^2.0.0",
"react-native-vector-icons": "^4.0.1",
"react-native-webview-bridge": "github:status-im/react-native-webview-bridge#0.33.12",
- "readable-stream": "^1.0.33",
+ "readable-stream": "1.0.33",
"realm": "^0.14.3",
"stream-browserify": "^1.0.0",
"string_decoder": "^0.10.31",
diff --git a/postinstall.sh b/postinstall.sh
index 31f6436159..a933169e9e 100755
--- a/postinstall.sh
+++ b/postinstall.sh
@@ -2,10 +2,9 @@
# rn-nodeify
# temporary hack due to https://github.com/facebook/react-native/issues/4968
-./node_modules/.bin/rn-nodeify --install --hack;
+./node_modules/.bin/rn-nodeify --install "assert,zlib,buffer,inherits,console,constants,crypto,dns,domain,events,http,https,os,path,process,punycode,querystring,fs,stream,string_decoder,timers,tty,url,util,net,vm" --hack;
npm install --save react@16.0.0-alpha.6;
npm install --save react-native-tcp@3.2.1;
-npm install --save react-native-udp@2.0.0;
# symlink for re-natal
if ! [ -f re-natal ]; then
diff --git a/resources/status.js b/resources/status.js
index 42fcb2cd78..39b43c1588 100644
--- a/resources/status.js
+++ b/resources/status.js
@@ -37,6 +37,7 @@ Command.prototype.create = function (com) {
this["on-send"] = com.onSend;
this.fullscreen = com.fullscreen;
this.request = com.request;
+ this["execute-immediately?"] = com.executeImmediately;
this["sequential-params"] = com.sequentialParams;
this.addToCatalog();
diff --git a/src/status_im/chat/constants.cljs b/src/status_im/chat/constants.cljs
index a810f96803..9bfee170d5 100644
--- a/src/status_im/chat/constants.cljs
+++ b/src/status_im/chat/constants.cljs
@@ -3,7 +3,6 @@
(def command-char "/")
(def spacing-char " ")
(def arg-wrapping-char "\"")
-(def masking-char "*")
(def bot-char "@")
(def input-height 56)
@@ -11,6 +10,7 @@
(def input-spacing-top 16)
(def crazy-math-message-id "crazy-math-message")
+(def move-to-internal-failure-message-id "move-to-internal-failure-message")
(def passphrase-message-id "passphraze-message")
(def intro-status-message-id "intro-status")
(def intro-message1-id "intro-message1")
diff --git a/src/status_im/chat/handlers.cljs b/src/status_im/chat/handlers.cljs
index ac987341f2..f5c32eb479 100644
--- a/src/status_im/chat/handlers.cljs
+++ b/src/status_im/chat/handlers.cljs
@@ -132,26 +132,42 @@
(when-not (messages/get-by-id chat-consts/passphrase-message-id)
(sign-up-service/account-generation-message)))))
+(register-handler :move-to-internal-failure-message
+ (u/side-effect!
+ (fn [_]
+ (when-not (messages/get-by-id chat-consts/move-to-internal-failure-message-id)
+ (sign-up-service/move-to-internal-failure-message)))))
+
(register-handler :show-mnemonic
(u/side-effect!
(fn [_ [_ mnemonic]]
(let [crazy-math-message? (messages/get-by-id chat-consts/crazy-math-message-id)]
(sign-up-service/passphrase-messages mnemonic crazy-math-message?)))))
+(defn- handle-sms [{body :body}]
+ (when-let [matches (re-matches #"(\d{4})" body)]
+ (dispatch [:sign-up-confirm (second matches)])))
+
(register-handler :sign-up
(after (fn [_ [_ phone-number]]
(dispatch [:account-update {:phone phone-number}])))
(fn [db [_ phone-number message-id]]
+ (sign-up-service/start-listening-confirmation-code-sms)
(let [formatted (format-phone-number phone-number)]
(-> db
(assoc :user-phone-number formatted)
- sign-up-service/start-listening-confirmation-code-sms
(server/sign-up formatted
message-id
sign-up-service/on-sign-up-response)))))
+(register-handler :start-listening-confirmation-code-sms
+ (fn [db [_ listener]]
+ (if-not (:confirmation-code-sms-listener db)
+ (assoc db :confirmation-code-sms-listener listener)
+ db)))
+
(register-handler :stop-listening-confirmation-code-sms
- (fn [db [_]]
+ (fn [db]
(if (:confirmation-code-sms-listener db)
(sign-up-service/stop-listening-confirmation-code-sms db)
db)))
diff --git a/src/status_im/chat/handlers/commands.cljs b/src/status_im/chat/handlers/commands.cljs
index 7a1344cdad..2d88bbabc3 100644
--- a/src/status_im/chat/handlers/commands.cljs
+++ b/src/status_im/chat/handlers/commands.cljs
@@ -35,3 +35,13 @@
(dispatch [:set-in [:message-data data-type message-id] result])
(when on-requested (on-requested result)))]
(status/call-jail jail-id path params callback)))))))
+
+(handlers/register-handler :execute-command-immediately
+ (handlers/side-effect!
+ (fn [_ [_ {command-name :name :as command}]]
+ (case (keyword command-name)
+ :grant-permissions
+ (dispatch [:request-permissions
+ [:read-external-storage]
+ #(dispatch [:initialize-geth])])
+ (log/debug "ignoring command: " command)))))
diff --git a/src/status_im/chat/handlers/input.cljs b/src/status_im/chat/handlers/input.cljs
index 58510d09df..3c58c482e4 100644
--- a/src/status_im/chat/handlers/input.cljs
+++ b/src/status_im/chat/handlers/input.cljs
@@ -97,7 +97,9 @@
(fn [{:keys [current-chat-id] :as db} [_ chat-id text]]
(let [chat-id (or chat-id current-chat-id)
chat-text (or text (get-in db [:chats chat-id :input-text]) "")
- requests (suggestions/get-request-suggestions db chat-text)
+ requests (->> (suggestions/get-request-suggestions db chat-text)
+ (remove (fn [{:keys [type]}]
+ (= type :grant-permissions))))
suggestions (suggestions/get-command-suggestions db chat-text)
global-commands (suggestions/get-global-command-suggestions db chat-text)
{:keys [dapp?]} (get-in db [:contacts chat-id])]
diff --git a/src/status_im/chat/sign_up.cljs b/src/status_im/chat/sign_up.cljs
index bed1ef6256..a2ae49677d 100644
--- a/src/status_im/chat/sign_up.cljs
+++ b/src/status_im/chat/sign_up.cljs
@@ -42,14 +42,15 @@
:from console-chat-id
:to "me"}])))
-(defn handle-sms [{body :body}]
- (when-let [matches (re-matches #"(\d{4})" body)]
- (dispatch [:sign-up-confirm (second matches)])))
-
-(defn start-listening-confirmation-code-sms [db]
- (if-not (:confirmation-code-sms-listener db)
- (assoc db :confirmation-code-sms-listener (add-sms-listener handle-sms))
- db))
+(defn start-listening-confirmation-code-sms []
+ (dispatch [:request-permissions
+ [:receive-sms]
+ (fn []
+ (let [listener (add-sms-listener
+ (fn [{body :body}]
+ (when-let [matches (re-matches #"(\d{4})" body)]
+ (dispatch [:sign-up-confirm (second matches)]))))]
+ (dispatch [:start-listening-confirmation-code-sms listener])))]))
(defn stop-listening-confirmation-code-sms [db]
(when-let [listener (:confirmation-code-sms-listener db)]
@@ -70,7 +71,9 @@
(defn sync-contacts []
;; TODO 'on-sync-contacts' is never called
- (dispatch [:sync-contacts on-sync-contacts]))
+ (dispatch [:request-permissions
+ [:read-contacts]
+ #(dispatch [:sync-contacts on-sync-contacts])]))
(defn on-send-code-response [body]
(dispatch [:received-message
@@ -122,6 +125,18 @@
:from console-chat-id
:to "me"}]))
+(defn move-to-internal-failure-message []
+ (dispatch [:received-message
+ {:message-id const/move-to-internal-failure-message-id
+ :content (command-content
+ :grant-permissions
+ (label :t/move-to-internal-failure-message))
+ :content-type content-type-command-request
+ :outgoing false
+ :chat-id console-chat-id
+ :from console-chat-id
+ :to "me"}]))
+
(defn passphrase-messages [mnemonic crazy-math-message?]
(dispatch [:received-message
{:message-id const/passphrase-message-id
diff --git a/src/status_im/chat/views/message/request_message.cljs b/src/status_im/chat/views/message/request_message.cljs
index 43975177a8..b50419ae27 100644
--- a/src/status_im/chat/views/message/request_message.cljs
+++ b/src/status_im/chat/views/message/request_message.cljs
@@ -56,11 +56,13 @@
:component-will-unmount
#(reset! loop? false)
:reagent-render
- (fn [message-id {command-icon :icon :as command} status-initialized?]
+ (fn [message-id {:keys [execute-immediately?] command-icon :icon :as command} status-initialized?]
(when command
[touchable-highlight
- {:on-press (when (and (not @answered?) status-initialized?)
- #(set-chat-command message-id command))
+ {:on-press (if execute-immediately?
+ #(dispatch [:execute-command-immediately command])
+ (when (and (not @answered?) status-initialized?)
+ #(set-chat-command message-id command)))
:style (st/command-request-image-touchable)
:accessibility-label (id/chat-request-message-button (:name command))}
[animated-view {:style (st/command-request-image-view command scale-anim-val)}
diff --git a/src/status_im/components/permissions.cljs b/src/status_im/components/permissions.cljs
new file mode 100644
index 0000000000..001dac5875
--- /dev/null
+++ b/src/status_im/components/permissions.cljs
@@ -0,0 +1,24 @@
+(ns status-im.components.permissions
+ (:require [taoensso.timbre :as log]))
+
+(def permissions-class (.-PermissionsAndroid js/ReactNative))
+
+(def permissions-map
+ {:read-external-storage "android.permission.READ_EXTERNAL_STORAGE"
+ :write-external-storage "android.permission.WRITE_EXTERNAL_STORAGE"
+ :read-contacts "android.permission.READ_CONTACTS"
+ :camera "android.permission.CAMERA"
+ :receive-sms "android.permission.RECEIVE_SMS"})
+
+(defn all-granted? [permissions]
+ (let [permission-vals (distinct (vals permissions))]
+ (and (= (count permission-vals) 1)
+ (not= (first permission-vals) "denied"))))
+
+(defn request-permissions [permissions then else]
+ (let [permissions (mapv #(get permissions-map %) permissions)
+ result (.requestMultiple permissions-class (clj->js permissions))
+ result (.then result #(if (all-granted? (js->clj %))
+ (then)
+ (when else (else))))
+ result (.catch result #(else))]))
\ No newline at end of file
diff --git a/src/status_im/components/status.cljs b/src/status_im/components/status.cljs
index a61ba717c3..69904cd784 100644
--- a/src/status_im/components/status.cljs
+++ b/src/status_im/components/status.cljs
@@ -61,6 +61,14 @@
(.addListener r/device-event-emitter "gethEvent"
#(dispatch [:signal-event (.-jsonEvent %)])))
+(defn should-move-to-internal-storage? [on-result]
+ (when status
+ (call-module #(.shouldMoveToInternalStorage status on-result))))
+
+(defn move-to-internal-storage [on-result]
+ (when status
+ (call-module #(.moveToInternalStorage status on-result))))
+
(defn start-node [on-result]
(when status
(call-module #(.startNode status on-result))))
diff --git a/src/status_im/handlers.cljs b/src/status_im/handlers.cljs
index d5c854d532..ef303951ab 100644
--- a/src/status_im/handlers.cljs
+++ b/src/status_im/handlers.cljs
@@ -6,6 +6,7 @@
[taoensso.timbre :as log]
[status-im.utils.crypt :refer [gen-random-bytes]]
[status-im.components.status :as status]
+ [status-im.components.permissions :as permissions]
[status-im.utils.handlers :refer [register-handler] :as u]
status-im.chat.handlers
status-im.group-settings.handlers
@@ -122,11 +123,24 @@
(log/debug "Started Node")
(enet/get-network #(dispatch [:set :network %])))
+(defn move-to-internal-storage [db]
+ (status/move-to-internal-storage
+ (fn []
+ (status/start-node
+ (fn [result]
+ (node-started db result))))))
+
(register-handler :initialize-geth
(u/side-effect!
(fn [db _]
- (log/debug "Starting node")
- (status/start-node (fn [result] (node-started db result))))))
+ (status/should-move-to-internal-storage?
+ (fn [should-move?]
+ (if should-move?
+ (dispatch [:request-permissions
+ [:read-external-storage]
+ #(move-to-internal-storage db)
+ #(dispatch [:move-to-internal-failure-message])])
+ (status/start-node (fn [result] (node-started db result)))))))))
(register-handler :signal-event
(u/side-effect!
@@ -168,6 +182,14 @@
(.resetOkHttpClient webview-bridge)))
nil))))
+(register-handler :request-permissions
+ (u/side-effect!
+ (fn [_ [_ permissions then else]]
+ (permissions/request-permissions
+ permissions
+ then
+ else))))
+
;; -- User data --------------------------------------------------------------
(register-handler :load-user-phone-number
(fn [db [_]]
diff --git a/src/status_im/profile/edit/screen.cljs b/src/status_im/profile/edit/screen.cljs
index d628b9bbe8..65e11f171b 100644
--- a/src/status_im/profile/edit/screen.cljs
+++ b/src/status_im/profile/edit/screen.cljs
@@ -37,8 +37,13 @@
:on-change-text #(dispatch [:set-in [:profile-edit :name] %])}]])
(def profile-icon-options
- [{:text (label :t/image-source-gallery) :value #(dispatch [:open-image-picker])}
- {:text (label :t/image-source-make-photo) :value #(dispatch [:navigate-to :profile-photo-capture])}])
+ [{:text (label :t/image-source-gallery)
+ :value #(dispatch [:open-image-picker])}
+ {:text (label :t/image-source-make-photo)
+ :value (fn []
+ (dispatch [:request-permissions
+ [:camera :write-external-storage]
+ #(dispatch [:navigate-to :profile-photo-capture])]))}])
(defn edit-profile-bage [contact]
[view st/edit-profile-bage
diff --git a/src/status_im/profile/handlers.cljs b/src/status_im/profile/handlers.cljs
index 27ab94c80f..d90457f59c 100644
--- a/src/status_im/profile/handlers.cljs
+++ b/src/status_im/profile/handlers.cljs
@@ -26,18 +26,6 @@
(.log js/console type error))]
(img->base64 path on-success on-error)))))))
-(register-handler :open-image-source-selector
- (u/side-effect!
- (fn [_ [_ list-selection-fn]]
- (list-selection-fn {:title (label :t/image-source-title)
- :options [(label :t/image-source-make-photo) (label :t/image-source-gallery)]
- :callback (fn [index]
- (case index
- 0 (dispatch [:navigate-to :profile-photo-capture])
- 1 (dispatch [:open-image-picker])
- :default))
- :cancel-text (label :t/image-source-cancel)}))))
-
(register-handler :phone-number-change-requested
;; Switch user to the console issuing the !phone command automatically to let him change his phone number.
;; We allow to change phone number only from console because this requires entering SMS verification code.
diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs
index f7d5153fbf..99f8d1bb86 100644
--- a/src/status_im/translations/en.cljs
+++ b/src/status_im/translations/en.cljs
@@ -122,6 +122,7 @@
:intro-status "Chat with me to setup your account and change your settings!"
:intro-message1 "Welcome to Status\nTap this message to set your password & get started!"
:account-generation-message "Gimmie a sec, I gotta do some crazy math to generate your account!"
+ :move-to-internal-failure-message "We need to move some important files from external to internal storage. To do this, we need your permission. We won't be using external storage in future versions."
:debug-enabled "Debug server has been launched! Your IP address is {{ip}}. You can now add your DApp by running *status-dev-cli add-dapp --ip {{ip}}* from your computer"
;phone types