diff --git a/.re-natal b/.re-natal index 74c8704bf6..3df6476527 100644 --- a/.re-natal +++ b/.re-natal @@ -21,7 +21,8 @@ "react-native-camera", "react-native-qrcode", "react-native-orientation", - "identicon.js" + "identicon.js", + "react-native-fs" ], "imageDirs": [ "images" diff --git a/android/app/build.gradle b/android/app/build.gradle index 913abe3bc0..0682d5fac0 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -133,6 +133,7 @@ dependencies { compile project(':react-native-camera') compile project(':react-native-status') compile project(':react-native-orientation') + compile project(':react-native-fs') //compile(name:'statusgo-android-16', ext:'aar') compile(group: 'status-im', name: 'status-go', version: '0.1.0-201607011545-da53ec', ext: 'aar') diff --git a/android/app/src/main/java/com/statusim/MainActivity.java b/android/app/src/main/java/com/statusim/MainActivity.java index 6c779cee3b..6303b63e9f 100644 --- a/android/app/src/main/java/com/statusim/MainActivity.java +++ b/android/app/src/main/java/com/statusim/MainActivity.java @@ -29,6 +29,8 @@ import com.lwansbrough.RCTCamera.*; import com.i18n.reactnativei18n.ReactNativeI18n; import android.content.res.Configuration; +import com.rnfs.RNFSPackage; + public class MainActivity extends ReactActivity { private static final String TAG = "MainActivity"; @@ -112,6 +114,7 @@ public class MainActivity extends ReactActivity { new RCTCameraPackage(), new SmsListener(this), new OrientationPackage(this), + new RNFSPackage(), new GethPackage() ); } diff --git a/android/app/src/main/java/com/statusim/geth/module/GethModule.java b/android/app/src/main/java/com/statusim/geth/module/GethModule.java index d0b2b286c8..113e9ecf16 100644 --- a/android/app/src/main/java/com/statusim/geth/module/GethModule.java +++ b/android/app/src/main/java/com/statusim/geth/module/GethModule.java @@ -117,7 +117,7 @@ public class GethModule extends ReactContextBaseJavaModule implements LifecycleE case GethMessages.MSG_LOGGED_IN: callback = unlockAccountCallbacks.remove(callbackIdentifier); if (callback != null) { - callback.invoke(null, "{ \"result\": \"" + data.getString("result") + "\"}"); + callback.invoke(data.getString("result")); } break; default: diff --git a/android/app/src/main/res/drawable-hdpi/avatar.png b/android/app/src/main/res/drawable-hdpi/avatar.png new file mode 100644 index 0000000000..b1c2c64e3d Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/avatar.png differ diff --git a/android/app/src/main/res/drawable-hdpi/icon_plus.png b/android/app/src/main/res/drawable-hdpi/icon_plus.png new file mode 100644 index 0000000000..19e2a45b57 Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/icon_plus.png differ diff --git a/android/app/src/main/res/drawable-hdpi/icon_scan_white.png b/android/app/src/main/res/drawable-hdpi/icon_scan_white.png new file mode 100644 index 0000000000..a9496cb185 Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/icon_scan_white.png differ diff --git a/android/app/src/main/res/drawable-mdpi/avatar.png b/android/app/src/main/res/drawable-mdpi/avatar.png new file mode 100644 index 0000000000..f208650ddb Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/avatar.png differ diff --git a/android/app/src/main/res/drawable-mdpi/icon_plus.png b/android/app/src/main/res/drawable-mdpi/icon_plus.png new file mode 100644 index 0000000000..a26e891239 Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/icon_plus.png differ diff --git a/android/app/src/main/res/drawable-mdpi/icon_scan_white.png b/android/app/src/main/res/drawable-mdpi/icon_scan_white.png new file mode 100644 index 0000000000..e1fe0fe57b Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/icon_scan_white.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/avatar.png b/android/app/src/main/res/drawable-xhdpi/avatar.png new file mode 100644 index 0000000000..8cc91adff5 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/avatar.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/icon_plus.png b/android/app/src/main/res/drawable-xhdpi/icon_plus.png new file mode 100644 index 0000000000..00f6f9cdb8 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/icon_plus.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/icon_scan_white.png b/android/app/src/main/res/drawable-xhdpi/icon_scan_white.png new file mode 100644 index 0000000000..ad6ad72070 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/icon_scan_white.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/avatar.png b/android/app/src/main/res/drawable-xxhdpi/avatar.png new file mode 100644 index 0000000000..7fb2d0b42b Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/avatar.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/icon_plus.png b/android/app/src/main/res/drawable-xxhdpi/icon_plus.png new file mode 100644 index 0000000000..dad95d1814 Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/icon_plus.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/icon_scan_white.png b/android/app/src/main/res/drawable-xxhdpi/icon_scan_white.png new file mode 100644 index 0000000000..9aeeecba40 Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/icon_scan_white.png differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/avatar.png b/android/app/src/main/res/drawable-xxxhdpi/avatar.png new file mode 100644 index 0000000000..c33ac67619 Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/avatar.png differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/icon_plus.png b/android/app/src/main/res/drawable-xxxhdpi/icon_plus.png new file mode 100644 index 0000000000..4474449b88 Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/icon_plus.png differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/icon_scan_white.png b/android/app/src/main/res/drawable-xxxhdpi/icon_scan_white.png new file mode 100644 index 0000000000..8011c4a64d Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/icon_scan_white.png differ diff --git a/android/settings.gradle b/android/settings.gradle index c238c1e7d2..77a38a09cf 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -26,3 +26,6 @@ project(':react-native-camera').projectDir = new File(rootProject.projectDir, include ':react-native-orientation', ':app' project(':react-native-orientation').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-orientation/android') + +include ':react-native-fs' +project(':react-native-fs').projectDir = new File(settingsDir, '../node_modules/react-native-fs/android') diff --git a/package.json b/package.json index 7890c53cb7..44873810b8 100644 --- a/package.json +++ b/package.json @@ -15,15 +15,16 @@ "react-native-camera": "github:codyhazelwood/react-native-camera", "react-native-circle-checkbox": "^0.1.3", "react-native-contacts": "^0.2.4", + "react-native-fs": "^1.5.1", "react-native-i18n": "0.0.8", "react-native-invertible-scroll-view": "^1.0.0", "react-native-linear-gradient": "1.5.7", "react-native-loading-spinner-overlay": "0.0.8", + "react-native-orientation": "^1.17.0", "react-native-qrcode": "^0.2.2", "react-native-randombytes": "^2.1.0", + "react-native-status": "git+ssh://git@github.com/status-im/react-native-status", "react-native-vector-icons": "^1.3.4", - "react-native-orientation": "^1.17.0", - "realm": "^0.11.1", - "react-native-status": "git+ssh://git@github.com/status-im/react-native-status" + "realm": "^0.14.0" } } diff --git a/src/status_im/accounts/handlers.cljs b/src/status_im/accounts/handlers.cljs index cfb6d32d9b..c9de35487b 100644 --- a/src/status_im/accounts/handlers.cljs +++ b/src/status_im/accounts/handlers.cljs @@ -1,11 +1,18 @@ (ns status-im.accounts.handlers (:require [status-im.models.accounts :as accounts] - [re-frame.core :refer [register-handler after dispatch debug]] + [re-frame.core :refer [register-handler after dispatch dispatch-sync debug]] [status-im.utils.logging :as log] [status-im.components.react :refer [geth]] [status-im.utils.types :refer [json->clj]] [status-im.persistence.simple-kv-store :as kv] [status-im.protocol.state.storage :as storage] + [status-im.utils.identicon :refer [identicon]] + [status-im.db :refer [default-view]] + [status-im.utils.random :as random] + [status-im.persistence.realm.core :as realm] + [status-im.i18n :refer [label]] + [status-im.constants :refer [content-type-command-request]] + status-im.accounts.login.handlers [clojure.string :as str])) @@ -20,26 +27,76 @@ (defn save-password [password] (storage/put kv/kv-store :password password)) -(defn account-created [result password] +(defn account-created [db result password] (let [data (json->clj result) public-key (:pubkey data) address (:address data) account {:public-key public-key - :address address}] - (log/debug "Created account: " result) + :address address + :name address + :photo-path (identicon address)} + ] + (log/debug "account-created: " account) (when (not (str/blank? public-key)) (do - (save-password password) - (dispatch [:login-account address password]) - (dispatch [:initialize-protocol account]) - (dispatch [:add-account account]))))) + ;(save-password password) + (dispatch-sync [:add-account account]) + (dispatch [:login-account address password]))))) (register-handler :create-account (-> (fn [db [_ password]] - (.createAccount geth password (fn [result] (account-created result password))) + (.createAccount geth password (fn [result] (account-created db result password))) db))) +(defn initialize-account [db account] + (let [is-login-screen? (= (:view-id db) :login)] + (dispatch [:set :login {}]) + (dispatch [:set :is-logged-in true]) + (dispatch [:set :user-identity account]) + (dispatch [:initialize-account account]) + (when is-login-screen? (dispatch [:navigate-to-clean default-view])))) + +(defn logged-in [db address] + (let [account (get-in db [:accounts address]) + is-login-screen? (= (:view-id db) :login) + new-account? (not is-login-screen?)] + (log/debug "Logged in: " address account) + (realm/change-account-realm address new-account? + #(if (nil? %) + (initialize-account db account) + (log/debug "Error changing acount realm: " %))))) + (register-handler :login-account (-> (fn [db [_ address password]] - (.login geth address password (fn [result] (log/debug "Logged in account: " address result))) - db))) \ No newline at end of file + (.login geth address password (fn [result] + (let [data (json->clj result) + error (:error data) + success (zero? (count error))] + (log/debug "Logged in account: " address result) + (if success + (logged-in db address) + (dispatch [:set-in [:login :error] error]))))) + db))) + +(defn load-accounts! [db _] + (let [accounts (->> (accounts/get-accounts) + (map (fn [{:keys [address] :as account}] + [address account])) + (into {}))] + (assoc db :accounts accounts))) + +(register-handler :load-accounts load-accounts!) + +(defn console-create-account [db _] + (let [msg-id (random/id)] + (dispatch [:received-msg + {:msg-id msg-id + :content {:command (name :keypair) + :content (label :t/keypair-generated)} + :content-type content-type-command-request + :outgoing false + :from "console" + :to "me"}]) + db)) + +(register-handler :console-create-account console-create-account) \ No newline at end of file diff --git a/src/status_im/accounts/login/handlers.cljs b/src/status_im/accounts/login/handlers.cljs new file mode 100644 index 0000000000..5a00d18935 --- /dev/null +++ b/src/status_im/accounts/login/handlers.cljs @@ -0,0 +1,10 @@ +(ns status-im.accounts.login.handlers + (:require [re-frame.core :refer [register-handler after dispatch]] + [status-im.utils.handlers :as u])) + + +(defn set-login-from-qr + [{:keys [login] :as db} [_ _ login-info]] + (assoc db :login (merge login login-info))) + +(register-handler :set-login-from-qr set-login-from-qr) \ No newline at end of file diff --git a/src/status_im/accounts/login/screen.cljs b/src/status_im/accounts/login/screen.cljs new file mode 100644 index 0000000000..490f04e028 --- /dev/null +++ b/src/status_im/accounts/login/screen.cljs @@ -0,0 +1,91 @@ +(ns status-im.accounts.login.screen + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] + [status-im.components.react :refer [view + text-class + text-input + image + linear-gradient + touchable-highlight]] + [status-im.components.toolbar :refer [toolbar]] + [status-im.components.text-field.view :refer [text-field]] + [status-im.components.styles :refer [color-purple + color-white + icon-search + icon-back + icon-qr + toolbar-background1 + toolbar-title-container + toolbar-title-text + button-input-container + button-input + white-form-text-input]] + [status-im.qr-scanner.views.scan-button :refer [scan-button]] + [status-im.i18n :refer [label]] + [status-im.accounts.login.styles :as st])) + +(def toolbar-title + [view toolbar-title-container + [text-class {:style (merge toolbar-title-text {:color color-white})} + (label :t/login)]]) + +(defview address-input [address] + [view button-input-container + [text-field + {:value address + :editable false + :label (label :t/address) + :labelColor "#ffffff80" + :lineColor :white + :inputStyle st/input-style + :wrapperStyle (merge button-input st/address-input-wrapper) + :onChangeText #(dispatch [:set-in [:login :address] %])}] + ;[scan-button {:labelStyle st/scan-label + ; :icon :icon_scan_white + ; :showLabel (zero? (count address)) + ; :handler #(dispatch [:scan-qr-code {:toolbar-title (label :t/login)} :set-address-from-qr])}] + ]) + +(defview password-input [error] + [text-field + {:value "" + :error (when (pos? (count error)) (label :t/wrong-password)) + :errorColor :white + :label (label :t/password) + :labelColor "#ffffff80" + :lineColor :white + :inputStyle st/input-style + :onChangeText #(do + (dispatch [:set-in [:login :password] %]) + (dispatch [:set-in [:login :error] ""]))}]) + +(defview login [] + [{:keys [address password error]} [:get :login]] + [view st/screen-container + [linear-gradient {:colors ["rgba(182, 116, 241, 1)" "rgba(107, 147, 231, 1)" "rgba(43, 171, 238, 1)"] + :start [0, 0] + :end [0.5, 1] + :locations [0, 0.8, 1] + :style st/gradient-background}] + + [toolbar {:background-color :transparent + :nav-action {:image {:source {:uri :icon_back_white} + :style icon-back} + :handler #(dispatch [:navigate-back])} + :custom-content toolbar-title + :action {:image {:style icon-search} + :handler #()}}] + [view st/form-container + [address-input (or address "")] + [password-input error] + ] + [view st/bottom-actions-container + [view st/recover-text-container + [touchable-highlight + {:on-press #()} + [text-class {:style st/recover-text} (label :t/recover-access)]]] + [view st/connect-button-container + [touchable-highlight + {:on-press #(dispatch [:login-account address password])} + [view st/connect-button + [text-class {:style st/connect-button-text} (label :t/connect)]]]]]]) diff --git a/src/status_im/accounts/login/styles.cljs b/src/status_im/accounts/login/styles.cljs new file mode 100644 index 0000000000..e718fed938 --- /dev/null +++ b/src/status_im/accounts/login/styles.cljs @@ -0,0 +1,64 @@ +(ns status-im.accounts.login.styles + (:require [status-im.components.styles :refer [font + title-font + text1-color + color-white + toolbar-background2 + online-color]])) + + +(def screen-container + {:flex 1 + :color :white}) + +(def gradient-background + {:position :absolute + :top 0 + :right 0 + :bottom 0 + :left 0}) + +(def form-container + {:marginLeft 16 + :margin-top 70}) + +(def bottom-actions-container + {:position :absolute + :left 0 + :right 0 + :bottom 0}) + +(def recover-text-container + {:flex 1 + :alignItems :center + :padding 16}) + +(def recover-text + {:flex 1 + :color color-white + :fontSize 16}) + +(def connect-button-container + {:flex 1}) + +(def connect-button + {:backgroundColor color-white + :flex 1 + :alignItems :center + :paddingVertical 16 + :paddingHorizontal 28 + }) + +(def connect-button-text + {:color "#7099e6" + :fontSize 16}) + +(def input-style + {:color :white + :font-size 12}) + +(def scan-label + {:color :white}) + +(def address-input-wrapper + {}) \ No newline at end of file diff --git a/src/status_im/accounts/screen.cljs b/src/status_im/accounts/screen.cljs new file mode 100644 index 0000000000..ef847e1748 --- /dev/null +++ b/src/status_im/accounts/screen.cljs @@ -0,0 +1,80 @@ +(ns status-im.accounts.screen + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] + [status-im.components.react :refer [view + text + list-view + list-item + image + linear-gradient + touchable-highlight]] + [status-im.components.toolbar :refer [toolbar]] + [status-im.components.styles :refer [color-purple + color-white + icon-search + icon-back + icon-qr + icon-plus + toolbar-background1 + toolbar-title-container + toolbar-title-text + button-input-container + button-input + white-form-text-input]] + [status-im.utils.listview :as lw] + [status-im.accounts.views.account :refer [account-view]] + [status-im.i18n :refer [label]] + [status-im.accounts.styles :as st] + [status-im.utils.logging :as log])) + +(def toolbar-title + [view toolbar-title-container + [text {:style (merge toolbar-title-text {:color color-white})} + (label :t/switch-users)]]) + +(defn render-row [row _ _] + (list-item [account-view row])) + +(defn render-separator [_ row-id _] + (list-item [view {:style st/row-separator + :key row-id}])) + +(defn create-account [event] + (dispatch-sync [:reset-app]) + ; add accounts screen to history ( maybe there is a better way ? ) + (dispatch [:navigate-to-clean :accounts]) + (dispatch [:navigate-to :chat "console"])) + +(defview accounts [] + [accounts [:get :accounts] + stack [:get :navigation-stack]] + (let [accounts (vals accounts) + show-back? (> (count stack) 1)] + [view st/screen-container + [linear-gradient {:colors ["rgba(182, 116, 241, 1)" "rgba(107, 147, 231, 1)" "rgba(43, 171, 238, 1)"] + :start [0, 0] + :end [0.5, 1] + :locations [0, 0.8, 1] + :style st/gradient-background}] + [toolbar {:background-color :transparent + :nav-action {:image {:source (if show-back? {:uri :icon_back_white} nil) + :style icon-back} + :handler (if show-back? #(dispatch [:navigate-back]) nil)} + :custom-content toolbar-title + :action {:image {:style icon-search} + :handler #()}}] + [view st/accounts-container + [view st/account-list-view-container + [list-view {:dataSource (lw/to-datasource accounts) + :enableEmptySections true + :renderRow render-row + ;:renderSeparator render-separator + :style st/account-list}]]] + [view st/add-account-button-container + [touchable-highlight {:on-press create-account} + [view st/add-account-button + [image {:source {:uri :icon_add} + :style st/icon-plus}] + [text {:style st/add-account-text} (label :t/add-account)]]]]])) + +;(re-frame.core/dispatch [:set :view-id :users]) diff --git a/src/status_im/accounts/styles.cljs b/src/status_im/accounts/styles.cljs new file mode 100644 index 0000000000..6ad1c9c930 --- /dev/null +++ b/src/status_im/accounts/styles.cljs @@ -0,0 +1,114 @@ +(ns status-im.accounts.styles + (:require [status-im.components.styles :refer [font + title-font + text1-color + color-white + toolbar-background2 + online-color]])) + + +(def screen-container + {:flex 1 + :color :white}) + +(def gradient-background + {:position :absolute + :top 0 + :right 0 + :bottom 0 + :left 0}) + +(def account-list-container1 + {:position :absolute + :top 56 + :right 0 + :bottom 0 + :left 0 + :justifyContent :center}) + +(def accounts-container + {:flex 1 + :flex-direction :column + :justifyContent :center + :padding-bottom 56}) + +(def account-list-view-container + {:flexDirection :column + :justifyContent :center}) + +(def account-list + {}) + +(def row-separator + {:borderBottomWidth 1 + :borderBottomColor "#bababa"}) + +(def account-container + {:flex 1 + :flexDirection :row + :height 69 + :backgroundColor "rgba(255, 255, 255, 0.1)" + :alignItems :center + :justifyContent :center}) + +(def photo-container + {:flex 0.2 + :flexDirection :column + :alignItems :center + :justifyContent :center}) + +(def account-photo-container + {:flex 1 + :backgroundColor "rgba(255, 255, 255, 0.2)" + :borderRadius 50 + :width 36 + :height 36 + :alignItems :center + :justifyContent :center}) + +(def photo-image + {:borderRadius 50 + :width 36 + :height 36}) + +(def name-container + {:flex 1 + :flexDirection :column}) + +(def name-text + {:color color-white + :fontSize 16}) + +(def address-text + {:color color-white + :fontSize 12}) + +(def online-container + {:flex 0.2 + :flexDirection :column + :alignItems :center + :justifyContent :center}) + +(def add-account-button-container + {:position :absolute + :bottom 16 + :height 50 + :left 100 + :right 100 + :justifyContent :center + :alignItems :center}) + +(def add-account-button + {:flexDirection :row}) + +(def icon-plus + {:flexDirection :column + :paddingTop 2 + :width 20 + :height 20}) + +(def add-account-text + {:flexDirection :column + :color :white + :fontSize 16 + :marginLeft 8}) diff --git a/src/status_im/accounts/views/account.cljs b/src/status_im/accounts/views/account.cljs new file mode 100644 index 0000000000..63afee013e --- /dev/null +++ b/src/status_im/accounts/views/account.cljs @@ -0,0 +1,39 @@ +(ns status-im.accounts.views.account + (:require-macros [status-im.utils.views :refer [defview]]) + (:require [clojure.string :as s] + [status-im.resources :as res] + [status-im.components.react :refer [view + text + image + touchable-highlight]] + [re-frame.core :refer [dispatch subscribe]] + [status-im.components.styles :refer [icon-ok + icon-plus]] + [status-im.accounts.styles :as st])) + +(defn on-press [address] + (dispatch [:navigate-to :login address]) + (dispatch [:set-in [:login :address] address])) + +(defview account-view [{:keys [address photo-path name] :as account}] + [current-account [:get :user-identity]] + [touchable-highlight + {:onPress #(on-press address)} + [view st/account-container + [view st/photo-container + [view st/account-photo-container + (if (not= address "0x0") + [image {:source {:uri (if (s/blank? photo-path) :avatar photo-path)} + :style st/photo-image}] + [image {:source {:uri :icon_plus} + :style icon-plus}])]] + [view st/name-container + [text {:style st/name-text + :numberOfLines 1} (or name address)] + (when (not= address "0x0") + [text {:style st/address-text + :numberOfLines 1} address])] + [view st/online-container + (when (= address (:address current-account)) + [image {:source {:uri :icon_ok} + :style icon-ok}])]]]) diff --git a/src/status_im/android/core.cljs b/src/status_im/android/core.cljs index 9288405b76..e544d3b811 100644 --- a/src/status_im/android/core.cljs +++ b/src/status_im/android/core.cljs @@ -8,12 +8,14 @@ [status-im.components.react :refer [navigator app-registry device-event-emitter orientation]] [status-im.components.main-tabs :refer [main-tabs]] - [status-im.contacts.views.contact-list :refer [contact-list] ] + [status-im.contacts.views.contact-list :refer [contact-list]] [status-im.contacts.views.new-contact :refer [new-contact]] [status-im.qr-scanner.screen :refer [qr-scanner]] [status-im.discovery.screen :refer [discovery]] [status-im.discovery.tag :refer [discovery-tag]] [status-im.chat.screen :refer [chat]] + [status-im.accounts.login.screen :refer [login]] + [status-im.accounts.screen :refer [accounts]] [status-im.chats-list.screen :refer [chats-list]] [status-im.new-group.screen :refer [new-group]] [status-im.participants.views.add :refer [new-participants]] @@ -21,7 +23,9 @@ [status-im.group-settings.screen :refer [group-settings]] [status-im.profile.screen :refer [profile my-profile]] [status-im.utils.utils :refer [toast]] - [status-im.utils.encryption])) + [status-im.utils.encryption] + status-im.persistence.realm.core + [status-im.utils.logging :as log])) (defn init-back-button-handler! [] (let [new-listener (fn [] @@ -39,8 +43,11 @@ (defn app-root [] (let [signed-up (subscribe [:get :signed-up]) + _ (log/debug "signed up: " @signed-up) view-id (subscribe [:get :view-id]) + account (subscribe [:get :user-identity]) keyboard-height (subscribe [:get :keyboard-height])] + (log/debug "Current account: " @account) (r/create-class {:component-will-mount (fn [] @@ -62,7 +69,15 @@ #(dispatch [:set :keyboard-height 0])))) :render (fn [] - (case (if @signed-up @view-id :chat) + (let [startup-view (if @account + (if @signed-up + @view-id + :chat) + (if (contains? #{:login :chat} @view-id) + @view-id + :accounts))] + (log/debug startup-view) + (case (if true startup-view :chat) :discovery [main-tabs] :discovery-tag [discovery-tag] :add-participants [new-participants] @@ -76,18 +91,14 @@ :qr-scanner [qr-scanner] :chat [chat] :profile [profile] - :my-profile [my-profile]))}))) + :accounts [accounts] + :login [login] + :my-profile [my-profile])))}))) (defn init [] - (dispatch-sync [:initialize-db]) + (dispatch-sync [:reset-app]) (dispatch [:initialize-crypt]) (dispatch [:initialize-geth]) - (dispatch [:initialize-chats]) - ;protocol must be initialized after user enters password and we create account - ;(dispatch [:initialize-protocol]) (dispatch [:load-user-phone-number]) - (dispatch [:load-contacts]) - (dispatch [:init-console-chat]) - (dispatch [:init-chat]) (init-back-button-handler!) (.registerComponent app-registry "StatusIm" #(r/reactify-component app-root))) diff --git a/src/status_im/chat/handlers.cljs b/src/status_im/chat/handlers.cljs index dea583129e..82f73b5cd9 100644 --- a/src/status_im/chat/handlers.cljs +++ b/src/status_im/chat/handlers.cljs @@ -15,7 +15,7 @@ [status-im.models.chats :as chats] [status-im.navigation.handlers :as nav] [status-im.utils.handlers :refer [register-handler] :as u] - [status-im.persistence.realm :as r] + [status-im.persistence.realm.core :as r] [status-im.handlers.server :as server] [status-im.handlers.content-suggestions :refer [get-content-suggestions]] [status-im.utils.phone-number :refer [format-phone-number]] @@ -343,7 +343,7 @@ (defn store-message! [{:keys [new-message]} [_ {chat-id :from}]] - (messages/save-message chat-id new-message)) + (messages/save-message chat-id new-message)) (defn dispatch-request! [{:keys [new-message]} [_ {chat-id :from}]] @@ -446,17 +446,17 @@ (defn delete-messages! [{:keys [current-chat-id]} _] - (r/write + (r/write :account (fn [] - (r/delete (r/get-by-field :msgs :chat-id current-chat-id))))) + (r/delete :account (r/get-by-field :account :msgs :chat-id current-chat-id))))) (defn delete-chat! [{:keys [current-chat-id]} _] - (r/write - (fn [] - (-> (r/get-by-field :chats :chat-id current-chat-id) - (r/single) - (r/delete))))) + (r/write :account + (fn [] :account + (->> (r/get-by-field :account :chats :chat-id current-chat-id) + (r/single) + (r/delete :account))))) (register-handler :leave-group-chat ;; todo oreder of operations tbd diff --git a/src/status_im/chat/handlers/requests.cljs b/src/status_im/chat/handlers/requests.cljs index d229b0dc94..a536ac946e 100644 --- a/src/status_im/chat/handlers/requests.cljs +++ b/src/status_im/chat/handlers/requests.cljs @@ -1,14 +1,13 @@ (ns status-im.chat.handlers.requests (:require [re-frame.core :refer [after dispatch enrich]] [status-im.utils.handlers :refer [register-handler]] - [status-im.persistence.realm :as realm] + [status-im.persistence.realm.core :as realm] + [status-im.models.requests :as requests] [status-im.utils.handlers :as u])) (defn store-request! - [{:keys [new-request]}] - (realm/write - (fn [] - (realm/create :requests new-request)))) + [{:keys [new-request] :as db}] + (requests/save-request new-request)) (defn add-request [db [_ chat-id {:keys [msg-id content]}]] @@ -24,9 +23,9 @@ (defn load-requests! [{:keys [current-chat-id] :as db} [_ chat-id]] (let [chat-id' (or chat-id current-chat-id) - requests (-> :requests - ;; todo maybe limit is needed - (realm/get-by-fields {:chat-id chat-id' + requests (-> ;; todo maybe limit is needed + (realm/get-by-fields :account :requests + {:chat-id chat-id' :status "open"}) (realm/sorted :added :desc) (realm/collection->map)) @@ -35,12 +34,11 @@ (defn mark-request-as-answered! [_ [_ chat-id message-id]] - (realm/write + (realm/write :account (fn [] - (-> :requests - (realm/get-by-fields - {:chat-id chat-id - :message-id message-id}) + (-> (realm/get-by-fields :account :requests + {:chat-id chat-id + :message-id message-id}) (realm/single) (.-status) (set! "answered"))))) diff --git a/src/status_im/chat/handlers/unviewed_messages.cljs b/src/status_im/chat/handlers/unviewed_messages.cljs index 7dfa9e9df8..539c8cc197 100644 --- a/src/status_im/chat/handlers/unviewed_messages.cljs +++ b/src/status_im/chat/handlers/unviewed_messages.cljs @@ -1,11 +1,11 @@ (ns status-im.chat.handlers.unviewed-messages (:require [re-frame.core :refer [after enrich path dispatch]] [status-im.utils.handlers :refer [register-handler]] - [status-im.persistence.realm :as realm])) + [status-im.persistence.realm.core :as realm])) (defn delivered-messages [] (-> (realm/get-by-fields - :msgs + :account :msgs {:delivery-status :delivered :outgoing false}) (realm/collection->map))) diff --git a/src/status_im/chat/sign_up.cljs b/src/status_im/chat/sign_up.cljs index e4140eab16..c60f6d2bce 100644 --- a/src/status_im/chat/sign_up.cljs +++ b/src/status_im/chat/sign_up.cljs @@ -5,7 +5,7 @@ [status-im.protocol.state.storage :as s] [status-im.models.chats :as c] [status-im.components.styles :refer [default-chat-color]] - [status-im.utils.utils :refer [log on-error http-post toast]] + [status-im.utils.utils :refer [on-error http-post toast]] [status-im.utils.random :as random] [status-im.utils.sms-listener :refer [add-sms-listener remove-sms-listener]] diff --git a/src/status_im/commands/handlers/loading.cljs b/src/status_im/commands/handlers/loading.cljs index ccecdc86e5..feeb9be155 100644 --- a/src/status_im/commands/handlers/loading.cljs +++ b/src/status_im/commands/handlers/loading.cljs @@ -4,7 +4,7 @@ [status-im.utils.handlers :as u] [status-im.utils.utils :refer [http-get toast]] [clojure.string :as s] - [status-im.persistence.realm :as realm] + [status-im.persistence.realm.core :as realm] [status-im.components.jail :as j] [status-im.utils.types :refer [json->clj]] [status-im.commands.utils :refer [reg-handler]])) @@ -15,8 +15,8 @@ [_ [identity]] (dispatch [::fetch-commands! identity]) ;; todo uncomment - #_(if-let [{:keys [file]} (realm/get-one-by-field :commands :chat-id - identity)] + #_(if-let [{:keys [file]} (realm/get-one-by-field :account :commands + :chat-id identity)] (dispatch [::parse-commands! identity file]) (dispatch [::fetch-commands! identity]))) @@ -73,7 +73,7 @@ (defn save-commands-js! [_ [id file]] - (realm/create-object :commands {:chat-id id :file file})) + (realm/create-object :account :commands {:chat-id id :file file})) (defn loading-failed! [db [id reason details]] diff --git a/src/status_im/components/drawer/view.cljs b/src/status_im/components/drawer/view.cljs index a98fb9d542..726f9251d4 100644 --- a/src/status_im/components/drawer/view.cljs +++ b/src/status_im/components/drawer/view.cljs @@ -65,6 +65,7 @@ [view st/switch-users-container [touchable-opacity {:onPress (fn [] (close-drawer) + (dispatch [:navigate-to :accounts]) ;; TODO not implemented )} [text {:style st/switch-users-text} diff --git a/src/status_im/components/text_field/view.cljs b/src/status_im/components/text_field/view.cljs index f3757ac1bc..4949c00ef2 100644 --- a/src/status_im/components/text_field/view.cljs +++ b/src/status_im/components/text_field/view.cljs @@ -18,12 +18,13 @@ (def config {:label-top 16 :label-bottom 37 :label-font-large 16 - :label-font-small 12 + :label-font-small 13 :label-animation-duration 200}) (def default-props {:wrapperStyle {} :inputStyle {} :lineStyle {} + :editable true :labelColor "#838c93" :lineColor "#0000001f" :focusLineColor "#0000001f" @@ -68,7 +69,7 @@ (:label-font-large config) (:label-font-small config))) :float-label? (if (s/blank? value) false true)}] - (log/debug "component-will-mount") + ;(log/debug "component-will-mount") (r/set-state component data))) ; Invoked once, only on the client (not on the server), immediately after the @@ -78,7 +79,8 @@ ; parent components. (defn component-did-mount [component] (let [props (r/props component)] - (log/debug "component-did-mount:"))) + ;(log/debug "component-did-mount:") + )) ; Invoked when a component is receiving new props. This method is not called for ; the initial render. Use this as an opportunity to react to a prop transition @@ -86,7 +88,8 @@ ; The old props can be accessed via this.props. Calling this.setState() within ; this function will not trigger an additional render. (defn component-will-receive-props [component new-props] - (log/debug "component-will-receive-props: new-props=" new-props)) + ;(log/debug "component-will-receive-props: new-props=" new-props) + ) ; Invoked before rendering when new props or state are being received. This method ; is not called for the initial render or when forceUpdate is used. Use this as @@ -96,20 +99,22 @@ ; until the next state change. In addition, componentWillUpdate and ; componentDidUpdate will not be called. (defn should-component-update [component next-props next-state] - (log/debug "should-component-update: " next-props next-state) + ;(log/debug "should-component-update: " next-props next-state) true) ; Invoked immediately before rendering when new props or state are being received. ; This method is not called for the initial render. Use this as an opportunity ; to perform preparation before an update occurs. (defn component-will-update [component next-props next-state] - (log/debug "component-will-update: " next-props next-state)) + ;(log/debug "component-will-update: " next-props next-state) + ) ; Invoked immediately after the component's updates are flushed to the DOM. ; This method is not called for the initial render. Use this as an opportunity ; to operate on the DOM when the component has been updated. (defn component-did-update [component prev-props prev-state] - (log/debug "component-did-update: " prev-props prev-state)) + ;(log/debug "component-did-update: " prev-props prev-state) + ) (defn on-focus [{:keys [component animation onFocus]}] (do @@ -141,16 +146,17 @@ max-line-width] :as state} (r/state component) {:keys [wrapperStyle inputStyle lineColor focusLineColor labelColor errorColor error label value onFocus onBlur - onChangeText onChange] :as props} (merge default-props (r/props component)) + onChangeText onChange editable] :as props} (merge default-props (r/props component)) lineColor (if error errorColor lineColor) focusLineColor (if error errorColor focusLineColor) labelColor (if (and error (not float-label?)) errorColor labelColor) label (if error (str label " *") label)] - (log/debug "reagent-render: " data state) + ;(log/debug "reagent-render: " data) [view (merge st/text-field-container wrapperStyle) [animated-text {:style (st/label label-top label-font-size labelColor)} label] [text-input {:style (merge st/text-input inputStyle) :placeholder "" + :editable editable :onFocus #(on-focus {:component component :animation {:top label-top :to-top (:label-top config) @@ -185,5 +191,5 @@ :component-did-update component-did-update :display-name "text-field" :reagent-render reagent-render}] - (log/debug "Creating text-field component: " data) + ;(log/debug "Creating text-field component: " data) (r/create-class component-data))) \ No newline at end of file diff --git a/src/status_im/contacts/validations.cljs b/src/status_im/contacts/validations.cljs index 5c930a8b3c..b10e27ccb6 100644 --- a/src/status_im/contacts/validations.cljs +++ b/src/status_im/contacts/validations.cljs @@ -1,12 +1,20 @@ (ns status-im.contacts.validations (:require [cljs.spec :as s] - [status-im.persistence.realm :as realm])) + [cljsjs.web3] + [status-im.persistence.realm.core :as realm])) + +(defn is-address? [s] + (.isAddress js/Web3.prototype s)) (defn unique-identity? [identity] - (not (realm/exists? :contacts :whisper-identity identity))) + (not (realm/exists? :account :contacts :whisper-identity identity))) (defn valid-length? [identity] - (= 132 (count identity))) + (let [length (count identity)] + (or + (= 130 length) + (= 132 length) + (is-address? identity)))) (s/def ::identity-length valid-length?) (s/def ::unique-identity unique-identity?) diff --git a/src/status_im/contacts/views/new_contact.cljs b/src/status_im/contacts/views/new_contact.cljs index 2dbe6abc82..d0673a22ea 100644 --- a/src/status_im/contacts/views/new_contact.cljs +++ b/src/status_im/contacts/views/new_contact.cljs @@ -11,6 +11,7 @@ [status-im.components.text-field.view :refer [text-field]] [status-im.utils.identicon :refer [identicon]] [status-im.components.toolbar :refer [toolbar]] + [status-im.utils.utils :refer [log on-error http-post toast]] [status-im.components.styles :refer [color-purple color-white icon-search @@ -43,12 +44,12 @@ :label (label :t/name) :onChangeText #(dispatch [:set-in [:new-contact :name] %])}]) -(defview contact-whisper-id-input [whisper-identity] +(defview contact-whisper-id-input [whisper-identity error] [] - (let [error (if (str/blank? whisper-identity) "" nil) + (let [error (if (str/blank? whisper-identity) "" error) error (if (s/valid? ::v/whisper-identity whisper-identity) error - "Please enter a valid address or scan a QR code")] + (label :t/enter-valid-address))] [view button-input-container [text-field {:error error @@ -56,25 +57,52 @@ :value whisper-identity :wrapperStyle (merge button-input) :label (label :t/address) - :onChangeText #(dispatch [:set-in [:new-contact :whisper-identity] %])}] - [scan-button #(dispatch [:scan-qr-code {:toolbar-title (label :t/new-contact)} :set-new-contact-from-qr])]])) + :onChangeText #(do + (dispatch [:set-in [:new-contact :whisper-identity] %]) + (dispatch [:set :new-contact-address-error nil]))}] + [scan-button {:showLabel (zero? (count whisper-identity)) + :handler #(dispatch [:scan-qr-code {:toolbar-title (label :t/new-contact)} :set-new-contact-from-qr])}]])) + +(defn on-add-contact [whisper-identity new-contact] + (if (v/is-address? whisper-identity) + (http-post "get-contacts-by-address" {:addresses [whisper-identity]} + (fn [{:keys [contacts]}] + (if (> (count contacts) 0) + (let [contact (first contacts) + new-contact (merge + new-contact + {:address whisper-identity + :whisper-identity (:whisper-identity contact)})] + (dispatch [:add-new-contact new-contact])) + (dispatch [:set :new-contact-address-error (label :t/unknown-address)])))) + (dispatch [:add-new-contact new-contact]))) + +(defn toolbar-action [whisper-identity new-contact error] + (let [valid-contact? (and + (s/valid? ::v/contact new-contact) + (nil? error))] + {:image {:source {:uri (if valid-contact? + :icon_ok_blue + :icon_ok_disabled)} + :style icon-search} + :handler #(when valid-contact? + (let [contact (merge + {:photo-path (identicon whisper-identity)} + new-contact)] + (on-add-contact whisper-identity contact)))})) (defview new-contact [] - [{:keys [name whisper-identity phone-number] :as new-contact} [:get :new-contact]] - (let [valid-contact? (s/valid? ::v/contact new-contact)] - [view st/contact-form-container - [toolbar {:background-color :white - :nav-action {:image {:source {:uri :icon_back} - :style icon-back} - :handler #(dispatch [:navigate-back])} - :custom-content toolbar-title - :action {:image {:source {:uri (if valid-contact? - :icon_ok_blue - :icon_ok_disabled)} - :style icon-search} - :handler #(when valid-contact? (dispatch [:add-new-contact (merge {:photo-path (identicon whisper-identity)} new-contact)]))}}] - [view st/form-container - [contact-name-input name] - [contact-whisper-id-input whisper-identity]] - [view st/address-explication-container - [text {:style st/address-explication} (label :t/address-explication)]]])) + [{:keys [name whisper-identity phone-number] :as new-contact} [:get :new-contact] + error [:get :new-contact-address-error]] + [view st/contact-form-container + [toolbar {:background-color :white + :nav-action {:image {:source {:uri :icon_back} + :style icon-back} + :handler #(dispatch [:navigate-back])} + :custom-content toolbar-title + :action (toolbar-action whisper-identity new-contact error)}] + [view st/form-container + [contact-name-input name] + [contact-whisper-id-input whisper-identity error]] + [view st/address-explication-container + [text {:style st/address-explication} (label :t/address-explication)]]]) diff --git a/src/status_im/db.cljs b/src/status_im/db.cljs index 503ca17a99..2fd469e69a 100644 --- a/src/status_im/db.cljs +++ b/src/status_im/db.cljs @@ -11,7 +11,9 @@ ;; initial state of app-db (def app-db {:identity-password "replace-me-with-user-entered-password" :identity "me" + :is-logged-in false :accounts {} + :user-identity nil :contacts [] :contacts-ids #{} :selected-contacts #{} @@ -22,7 +24,7 @@ :chats-updated-signal 0 :show-actions false :selected-participants #{} - :signed-up true + :signed-up false :view-id default-view :navigation-stack (list default-view) ;; TODO fix hardcoded values diff --git a/src/status_im/discovery/model.cljs b/src/status_im/discovery/model.cljs index 6547321ff7..7b8a72b3a8 100644 --- a/src/status_im/discovery/model.cljs +++ b/src/status_im/discovery/model.cljs @@ -1,12 +1,11 @@ (ns status-im.discovery.model ;status-im.models.discoveries (:require [status-im.utils.logging :as log] - [status-im.persistence.realm :as realm] - [status-im.persistence.realm :as r])) + [status-im.persistence.realm.core :as r])) (defn get-tag [tag] (log/debug "Getting tag: " tag) - (-> (r/get-by-field :tag :name tag) + (-> (r/get-by-field :base :tag :name tag) (r/single-cljs))) (defn decrease-tag-counter [tag] @@ -15,18 +14,20 @@ (if tag-object (let [counter (dec (:count tag-object))] (if (zero? counter) - (realm/delete tag-object) - (realm/create :tag {:name tag - :count counter} - true)))))) + (r/delete :base tag-object) + (r/create :base :tag + {:name tag + :count counter} + true)))))) (defn increase-tag-counter [tag] (let [tag (:name tag) tag-object (get-tag tag)] (if tag-object - (realm/create :tag {:name tag - :count (inc (:count tag-object))} - true)))) + (r/create :base :tag + {:name tag + :count (inc (:count tag-object))} + true)))) (defn decrease-tags-counter [tags] (doseq [tag tags] @@ -37,45 +38,46 @@ (increase-tag-counter tag))) (defn get-tags [whisper-id] - (:tags (-> (r/get-by-field :discoveries :whisper-id whisper-id) + (:tags (-> (r/get-by-field :base :discoveries :whisper-id whisper-id) (r/single-cljs)))) (defn- create-discovery [{:keys [tags] :as discovery}] (log/debug "Creating discovery: " discovery tags) - (realm/create :discoveries discovery true) + (r/create :base :discoveries discovery true) (increase-tags-counter tags)) (defn- update-discovery [{:keys [whisper-id tags] :as discovery}] (let [old-tags (get-tags whisper-id) tags (map :name tags)] (decrease-tags-counter old-tags) - (realm/create :discoveries discovery true) + (r/create :base :discoveries discovery true) (increase-tags-counter tags))) (defn- discovery-exist? [discoveries discovery] (some #(= (:whisper-id discovery) (:whisper-id %)) discoveries)) (defn discovery-list [] - (->> (-> (r/get-all :discoveries) + (->> (-> (r/get-all :base :discoveries) (r/sorted :last-updated :desc) r/collection->map) (map #(update % :tags vals)))) (defn- add-discoveries [discoveries] - (realm/write (fn [] - (let [db-discoveries (discovery-list)] - (mapv (fn [discovery] - (if-not (discovery-exist? db-discoveries - discovery) - (create-discovery discovery) - (update-discovery discovery))) - discoveries))))) + (r/write :base + (fn [] + (let [db-discoveries (discovery-list)] + (mapv (fn [discovery] + (if-not (discovery-exist? db-discoveries + discovery) + (create-discovery discovery) + (update-discovery discovery))) + discoveries))))) (defn save-discoveries [discoveries] (add-discoveries discoveries)) (defn discoveries-by-tag [tag limit] - (let [discoveries (-> (r/get-by-filter :discoveries (str "tags.name = '" tag "'")) + (let [discoveries (-> (r/get-by-filter :base :discoveries (str "tags.name = '" tag "'")) (r/sorted :last-updated :desc))] (log/debug "Discoveries by tag: " tag) (if (pos? limit) @@ -83,7 +85,7 @@ discoveries))) (defn all-tags [] - (-> (r/get-all :tag) + (-> (r/get-all :base :tag) (r/sorted :count :desc) r/collection->map)) diff --git a/src/status_im/group_settings/handlers.cljs b/src/status_im/group_settings/handlers.cljs index 6f5e94d558..0c0521bcfd 100644 --- a/src/status_im/group_settings/handlers.cljs +++ b/src/status_im/group_settings/handlers.cljs @@ -1,7 +1,7 @@ (ns status-im.group-settings.handlers (:require [re-frame.core :refer [debug dispatch after enrich]] [status-im.utils.handlers :refer [register-handler]] - [status-im.persistence.realm :as r] + [status-im.persistence.realm.core :as r] [status-im.chat.handlers :refer [delete-messages!]] [status-im.protocol.api :as api] [status-im.utils.random :as random] @@ -20,8 +20,9 @@ [db-name property-name] (fn [{:keys [current-chat-id] :as db} _] (let [property (db-name db)] - (r/write (fn [] - (-> (r/get-by-field :chats :chat-id current-chat-id) + (r/write :account + (fn [] + (-> (r/get-by-field :account :chats :chat-id current-chat-id) (r/single) (aset (name property-name) property))))))) @@ -76,9 +77,9 @@ (defn remove-members-from-realm! [{:keys [current-chat-id selected-participants] :as db} _] (let [chat (get-in db [:chats current-chat-id])] - (r/write + (r/write :account (fn [] - (r/create + (r/create :account :chats (update chat :contacts remove-identities selected-participants) true))))) diff --git a/src/status_im/handlers.cljs b/src/status_im/handlers.cljs index 3012b78491..84887faa34 100644 --- a/src/status_im/handlers.cljs +++ b/src/status_im/handlers.cljs @@ -1,8 +1,9 @@ (ns status-im.handlers (:require - [re-frame.core :refer [after dispatch debug]] + [re-frame.core :refer [after dispatch dispatch-sync debug]] [schema.core :as s :include-macros true] [status-im.db :refer [app-db schema]] + [status-im.persistence.realm.core :as realm] [status-im.persistence.simple-kv-store :as kv] [status-im.protocol.state.storage :as storage] [status-im.utils.logging :as log] @@ -55,11 +56,33 @@ (register-handler :initialize-db (fn [_ _] + (realm/reset-account) (assoc app-db + :user-identity nil))) + +(register-handler :initialize-account-db + (fn [db _] + (assoc db :signed-up (storage/get kv/kv-store :signed-up) - :user-identity (protocol/stored-identity nil) :password (storage/get kv/kv-store :password)))) +(register-handler :initialize-account + (u/side-effect! + (fn [_ [_ account]] + (dispatch [:initialize-protocol account]) + (dispatch [:initialize-account-db]) + (dispatch [:initialize-chats]) + (dispatch [:load-contacts]) + (dispatch [:init-chat])))) + +(register-handler :reset-app + (u/side-effect! + (fn [_ _] + (dispatch [:initialize-db]) + (dispatch [:load-accounts]) + (dispatch [:init-console-chat]) + (dispatch [:load-commands! "console"])))) + (register-handler :initialize-crypt (u/side-effect! (fn [_ _] @@ -77,12 +100,7 @@ (dispatch [:crypt-initialized])))))))) (defn node-started [db result] - (let [identity (:user-identity db) - password (:password db)] - (log/debug "Started Node: " result) - (when identity (do - (dispatch [:login-account (:address identity) password]) - (dispatch [:initialize-protocol identity]))))) + (log/debug "Started Node: " result)) (register-handler :initialize-geth (u/side-effect! @@ -90,7 +108,7 @@ (log/debug "Starting node") (.startNode geth (fn [result] (node-started db result)) - #(dispatch [:initialize-protocol]))))) + #(log/debug "Geth already initialized"))))) (register-handler :crypt-initialized (u/side-effect! diff --git a/src/status_im/models/accounts.cljs b/src/status_im/models/accounts.cljs index a9f333c3c7..834db43e94 100644 --- a/src/status_im/models/accounts.cljs +++ b/src/status_im/models/accounts.cljs @@ -1,22 +1,22 @@ (ns status-im.models.accounts - (:require [status-im.persistence.realm :as r])) + (:require [status-im.persistence.realm.core :as r])) (defn get-accounts [] - (-> (r/get-all :accounts) + (-> (r/get-all :base :accounts) r/collection->map)) (defn create-account [{:keys [address public-key] :as account}] (->> account - (r/create :accounts))) + (r/create :base :accounts))) (defn save-accounts [accounts] - (r/write #(mapv create-account accounts))) + (r/write :base #(mapv create-account accounts))) ;;;;;;;;;;;;;;;;;;;;---------------------------------------------- (defn accounts-list [] - (r/get-all :accounts)) + (r/get-all :base :accounts)) (defn account-by-address [address] - (r/single-cljs (r/get-by-field :accounts :address address))) + (r/single-cljs (r/get-by-field :base :accounts :address address))) diff --git a/src/status_im/models/chats.cljs b/src/status_im/models/chats.cljs index 33e003a10d..854e7bcc57 100644 --- a/src/status_im/models/chats.cljs +++ b/src/status_im/models/chats.cljs @@ -1,7 +1,7 @@ (ns status-im.models.chats (:require [clojure.set :refer [difference]] [re-frame.core :refer [dispatch]] - [status-im.persistence.realm :as r] + [status-im.persistence.realm.core :as r] [status-im.utils.random :as random :refer [timestamp]] [clojure.string :refer [join blank?]] [status-im.utils.logging :as log] @@ -12,7 +12,7 @@ (defn chat-name-from-contacts [identities] (let [chat-name (->> identities (map (fn [identity] - (-> (r/get-by-field :contacts :whisper-identity identity) + (-> (r/get-by-field :account :contacts :whisper-identity identity) (r/single-cljs) :name))) (filter identity) @@ -25,7 +25,7 @@ chat-id)) (defn chat-exists? [chat-id] - (r/exists? :chats :chat-id chat-id)) + (r/exists? :account :chats :chat-id chat-id)) (defn add-status-message [chat-id] ;; TODO Get real status @@ -42,32 +42,33 @@ (defn create-chat ([{:keys [last-msg-id] :as chat}] (let [chat (assoc chat :last-msg-id (or last-msg-id ""))] - (r/write #(r/create :chats chat)))) + (r/write :account #(r/create :account :chats chat)))) ([db chat-id identities group-chat? chat-name] (when-not (chat-exists? chat-id) (let [chat-name (or chat-name (get-chat-name chat-id identities)) _ (log/debug "creating chat" chat-name)] - (r/write + (r/write :account (fn [] (let [contacts (mapv (fn [ident] {:identity ident}) identities)] - (r/create :chats {:chat-id chat-id - :is-active true - :name chat-name - :group-chat group-chat? - :timestamp (timestamp) - :contacts contacts - :last-msg-id ""})))) + (r/create :account :chats + {:chat-id chat-id + :is-active true + :name chat-name + :group-chat group-chat? + :timestamp (timestamp) + :contacts contacts + :last-msg-id ""})))) (add-status-message chat-id))))) (defn chat-contacts [chat-id] - (-> (r/get-by-field :chats :chat-id chat-id) + (-> (r/get-by-field :account :chats :chat-id chat-id) (r/single) (aget "contacts"))) (defn re-join-group-chat [db group-id identities group-name] - (r/write + (r/write :account (fn [] (let [new-identities (set identities) only-old-contacts (->> (chat-contacts group-id) @@ -78,10 +79,11 @@ (mapv (fn [ident] {:identity ident})) (concat only-old-contacts))] - (r/create :chats {:chat-id group-id - :is-active true - :name group-name - :contacts contacts} true)))) + (r/create :account :chats + {:chat-id group-id + :is-active true + :name group-name + :contacts contacts} true)))) db) (defn normalize-contacts @@ -89,23 +91,23 @@ (map #(update % :contacts vals) chats)) (defn chats-list [] - (-> (r/get-all :chats) + (-> (r/get-all :account :chats) (r/sorted :timestamp :desc) r/collection->map normalize-contacts)) (defn chat-by-id [chat-id] - (-> (r/get-by-field :chats :chat-id chat-id) + (-> (r/get-by-field :account :chats :chat-id chat-id) (r/single-cljs) (r/list-to-array :contacts))) (defn chat-by-id2 [chat-id] - (-> (r/get-by-field :chats :chat-id chat-id) + (-> (r/get-by-field :account :chats :chat-id chat-id) r/collection->map first)) (defn chat-add-participants [chat-id identities] - (r/write + (r/write :account (fn [] (let [contacts (chat-contacts chat-id)] (doseq [contact-identity identities] @@ -118,23 +120,24 @@ ;; TODO deprecated? (is there need to remove multiple member at once?) (defn chat-remove-participants [chat-id identities] - (r/write + (r/write :account (fn [] (let [query (include-query :identity identities) - chat (r/single (r/get-by-field :chats :chat-id chat-id))] + chat (r/single (r/get-by-field :account :chats :chat-id chat-id))] (-> (aget chat "contacts") (r/filtered query) (.forEach (fn [object _ _] (aset object "is-in-chat" false)))))))) (defn active-group-chats [] - (let [results (r/filtered (r/get-all :chats) + (let [results (r/filtered (r/get-all :account :chats) "group-chat = true && is-active = true")] (js->clj (.map results (fn [object _ _] (aget object "chat-id")))))) (defn set-chat-active [chat-id active?] - (r/write (fn [] - (-> (r/get-by-field :chats :chat-id chat-id) + (r/write :account + (fn [] + (-> (r/get-by-field :account :chats :chat-id chat-id) (r/single) (aset "is-active" active?))))) diff --git a/src/status_im/models/contacts.cljs b/src/status_im/models/contacts.cljs index 6c3ea62a7a..d10904e789 100644 --- a/src/status_im/models/contacts.cljs +++ b/src/status_im/models/contacts.cljs @@ -1,11 +1,11 @@ (ns status-im.models.contacts - (:require [status-im.persistence.realm :as r] + (:require [status-im.persistence.realm.core :as r] [status-im.utils.identicon :refer [identicon]] [status-im.persistence.realm-queries :refer [include-query exclude-query]])) (defn get-contacts [] - (-> (r/get-all :contacts) + (-> (r/get-all :account :contacts) (r/sorted :name :asc) r/collection->map)) @@ -13,22 +13,22 @@ (->> {:name (or name "") :photo-path (or photo-path (identicon whisper-identity))} (merge contact) - (r/create :contacts))) + (r/create :account :contacts))) (defn save-contacts [contacts] - (r/write #(mapv create-contact contacts))) + (r/write :account #(mapv create-contact contacts))) ;;;;;;;;;;;;;;;;;;;;---------------------------------------------- (defn contacts-list [] - (r/sorted (r/get-all :contacts) :name :asc)) + (r/sorted (r/get-all :account :contacts) :name :asc)) (defn contacts-list-exclude [exclude-idents] (if (empty? exclude-idents) (contacts-list) (let [query (exclude-query :whisper-identity exclude-idents)] - (-> (r/get-all :contacts) + (-> (r/get-all :account :contacts) (r/filtered query) (r/sorted :name :asc))))) @@ -36,9 +36,9 @@ (if (empty? include-indents) () (let [query (include-query :whisper-identity include-indents)] - (-> (r/get-all :contacts) + (-> (r/get-all :account :contacts) (r/filtered query) (r/sorted :name :asc))))) (defn contact-by-identity [identity] - (r/single-cljs (r/get-by-field :contacts :whisper-identity identity))) + (r/single-cljs (r/get-by-field :account :contacts :whisper-identity identity))) diff --git a/src/status_im/models/messages.cljs b/src/status_im/models/messages.cljs index a595cdcf68..4d45a64456 100644 --- a/src/status_im/models/messages.cljs +++ b/src/status_im/models/messages.cljs @@ -1,5 +1,5 @@ (ns status-im.models.messages - (:require [status-im.persistence.realm :as r] + (:require [status-im.persistence.realm.core :as r] [re-frame.core :refer [dispatch]] [cljs.reader :refer [read-string]] [status-im.utils.random :refer [timestamp]] @@ -29,8 +29,8 @@ [chat-id {:keys [delivery-status msg-id content] :or {delivery-status :pending} :as message}] - (when-not (r/exists? :msgs :msg-id msg-id) - (r/write + (when-not (r/exists? :account :msgs :msg-id msg-id) + (r/write :account (fn [] (let [content' (if (string? content) content @@ -41,7 +41,7 @@ :content content' :delivery-status delivery-status :timestamp (timestamp)})] - (r/create :msgs message' true)))))) + (r/create :account :msgs message' true)))))) (defn command-type? [type] (contains? @@ -51,20 +51,20 @@ (defn get-messages ([chat-id] (get-messages chat-id 0)) ([chat-id from] - (->> (-> (r/get-by-field :msgs :chat-id chat-id) - (r/sorted :timestamp :desc) - (r/page from (+ from c/default-number-of-messages)) - (r/collection->map)) - (into '()) - reverse - (keep (fn [{:keys [content-type] :as message}] + (->> (-> (r/get-by-field :account :msgs :chat-id chat-id) + (r/sorted :timestamp :desc) + (r/page from (+ from c/default-number-of-messages)) + (r/collection->map)) + (into '()) + reverse + (keep (fn [{:keys [content-type] :as message}] (if (command-type? content-type) (update message :content str-to-map) message)))))) (defn update-message! [{:keys [msg-id] :as msg}] (log/debug "update-message!" msg) - (r/write + (r/write :account (fn [] - (when (r/exists? :msgs :msg-id msg-id) - (r/create :msgs msg true))))) + (when (r/exists? :account :msgs :msg-id msg-id) + (r/create :account :msgs msg true))))) diff --git a/src/status_im/models/requests.cljs b/src/status_im/models/requests.cljs new file mode 100644 index 0000000000..62a2dfb6fb --- /dev/null +++ b/src/status_im/models/requests.cljs @@ -0,0 +1,21 @@ +(ns status-im.models.requests + (:require [status-im.persistence.realm.core :as r])) + +(defn get-requests [] + (-> (r/get-all :account :requests) + r/collection->map)) + +(defn create-request [request] + (r/create :account :requests request true)) + +(defn save-request [request] + (r/write :account + (fn [] + (create-request request)))) + +(defn save-requests [requests] + (r/write :account #(mapv create-request requests))) + +(defn requests-list [] + (r/get-all :account :requests)) + diff --git a/src/status_im/navigation/handlers.cljs b/src/status_im/navigation/handlers.cljs index db33411902..5d61fe3163 100644 --- a/src/status_im/navigation/handlers.cljs +++ b/src/status_im/navigation/handlers.cljs @@ -80,3 +80,11 @@ (push-view :profile))) (register-handler :show-profile show-profile) + +(defn navigate-to-clean + [db [_ view-id]] + (-> db + (assoc :navigation-stack (list)) + (push-view view-id))) + +(register-handler :navigate-to-clean navigate-to-clean) diff --git a/src/status_im/persistence/realm.cljs b/src/status_im/persistence/realm.cljs deleted file mode 100644 index e9e9e1098d..0000000000 --- a/src/status_im/persistence/realm.cljs +++ /dev/null @@ -1,198 +0,0 @@ -(ns status-im.persistence.realm - (:require [cljs.reader :refer [read-string]] - [status-im.components.styles :refer [default-chat-color]] - [status-im.utils.types :refer [to-string]] - [status-im.utils.utils :as u] - [clojure.string :as str]) - (:refer-clojure :exclude [exists?])) - -(def opts {:schema [{:name :contacts - :primaryKey :whisper-identity - :properties {:phone-number {:type "string" - :optional true} - :whisper-identity "string" - :name {:type "string" - :optional true} - :photo-path {:type "string" - :optinal true}}} - {:name :accounts - :primaryKey :address - :properties {:address "string" - :public-key "string"}} - {:name :requests - :properties {:message-id :string - :chat-id :string - :type :string - :status {:type :string - :default "open"} - :added :date}} - {:name :kv-store - :primaryKey :key - :properties {:key "string" - :value "string"}} - {:name :msgs - :primaryKey :msg-id - :properties {:msg-id "string" - :from "string" - :to {:type "string" - :optional true} - :content "string" ;; TODO make it ArrayBuffer - :content-type "string" - :timestamp "int" - :chat-id {:type "string" - :indexed true} - :outgoing "bool" - :delivery-status {:type "string" - :optional true} - :same-author "bool" - :same-direction "bool" - :preview {:type :string - :optional true}}} - {:name :chat-contact - :properties {:identity "string" - :is-in-chat {:type "bool" - :default true}}} - {:name :chats - :primaryKey :chat-id - :properties {:chat-id "string" - :name "string" - :color {:type "string" - :default default-chat-color} - :group-chat {:type "bool" - :indexed true} - :is-active "bool" - :timestamp "int" - :contacts {:type "list" - :objectType "chat-contact"} - :dapp-url {:type :string - :optional true} - :dapp-hash {:type :int - :optional true} - :last-msg-id "string"}} - {:name :commands - :primaryKey :chat-id - :properties {:chat-id "string" - :file "string"}} - {:name :tag - :primaryKey :name - :properties {:name "string" - :count {:type "int" - :optional true - :default 0}}} - {:name :discoveries - :primaryKey :whisper-id - :properties {:name "string" - :status "string" - :whisper-id "string" - :photo "string" - :location "string" - :tags {:type "list" - :objectType "tag"} - :last-updated "date"}}]}) - -(def realm-class (u/require "realm")) - -(def realm (when (cljs.core/exists? js/window) - (realm-class. (clj->js opts)))) - -(def schema-by-name (->> (:schema opts) - (mapv (fn [{:keys [name] :as schema}] - [name schema])) - (into {}))) - -(defn field-type [schema-name field] - (let [field-def (get-in schema-by-name [schema-name :properties field])] - (if (map? field-def) - (:type field-def) - field-def))) - -(defn write [f] - (.write realm f)) - -(defn create - ([schema-name obj] - (create schema-name obj false)) - ([schema-name obj update?] - (.create realm (to-string schema-name) (clj->js obj) update?))) - -(defn create-object - [schema-name obj] - (write (fn [] (create schema-name obj true)))) - -(defn and-q [queries] - (str/join " and " queries)) - -(defmulti to-query (fn [schema-name operator field value] - operator)) - -(defmethod to-query :eq [schema-name operator field value] - (let [value (to-string value) - query (str (name field) "=" (if (= "string" (name (field-type - schema-name field))) - (str "\"" value "\"") - value))] - query)) - -(defn get-by-filter [schema-name filter] - (-> (.objects realm (name schema-name)) - (.filtered filter))) - -(defn get-by-field [schema-name field value] - (let [q (to-query schema-name :eq field value)] - (.filtered (.objects realm (name schema-name)) q))) - -(defn get-by-fields [schema-name fields] - (let [queries (map (fn [[k v]] - (to-query schema-name :eq k v)) - fields)] - (.filtered (.objects realm (name schema-name)) (and-q queries)))) - -(defn get-all [schema-name] - (.objects realm (to-string schema-name))) - -(defn sorted [results field-name order] - (.sorted results (to-string field-name) (if (= order :asc) - false - true))) - -(defn filtered [results filter-query] - (.filtered results filter-query)) - -(defn page [results from to] - (js/Array.prototype.slice.call results from to)) - -(defn single [result] - (-> (aget result 0))) - -(defn single-cljs [result] - (some-> (aget result 0) - (js->clj :keywordize-keys true))) - -(defn cljs-list [results] - (-> (js->clj results :keywordize-keys true) - (vals))) - -(defn list-to-array [record list-field] - (update-in record [list-field] (comp vec vals))) - -(defn decode-value [{:keys [key value]}] - (read-string value)) - -(defn delete [obj] - (.delete realm obj)) - -(defn exists? [schema-name field value] - (pos? (.-length (get-by-field schema-name field value)))) - -(defn get-count [objs] - (.-length objs)) - -(defn get-list [schema-name] - (vals (js->clj (.objects realm (to-string schema-name)) :keywordize-keys true))) - -(defn collection->map [collection] - (-> (.map collection (fn [object _ _] object)) - (js->clj :keywordize-keys true))) - -(defn get-one-by-field [schema-name field value] - (single-cljs (get-by-field schema-name field value))) diff --git a/src/status_im/persistence/realm/core.cljs b/src/status_im/persistence/realm/core.cljs new file mode 100644 index 0000000000..8a8dbc1ff6 --- /dev/null +++ b/src/status_im/persistence/realm/core.cljs @@ -0,0 +1,179 @@ +(ns status-im.persistence.realm.core + (:require [cljs.reader :refer [read-string]] + [status-im.components.styles :refer [default-chat-color]] + [status-im.utils.types :refer [to-string]] + [status-im.utils.utils :as u] + [status-im.utils.fs :as fs] + [status-im.utils.logging :as log] + [status-im.persistence.realm.schemas :refer [base account]] + [clojure.string :as str]) + (:refer-clojure :exclude [exists?])) + +(def new-account-filename "new-account") + +(def realm-class (u/require "realm")) + +(defn create-account-realm [address] + (let [opts (merge account {:path (str address ".realm")})] + (when (cljs.core/exists? js/window) + (realm-class. (clj->js opts))))) + +(def base-realm + (when (cljs.core/exists? js/window) + (realm-class. (clj->js base)))) + +(def account-realm (atom (create-account-realm new-account-filename))) + +(defn is-new-account? [] + (let [path (.-path @account-realm) + realm_file (str new-account-filename ".realm")] + (str/ends-with? path realm_file))) + +(defn realm [schema] + (case schema + :base base-realm + :account @account-realm)) + +(defn close [schema] + (let [realm-db (realm schema)] + (when realm-db + (.close realm-db)))) + +(defn close-account-realm [] + (close :account) + (reset! account-realm nil)) + +(defn reset-account [] + (when @account-realm + (close-account-realm)) + (reset! account-realm (create-account-realm new-account-filename)) + (.write @account-realm #(.deleteAll @account-realm))) + +(defn move-file-handler [address err handler] + (log/debug "Moved file with error: " err address) + (if err + (log/error "Error moving account realm: " (.-message err)) + (reset! account-realm (create-account-realm address))) + (handler err)) + +(defn change-account-realm [address new-account? handler] + (let [path (.-path @account-realm) + realm-file (str new-account-filename ".realm")] + (log/debug "closing account realm: " path) + (close-account-realm) + (log/debug "is new account? " new-account?) + (if new-account? + (let [new-path (str/replace path realm-file (str address ".realm"))] + (log/debug "Moving file to " new-path) + (fs/move-file path new-path #(move-file-handler address % handler))) + (do + (reset! account-realm (create-account-realm address)) + (handler nil))))) + +(defn get-schema-by-name [opts] + (->> (:schema opts) + (mapv (fn [{:keys [name] :as schema}] + [name schema])) + (into {}))) + +(def schema-by-name + {:base (get-schema-by-name base) + :account (get-schema-by-name account)}) + +(defn field-type [schema schema-name field] + (let [schema-by-name (get schema-by-name schema) + field-def (get-in schema-by-name [schema-name :properties field])] + (if (map? field-def) + (:type field-def) + field-def))) + +(defn write [schema f] + (.write (realm schema) f)) + +(defn create + ([schema schema-name obj] + (create schema schema-name obj false)) + ([schema schema-name obj update?] + (.create (realm schema) (to-string schema-name) (clj->js obj) update?))) + +(defn create-object + [schema schema-name obj] + (write schema (fn [] (create schema schema-name obj true)))) + +(defn and-q [queries] + (str/join " and " queries)) + +(defmulti to-query (fn [schema schema-name operator field value] + operator)) + +(defmethod to-query :eq [schema schema-name operator field value] + (let [value (to-string value) + field-type (field-type schema schema-name field) + query (str (name field) "=" (if (= "string" (name field-type)) + (str "\"" value "\"") + value))] + query)) + +(defn get-by-filter [schema schema-name filter] + (-> (.objects (realm schema) (name schema-name)) + (.filtered filter))) + +(defn get-by-field [schema schema-name field value] + (let [q (to-query schema schema-name :eq field value)] + (.filtered (.objects (realm schema) (name schema-name)) q))) + +(defn get-by-fields [schema schema-name fields] + (let [queries (map (fn [[k v]] + (to-query schema schema-name :eq k v)) + fields)] + (.filtered (.objects (realm schema) (name schema-name)) (and-q queries)))) + +(defn get-all [schema schema-name] + (.objects (realm schema) (to-string schema-name))) + +(defn sorted [results field-name order] + (.sorted results (to-string field-name) (if (= order :asc) + false + true))) + +(defn filtered [results filter-query] + (.filtered results filter-query)) + +(defn page [results from to] + (js/Array.prototype.slice.call results from to)) + +(defn single [result] + (-> (aget result 0))) + +(defn single-cljs [result] + (some-> (aget result 0) + (js->clj :keywordize-keys true))) + +(defn cljs-list [results] + (-> (js->clj results :keywordize-keys true) + (vals))) + +(defn list-to-array [record list-field] + (update-in record [list-field] (comp vec vals))) + +(defn decode-value [{:keys [key value]}] + (read-string value)) + +(defn delete [schema obj] + (.delete (realm schema) obj)) + +(defn exists? [schema schema-name field value] + (pos? (.-length (get-by-field schema schema-name field value)))) + +(defn get-count [objs] + (.-length objs)) + +(defn get-list [schema schema-name] + (vals (js->clj (.objects (realm schema) (to-string schema-name)) :keywordize-keys true))) + +(defn collection->map [collection] + (-> (.map collection (fn [object _ _] object)) + (js->clj :keywordize-keys true))) + +(defn get-one-by-field [schema schema-name field value] + (single-cljs (get-by-field schema schema-name field value))) \ No newline at end of file diff --git a/src/status_im/persistence/realm/schemas.cljs b/src/status_im/persistence/realm/schemas.cljs new file mode 100644 index 0000000000..1506f3ad96 --- /dev/null +++ b/src/status_im/persistence/realm/schemas.cljs @@ -0,0 +1,96 @@ +(ns status-im.persistence.realm.schemas + (:require [status-im.components.styles :refer [default-chat-color]])) + +(def base {:schema [{:name :accounts + :primaryKey :address + :properties {:address "string" + :public-key "string" + :name "string" + :photo-path "string"}} + {:name :tag + :primaryKey :name + :properties {:name "string" + :count {:type "int" + :optional true + :default 0}}} + {:name :discoveries + :primaryKey :whisper-id + :properties {:name "string" + :status "string" + :whisper-id "string" + :photo "string" + :location "string" + :tags {:type "list" + :objectType "tag"} + :last-updated "date"}} + {:name :kv-store + :primaryKey :key + :properties {:key "string" + :value "string"}}] + :schemaVersion 0}) + +(def account {:schema [{:name :contacts + :primaryKey :whisper-identity + :properties {:phone-number {:type "string" + :optional true} + :whisper-identity "string" + :name {:type "string" + :optional true} + :photo-path {:type "string" + :optinal true}}} + {:name :requests + :properties {:message-id :string + :chat-id :string + :type :string + :status {:type :string + :default "open"} + :added :date}} + {:name :kv-store + :primaryKey :key + :properties {:key "string" + :value "string"}} + {:name :msgs + :primaryKey :msg-id + :properties {:msg-id "string" + :from "string" + :to {:type "string" + :optional true} + :content "string" ;; TODO make it ArrayBuffer + :content-type "string" + :timestamp "int" + :chat-id {:type "string" + :indexed true} + :outgoing "bool" + :delivery-status {:type "string" + :optional true} + :same-author "bool" + :same-direction "bool" + :preview {:type :string + :optional true}}} + {:name :chat-contact + :properties {:identity "string" + :is-in-chat {:type "bool" + :default true}}} + {:name :chats + :primaryKey :chat-id + :properties {:chat-id "string" + :name "string" + :color {:type "string" + :default default-chat-color} + :group-chat {:type "bool" + :indexed true} + :is-active "bool" + :timestamp "int" + :contacts {:type "list" + :objectType "chat-contact"} + :dapp-url {:type :string + :optional true} + :dapp-hash {:type :int + :optional true} + :last-msg-id "string"}} + {:name :commands + :primaryKey :chat-id + :properties {:chat-id "string" + :file "string"}}] + :schemaVersion 0}) + diff --git a/src/status_im/persistence/simple_kv_store.cljs b/src/status_im/persistence/simple_kv_store.cljs index 84dd85bff3..84151ef522 100644 --- a/src/status_im/persistence/simple_kv_store.cljs +++ b/src/status_im/persistence/simple_kv_store.cljs @@ -1,25 +1,29 @@ (ns status-im.persistence.simple-kv-store (:require [status-im.protocol.state.storage :as st] - [status-im.persistence.realm :as r] + [status-im.persistence.realm.core :as r] [status-im.utils.types :refer [to-edn-string]])) -(defrecord SimpleKvStore [] +(defrecord SimpleKvStore [schema] st/Storage (put [_ key value] - (r/write + (r/write schema (fn [] - (r/create :kv-store {:key key - :value (to-edn-string value)} true)))) + (r/create schema :kv-store + {:key key + :value (to-edn-string value)} true)))) (get [_ key] - (some-> (r/get-by-field :kv-store :key key) + (some-> (r/get-by-field schema :kv-store :key key) (r/single-cljs) (r/decode-value))) (contains-key? [_ key] - (r/exists? :kv-store :key key)) + (r/exists? schema :kv-store :key key)) (delete [_ key] - (r/write (fn [] - (-> (r/get-by-field :kv-store :key key) - (r/single) - (r/delete)))))) + (r/write schema + (fn [] + (->> (r/get-by-field schema :kv-store :key key) + (r/single) + (r/delete schema)))))) -(def kv-store (->SimpleKvStore)) +(def kv-store (->SimpleKvStore :account)) + +(def base-kv-store (->SimpleKvStore :base)) diff --git a/src/status_im/qr_scanner/views/scan-button.cljs b/src/status_im/qr_scanner/views/scan-button.cljs index 9ed1fd39e5..81dae39990 100644 --- a/src/status_im/qr_scanner/views/scan-button.cljs +++ b/src/status_im/qr_scanner/views/scan-button.cljs @@ -12,12 +12,13 @@ [status-im.qr-scanner.styles :as st])) -(defview scan-button [handler] - [] - [view st/scan-button - [touchable-highlight - {:on-press handler} - [view st/scan-button-content - [image {:source {:uri :scan_blue} - :style icon-scan}] - [text {:style st/scan-text} (label :t/scan-qr)]]]]) \ No newline at end of file +(defview scan-button [{:keys [showLabel icon labelStyle handler]}] + (let [showLabel (if (nil? showLabel) true showLabel)] + [view st/scan-button + [touchable-highlight + {:on-press handler} + [view st/scan-button-content + [image {:source {:uri (or icon :scan_blue)} + :style icon-scan}] + (when showLabel [text {:style (merge st/scan-text labelStyle)} + (label :t/scan-qr)])]]])) \ No newline at end of file diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs index e86d4fbc9b..d96cb58eb8 100644 --- a/src/status_im/translations/en.cljs +++ b/src/status_im/translations/en.cljs @@ -125,13 +125,17 @@ :name "Name" :whisper-identity "Whisper Identity" :address-explication "Maybe here should be some text explaining what an address is and where to look for it" + :enter-valid-address "Please enter a valid address or scan a QR code" + :unknown-address "Unknown address" + ;login - :recover-from-passphrase "Recover from passphrase" + :recover-access "Recover access" :connect "Connect" :address "Address" :password "Password" :login "Login" + :wrong-password "Wrong password" ;users :add-account "Add account" diff --git a/src/status_im/utils/fs.cljs b/src/status_im/utils/fs.cljs new file mode 100644 index 0000000000..c81ab9dae8 --- /dev/null +++ b/src/status_im/utils/fs.cljs @@ -0,0 +1,11 @@ +(ns status-im.utils.fs + (:require [clojure.string :as s] + [status-im.utils.utils :as u])) + +(def fs (u/require "react-native-fs")) + +(defn move-file [src dst handler] + (let [result (.moveFile fs src dst) + result (.then result #(handler nil %)) + result (.catch result #(handler % nil))] + result)) \ No newline at end of file