Merge pull request #155 from status-im/feature/#124

Feature/#124
This commit is contained in:
Jarrad 2016-07-19 16:23:06 +02:00 committed by GitHub
commit 040ce74593
55 changed files with 1074 additions and 406 deletions

View File

@ -21,7 +21,8 @@
"react-native-camera",
"react-native-qrcode",
"react-native-orientation",
"identicon.js"
"identicon.js",
"react-native-fs"
],
"imageDirs": [
"images"

View File

@ -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')

View File

@ -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()
);
}

View File

@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1017 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 530 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 668 B

View File

@ -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')

View File

@ -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"
}
}

View File

@ -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)))
(.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)

View File

@ -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)

View File

@ -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)]]]]]])

View File

@ -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
{})

View File

@ -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])

View File

@ -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})

View File

@ -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}])]]])

View File

@ -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)))

View File

@ -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

View File

@ -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")))))

View File

@ -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)))

View File

@ -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]]

View File

@ -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]]

View File

@ -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}

View File

@ -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)))

View File

@ -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?)

View File

@ -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)]]])

View File

@ -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

View File

@ -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))

View File

@ -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)))))

View File

@ -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!

View File

@ -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)))

View File

@ -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?)))))

View File

@ -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)))

View File

@ -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)))))

View File

@ -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))

View File

@ -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)

View File

@ -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)))

View File

@ -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)))

View File

@ -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})

View File

@ -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))

View File

@ -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)]]]])
(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)])]]]))

View File

@ -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"

View File

@ -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))