merged develop

Former-commit-id: 7f207a3760
This commit is contained in:
Adrian Tiberius 2016-06-10 03:21:48 +03:00
commit 23a17b2632
41 changed files with 459 additions and 212 deletions

9
.gitignore vendored
View File

@ -50,3 +50,12 @@ target/
#
figwheel_server.log
.nrepl-port
# Lein
#
.lein-failures
## Doo
#
out
doo-index.html

View File

@ -1,7 +1,7 @@
{
"name": "StatusIm",
"interface": "reagent",
"androidHost": "localhost",
"androidHost": "10.0.3.2",
"modules": [
"react-native-contacts",
"react-native-invertible-scroll-view",

View File

@ -8,11 +8,18 @@ import com.facebook.react.shell.MainReactPackage;
import com.rt2zz.reactnativecontacts.ReactNativeContacts;
import android.os.Bundle;
import android.os.Environment;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.DialogInterface.OnCancelListener;
import com.github.ethereum.go_ethereum.cmd.Geth;
import com.bitgo.randombytes.RandomBytesPackage;
import com.BV.LinearGradient.LinearGradientPackage;
import com.centaurwarchief.smslistener.SmsListener;
import android.os.Handler;
import android.util.Log;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
@ -25,15 +32,10 @@ import io.realm.react.RealmReactPackage;
public class MainActivity extends ReactActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Handler handler = new Handler();
// Required for android-16 (???)
System.loadLibrary("gethraw");
System.loadLibrary("geth");
// Required because of crazy APN settings redirecting localhost
protected void startStatus() {
// Required because of crazy APN settings redirecting localhost (found in GB)
Properties properties = System.getProperties();
properties.setProperty("http.nonProxyHosts", "localhost|127.0.0.1");
properties.setProperty("https.nonProxyHosts", "localhost|127.0.0.1");
@ -45,11 +47,56 @@ public class MainActivity extends ReactActivity {
getApplicationInfo().dataDir;
// Launch!
final Runnable addPeer = new Runnable() {
public void run() {
Log.w("Geth", "adding peer");
Geth.run("--exec admin.addPeer(\"enode://e2f28126720452aa82f7d3083e49e6b3945502cb94d9750a15e27ee310eed6991618199f878e5fbc7dfa0e20f0af9554b41f491dc8f1dbae8f0f2d37a3a613aa@139.162.13.89:55555\") attach http://localhost:8545");
}
};
new Thread(new Runnable() {
public void run() {
Geth.run("--bootnodes enode://e2f28126720452aa82f7d3083e49e6b3945502cb94d9750a15e27ee310eed6991618199f878e5fbc7dfa0e20f0af9554b41f491dc8f1dbae8f0f2d37a3a613aa@139.162.13.89:30303 --shh --ipcdisable --nodiscover --rpc --rpcapi db,eth,net,web3,shh,admin --fast --datadir=" + dataFolder);
Geth.run("--shh --ipcdisable --nodiscover --rpc --rpcapi db,eth,net,web3,shh,admin --fast --datadir=" + dataFolder);
}
}).start();
handler.postDelayed(addPeer, 5000);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Required for android-16 (???)
// Crash if put in startStatus() ?
System.loadLibrary("gethraw");
System.loadLibrary("geth");
if(!RootUtil.isDeviceRooted()) {
startStatus();
} else {
AlertDialog dialog = new AlertDialog.Builder(MainActivity.this).setMessage(getResources().getString(R.string.root_warning))
.setPositiveButton(getResources().getString(R.string.root_okay), new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
startStatus();
}
}).setNegativeButton(getResources().getString(R.string.root_cancel), new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
MainActivity.this.finishAffinity();
}
}).setOnCancelListener(new OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
dialog.dismiss();
MainActivity.this.finishAffinity();
}
}).create();
dialog.show();
}
}
/**

View File

@ -0,0 +1,41 @@
package com.statusim;
import java.io.File;
import java.io.BufferedReader;
import java.io.InputStreamReader;
/** @author Kevin Kowalewski */
public class RootUtil {
public static boolean isDeviceRooted() {
return checkRootMethod1() || checkRootMethod2() || checkRootMethod3();
}
private static boolean checkRootMethod1() {
String buildTags = android.os.Build.TAGS;
return buildTags != null && buildTags.contains("test-keys");
}
private static boolean checkRootMethod2() {
String[] paths = { "/system/app/Superuser.apk", "/sbin/su", "/system/bin/su", "/system/xbin/su", "/data/local/xbin/su", "/data/local/bin/su", "/system/sd/xbin/su",
"/system/bin/failsafe/su", "/data/local/su" };
for (String path : paths) {
if (new File(path).exists()) return true;
}
return false;
}
private static boolean checkRootMethod3() {
Process process = null;
try {
process = Runtime.getRuntime().exec(new String[] { "/system/xbin/which", "su" });
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
if (in.readLine() != null) return true;
return false;
} catch (Throwable t) {
return false;
} finally {
if (process != null) process.destroy();
}
}
}

View File

@ -1,3 +1,6 @@
<resources>
<string name="app_name">StatusIm</string>
</resources>
<string name="app_name">Status</string>
<string name="root_warning">Your phone appears to be ROOTED, by pressing CONTINUE you understand and accept the risks in using this software.</string>
<string name="root_okay">Continue</string>
<string name="root_cancel">Exit</string>
</resources>

View File

@ -8,7 +8,7 @@
[reagent "0.5.1" :exclusions [cljsjs/react]]
[re-frame "0.6.0"]
[prismatic/schema "1.0.4"]
^{:voom {:repo "https://github.com/status-im/status-lib.git"
^{:voom {:repo "git@github.com:status-im/status-lib.git"
:branch "master"}}
[status-im/protocol "0.1.1-20160525_083359-g53ab2c2"]
[natal-shell "0.1.6"]
@ -20,9 +20,12 @@
["do" "clean"
["with-profile" "prod" "cljsbuild" "once" "ios"]
["with-profile" "prod" "cljsbuild" "once" "android"]]}
:test-paths ["test/clj"]
:figwheel {:nrepl-port 7888}
:profiles {:dev {:dependencies [[figwheel-sidecar "0.5.0-2"]
[com.cemerick/piggieback "0.2.1"]]
[com.cemerick/piggieback "0.2.1"]
[io.appium/java-client "3.4.1"]]
:plugins [[lein-doo "0.1.6"]]
:source-paths ["src" "env/dev"]
:cljsbuild {:builds {:ios {:source-paths ["src" "env/dev"]
:figwheel true
@ -35,7 +38,13 @@
:compiler {:output-to "target/android/not-used.js"
:main "env.android.main"
:output-dir "target/android"
:optimizations :none}}}}
:optimizations :none}}
:test {:source-paths ["src" "test/cljs"]
:compiler
{:main status-im.test.runner
:output-to "target/test/test.js"
:optimizations :none
:target :nodejs}}}}
:repl-options {:nrepl-middleware [cemerick.piggieback/wrap-cljs-repl]}}
:prod {:cljsbuild {:builds {:ios {:source-paths ["src" "env/prod"]
:compiler {:output-to "index.ios.js"
@ -46,5 +55,4 @@
:compiler {:output-to "index.android.js"
:main "env.android.main"
:output-dir "target/android"
:optimizations :simple}}}}
}})
:optimizations :simple}}}}}})

View File

@ -17,11 +17,13 @@ function tab () {
fi
osascript &>/dev/null <<EOF
tell application "iTerm"
tell current terminal
launch session "Default Session"
tell the last session
write text "cd \"$cdto\"$cmd"
tell application "iTerm2"
tell current window
set newTab to (create tab with default profile)
tell newTab
tell current session
write text "cd \"$cdto\"$cmd"
end tell
end tell
end tell
end tell
@ -59,3 +61,10 @@ sleep 10s
adb reverse tcp:8081 tcp:8081 && adb reverse tcp:3449 tcp:3449
react-native run-android
if [ ! -z $2 ]
then
tab "appium"
lein test
lein doo node test once
fi

View File

@ -1 +1,4 @@
(ns cljsjs.react)
(ns cljsjs.react)
(when (exists? js/window)
(set! js/window.React (js/require "react-native")))

View File

@ -230,9 +230,9 @@
(sign-up-service/stop-listening-confirmation-code-sms db)))
(register-handler :sign-up-confirm
(fn [db [_ confirmation-code]]
(server/sign-up-confirm confirmation-code sign-up-service/on-send-code-response)
db))
(u/side-effect!
(fn [_ [_ confirmation-code]]
(server/sign-up-confirm confirmation-code sign-up-service/on-send-code-response))))
(register-handler :set-signed-up
(fn [db [_ signed-up]]

View File

@ -18,7 +18,7 @@
[status-im.components.toolbar :refer [toolbar]]
[status-im.chat.views.message :refer [chat-message]]
[status-im.chat.views.new-message :refer [chat-message-new]]
[status-im.i18n :refer [label]]))
[status-im.i18n :refer [label label-pluralize]]))
(defn contacts-by-identity [contacts]
@ -186,7 +186,7 @@
[icon :group st/group-icon]
[text {:style st/members}
(let [cnt (inc (count @contacts))]
(label :t/members {:count cnt}))]]
(label-pluralize cnt :t/members))]]
;; TODO stub data: last activity
[text {:style st/last-activity} (label :t/last-active)])])))

View File

@ -38,11 +38,13 @@
:onChangeText set-input-message
:onSubmitEditing (fn []
(when (valid? message validator)
(send-command)))}
(send-command)))
:accessibility-label :command-input}
input-options)
message]
(if (valid? message validator)
[touchable-highlight {:on-press send-command}
[touchable-highlight {:on-press send-command
:accessibility-label :stage-command}
[view st/send-container [icon :send st/send-icon]]]
[touchable-highlight {:on-press cancel-command-input}
[view st/cancel-container

View File

@ -72,13 +72,18 @@
(defn set-chat-command [msg-id command]
(dispatch [:set-response-chat-command msg-id (:command command)]))
(defn label [{:keys [command]}]
(->> (name command)
(str "request-")))
(defn message-content-command-request
[{:keys [msg-id content from incoming-group]}]
(let [commands-atom (subscribe [:get-commands])]
(fn [{:keys [msg-id content from incoming-group]}]
(let [commands @commands-atom
{:keys [command content]} (parse-command-request commands content)]
[touchable-highlight {:onPress #(set-chat-command msg-id command)}
[touchable-highlight {:onPress #(set-chat-command msg-id command)
:accessibility-label (label command)}
[view st/comand-request-view
[view st/command-request-message-view
(when incoming-group

View File

@ -1,9 +1,9 @@
(ns status-im.chat.views.plain-input
(:require [re-frame.core :refer [subscribe dispatch]]
[status-im.components.react :refer [view
icon
touchable-highlight
text-input]]
icon
touchable-highlight
text-input]]
[status-im.chat.views.suggestions :refer [suggestions-view]]
[status-im.chat.styles.plain-input :as st]))
@ -39,15 +39,16 @@
(if @typing-command?
[icon :close-gray st/close-icon]
[icon :list st/list-icon])]]
[text-input {:style st/message-input
:autoFocus (pos? (count @staged-commands-atom))
:onChangeText set-input-message
:onSubmitEditing #(try-send @chat @staged-commands-atom
input-message)}
[text-input {:style st/message-input
:autoFocus (pos? (count @staged-commands-atom))
:onChangeText set-input-message
:onSubmitEditing #(try-send @chat @staged-commands-atom
input-message)}
input-message]
;; TODO emoticons: not implemented
[icon :smile st/smile-icon]
(when (message-valid? @staged-commands-atom input-message)
[touchable-highlight {:on-press #(send @chat input-message)}
[touchable-highlight {:on-press #(send @chat input-message)
:accessibility-label :send-message}
[view st/send-container
[icon :send st/send-icon]]])]]))))

View File

@ -36,7 +36,7 @@
[drawer-view
[view st/chats-container
[chats-list-toolbar]
[list-view {:dataSource (to-datasource (vals @chats))
[list-view {:dataSource (to-datasource @chats)
:renderRow (fn [row _ _]
(list-item [chat-list-item row]))
:style st/list-container}]

View File

@ -1,17 +1,18 @@
(ns status-im.chats-list.views.chat-list-item
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
[status-im.components.react :refer [view
text
image
touchable-highlight]]
text
image
touchable-highlight]]
[status-im.components.styles :refer [font]]
[status-im.chats-list.views.inner-item :refer
[chat-list-item-inner-view]]))
(defn chat-list-item [{:keys [chat-id] :as chat}]
(defn chat-list-item [[chat-id chat]]
[touchable-highlight
{:on-press #(dispatch [:navigate-to :chat chat-id])}
[view [chat-list-item-inner-view (merge chat
;; TODO stub data
{:new-messages-count 3
{:chat-id chat-id
:new-messages-count 3
:online true})]]])

View File

@ -1,7 +1,7 @@
(ns status-im.components.action-button
(:require [reagent.core :as r]))
(set! js/window.ActionButton (js/require "react-native-action-button"))
(def class (js/require "react-native-action-button"))
(def action-button (r/adapt-react-class (.-default js/ActionButton)))
(def action-button-item (r/adapt-react-class (.. js/ActionButton -default -Item)))
(def action-button (r/adapt-react-class (.-default class)))
(def action-button-item (r/adapt-react-class (.. class -default -Item)))

View File

@ -5,11 +5,12 @@
touchable-without-feedback
text]]
[status-im.components.carousel.styles :as st]
[status-im.utils.logging :as log]))
[status-im.utils.logging :as log]
[status-im.components.react :as r]))
(defn window-page-width []
(.-width (.get (.. js/React -Dimensions) "window")))
(.-width (.get (.. r/react -Dimensions) "window")))
(def defaults {:gap 10
:sneak 10

View File

@ -6,7 +6,8 @@
image
icon]]
[status-im.components.chat-icon.styles :as st]
[status-im.components.styles :refer [color-purple]]))
[status-im.components.styles :refer [color-purple]]
[clojure.string :as s]))
(defn default-chat-icon [name styles]
[view (:default-chat-icon styles)
@ -26,10 +27,10 @@
(defview chat-icon-view [chat-id group-chat name online styles]
[photo-path [:chat-photo chat-id]]
[view (:container styles)
(if (and photo-path (not (empty? photo-path)))
(if-not (s/blank? photo-path)
[chat-icon photo-path styles]
[default-chat-icon name styles])
(when (not group-chat)
(when-not group-chat
[contact-online online styles])])
(defn chat-icon-view-chat-list [chat-id group-chat name color online]
@ -80,7 +81,7 @@
[contact [:contact]]
(let [;; TODO stub data
online true
color color-purple]
color color-purple]
[profile-icon-view (:photo-path contact) (:name contact) color online]))
(defview my-profile-icon []
@ -88,5 +89,5 @@
photo-path [:get :photo-path]]
(let [;; TODO stub data
online true
color color-purple]
color color-purple]
[profile-icon-view photo-path name color online]))

View File

@ -2,14 +2,14 @@
(:require [clojure.string :as s]
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
[reagent.core :as r]
[status-im.components.react :refer [android?
view
text
image
navigator
toolbar-android
drawer-layout-android
touchable-opacity]]
[status-im.components.react :refer [react
view
text
image
navigator
toolbar-android
drawer-layout-android
touchable-opacity]]
[status-im.resources :as res]
[status-im.components.drawer.styles :as st]
[status-im.i18n :refer [label]]))
@ -29,7 +29,7 @@
:style st/user-photo}])
(defn menu-item [{:keys [name handler]}]
[touchable-opacity {:style st/menu-item-touchable
[touchable-opacity {:style st/menu-item-touchable
:onPress (fn []
(close-drawer)
(handler))}
@ -40,40 +40,40 @@
(let [username (subscribe [:get :username])]
(fn []
[view st/drawer-menu
[view st/user-photo-container
[user-photo {}]]
[view st/name-container
[text {:style st/name-text}
@username]]
[view st/menu-items-container
[menu-item {:name (label :t/profile)
:handler #(dispatch [:navigate-to :my-profile])}]
[menu-item {:name (label :t/settings)
:handler (fn []
;; TODO not implemented
)}]
[menu-item {:name (label :t/discovery)
:handler #(dispatch [:navigate-to :discovery])}]
[menu-item {:name (label :t/contacts)
:handler #(dispatch [:show-contacts navigator])}]
[menu-item {:name (label :t/invite-friends)
:handler (fn []
;; TODO not implemented
)}]
[menu-item {:name (label :t/faq)
:handler (fn [])}]]
[view st/switch-users-container
[touchable-opacity {:onPress (fn []
(close-drawer)
;; TODO not implemented
)}
[text {:style st/switch-users-text}
(label :t/switch-users)]]]])))
[view st/user-photo-container
[user-photo {}]]
[view st/name-container
[text {:style st/name-text}
@username]]
[view st/menu-items-container
[menu-item {:name (label :t/profile)
:handler #(dispatch [:navigate-to :my-profile])}]
[menu-item {:name (label :t/settings)
:handler (fn []
;; TODO not implemented
)}]
[menu-item {:name (label :t/discovery)
:handler #(dispatch [:navigate-to :discovery])}]
[menu-item {:name (label :t/contacts)
:handler #(dispatch [:show-contacts navigator])}]
[menu-item {:name (label :t/invite-friends)
:handler (fn []
;; TODO not implemented
)}]
[menu-item {:name (label :t/faq)
:handler (fn [])}]]
[view st/switch-users-container
[touchable-opacity {:onPress (fn []
(close-drawer)
;; TODO not implemented
)}
[text {:style st/switch-users-text}
(label :t/switch-users)]]]])))
(defn drawer-view [items]
[drawer-layout-android {:drawerWidth 260
:drawerPosition js/React.DrawerLayoutAndroid.positions.Left
:render-navigation-view #(r/as-element [drawer-menu])
:ref (fn [drawer]
(reset! drawer-atom drawer))}
:ref (fn [drawer]
(reset! drawer-atom drawer))}
items])

View File

@ -1,6 +1,4 @@
(ns status-im.components.icons.ionicons
(:require [reagent.core :as r]))
(set! js/window.Ionicons (js/require "react-native-vector-icons/Ionicons"))
(def icon (r/adapt-react-class js/Ionicons))
(def icon (r/adapt-react-class (js/require "react-native-vector-icons/Ionicons")))

View File

@ -1,8 +1,8 @@
(ns status-im.components.invertible-scroll-view)
(ns status-im.components.invertible-scroll-view
(:require [reagent.core :as r]))
(set! js/window.InvertibleScrollView (js/require "react-native-invertible-scroll-view"))
(def class (js/require "react-native-invertible-scroll-view"))
(defn invertible-scroll-view [props]
(js/React.createElement js/InvertibleScrollView
(clj->js (merge {:inverted true} props))))
(r/create-element class (clj->js (merge {:inverted true} props))))

View File

@ -1,7 +1,5 @@
(ns status-im.components.item-checkbox
(:require [reagent.core :as r]))
(set! js/window.ItemCheckbox (js/require "react-native-circle-checkbox"))
(def item-checkbox (r/adapt-react-class js/ItemCheckbox))
(def item-checkbox (r/adapt-react-class (js/require "react-native-circle-checkbox")))

View File

@ -1,26 +1,36 @@
(ns status-im.components.react
(:require [reagent.core :as r]
[status-im.components.styles :as st]))
[status-im.components.styles :as st]
[status-im.utils.utils :as u]))
(set! js/window.React (js/require "react-native"))
(def react (u/require "react-native"))
(def app-registry (.-AppRegistry js/React))
(def navigator (r/adapt-react-class (.-Navigator js/React)))
(def text (r/adapt-react-class (.-Text js/React)))
(def view (r/adapt-react-class (.-View js/React)))
(def image (r/adapt-react-class (.-Image js/React)))
(def touchable-highlight-class (r/adapt-react-class (.-TouchableHighlight js/React)))
(defn get-react-property [name]
(aget react name))
(defn adapt-class [class]
(when class (r/adapt-react-class class)))
(defn get-class [name]
(adapt-class (get-react-property name)))
(def app-registry (get-react-property "AppRegistry"))
(def navigator (get-class "Navigator"))
(def text (get-class "Text"))
(def view (get-class "View"))
(def image (get-class "Image"))
(def touchable-highlight-class (get-class "TouchableHighlight"))
(defn touchable-highlight [props content]
[touchable-highlight-class
(merge {:underlay-color :transparent} props)
content])
(def toolbar-android (r/adapt-react-class (.-ToolbarAndroid js/React)))
(def list-view-class (r/adapt-react-class (.-ListView js/React)))
(def toolbar-android (get-class "ToolbarAndroid"))
(def list-view-class (get-class "ListView"))
(defn list-view [props]
[list-view-class (merge {:enableEmptySections true} props)])
(def scroll-view (r/adapt-react-class (.-ScrollView js/React)))
(def touchable-without-feedback (r/adapt-react-class (.-TouchableWithoutFeedback js/React)))
(def text-input-class (r/adapt-react-class (.-TextInput js/React)))
(def scroll-view (get-class "ScrollView"))
(def touchable-without-feedback (get-class "TouchableWithoutFeedback"))
(def text-input-class (get-class "TextInput"))
(defn text-input [props text]
[text-input-class (merge
{:underlineColorAndroid :transparent
@ -28,11 +38,13 @@
:placeholder "Type"}
props)
text])
(def drawer-layout-android (r/adapt-react-class (.-DrawerLayoutAndroid js/React)))
(def touchable-opacity (r/adapt-react-class (.-TouchableOpacity js/React)))
(def modal (r/adapt-react-class (.-Modal js/React)))
(def picker (r/adapt-react-class (.-Picker js/React)))
(def picker-item (r/adapt-react-class (.-Item (.-Picker js/React))))
(def drawer-layout-android (get-class "DrawerLayoutAndroid"))
(def touchable-opacity (get-class "TouchableOpacity"))
(def modal (get-class "Modal"))
(def picker (get-class "Picker"))
(def picker-item
(when-let [picker (get-react-property "Picker")]
(adapt-class (.-Item picker))))
(defn icon
@ -41,20 +53,18 @@
[image {:source {:uri (keyword (str "icon_" (name n)))}
:style style}]))
;(def react-linear-gradient (.-default (js/require "react-native-linear-gradient")))
;(def linear-gradient (r/adapt-react-class react-linear-gradient))
(set! js/window.LinearGradient (js/require "react-native-linear-gradient"))
(def linear-gradient-class (u/require "react-native-linear-gradient"))
(defn linear-gradient [props]
(js/React.createElement js/LinearGradient
(clj->js (merge {:inverted true} props))))
(r/create-element linear-gradient-class
(clj->js (merge {:inverted true} props))))
(def platform (.. js/React -Platform -OS))
(def platform
(when-let [pl (.-Platform react)] (.-OS pl)))
(def android? (= platform "android"))
(defn list-item [component]
(r/as-element component))
(def dismiss-keyboard! (js/require "dismissKeyboard"))
(def dismiss-keyboard! (u/require "dismissKeyboard"))

View File

@ -1,9 +0,0 @@
(ns status-im.components.realm
(:require [reagent.core :as r]))
(set! js/window.RealmReactNative (js/require "realm/react-native"))
(def list-view-class (r/adapt-react-class (.-ListView js/RealmReactNative)))
(defn list-view [props]
[list-view-class (merge {:enableEmptySections true} props)])

View File

@ -16,9 +16,7 @@
toolbar-title-container
toolbar-title-text
icon-back
toolbar-height]]
[status-im.components.realm :refer [list-view]]
[reagent.core :as r]))
toolbar-height]]))
(defn toolbar [{:keys [title nav-action hide-nav? action custom-action
background-color custom-content style]}]

View File

@ -5,7 +5,8 @@
[clojure.string :as s]
[status-im.utils.utils :refer [http-post]]
[status-im.utils.phone-number :refer [format-phone-number]]
[status-im.utils.handlers :as u]))
[status-im.utils.handlers :as u]
[status-im.utils.utils :refer [require]]))
(defn save-contact
[_ [_ contact]]
@ -26,7 +27,7 @@
(register-handler :load-contacts load-contacts!)
;; TODO see https://github.com/rt2zz/react-native-contacts/issues/45
(def react-native-contacts (js/require "react-native-contacts"))
(def react-native-contacts (require "react-native-contacts"))
(defn contact-name [contact]
(->> contact
@ -91,10 +92,14 @@
(defn add-new-contacts
[{:keys [contacts] :as db} [_ new-contacts]]
(let [identities (set (map :whisper-identity contacts))
new-contacts' (remove #(identities (:whisper-identity %)) new-contacts)]
new-contacts' (->> new-contacts
(remove #(identities (:whisper-identity %)))
(map #(vector (:whisper-identity %) %))
(into {}))]
(println new-contacts')
(-> db
(update :contacts concat new-contacts')
(assoc :new-contacts new-contacts'))))
(update :contacts merge new-contacts')
(assoc :new-contacts (vals new-contacts')))))
(register-handler :add-contacts
(after save-contacts!)

View File

@ -2,16 +2,16 @@
(:require-macros [status-im.utils.views :refer [defview]])
(:require
[re-frame.core :refer [subscribe]]
[status-im.utils.logging :as log]
[status-im.components.react :refer [android?
text]]
[status-im.components.carousel.carousel :refer [carousel]]
[status-im.discovery.styles :as st]
[status-im.discovery.views.popular-list :refer [discovery-popular-list]]
[status-im.i18n :refer [label]]))
[status-im.i18n :refer [label]]
[status-im.components.react :as r]))
(defn page-width []
(.-width (.get (.. js/React -Dimensions) "window")))
(.-width (.get (.. r/react -Dimensions) "window")))
(defview popular []
[popular-tags [:get-popular-tags 3]]

View File

@ -36,15 +36,19 @@
;; -- Common --------------------------------------------------------------
(defn set-el [db [_ k v]]
(assoc db k v))
(register-handler :set
(debug
(fn [db [_ k v]]
(assoc db k v))))
debug
set-el)
(defn set-in [db [_ path v]]
(assoc-in db path v))
(register-handler :set-in
(debug
(fn [db [_ path v]]
(assoc-in db path v))))
debug
set-in)
(register-handler :initialize-db
(fn [_ _]

View File

@ -1,25 +1,23 @@
(ns status-im.i18n
(:require
[status-im.translations.en :as en]))
[status-im.translations.en :as en]
[status-im.utils.utils :as u]))
(set! js/window.I18n (js/require "react-native-i18n"))
(set! (.-fallbacks js/I18n) true)
(set! (.-defaultSeparator js/I18n) "/")
(def i18n (u/require "react-native-i18n"))
(set! (.-fallbacks i18n) true)
(set! (.-defaultSeparator i18n) "/")
(set! (.-translations js.I18n) (clj->js {:en en/translations}))
(set! (.-translations i18n) (clj->js {:en en/translations}))
(defn label
([path] (label path {}))
([path options]
(.t js/I18n (name path) (clj->js options))))
(if (exists? i18n.t)
(.t i18n (name path) (clj->js options))
(name path))))
(comment
(defn deep-merge [& maps]
(if (every? map? maps)
(apply merge-with deep-merge maps)
(last maps)))
(defn add-translations [new-translations]
(let [translations (.-translations js/I18n)]
(set! (.-translations js/I18n) (clj->js (deep-merge (js->clj translations) new-translations)))))
)
(defn label-pluralize [count path & options]
(if (exists? i18n.t)
(.p i18n count (name path) (clj->js options))
(name path)))

View File

@ -2,11 +2,10 @@
(:require [cljs.reader :refer [read-string]]
[status-im.components.styles :refer [default-chat-color]]
[status-im.utils.logging :as log]
[status-im.utils.types :refer [to-string]])
[status-im.utils.types :refer [to-string]]
[status-im.utils.utils :as u])
(:refer-clojure :exclude [exists?]))
(set! js/window.Realm (js/require "realm"))
(def opts {:schema [{:name :contacts
:primaryKey :whisper-identity
:properties {:phone-number {:type "string"
@ -70,7 +69,10 @@
:objectType "tag"}
:last-updated "date"}}]})
(def realm (js/Realm. (clj->js opts)))
(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}]

View File

@ -2,14 +2,14 @@
(:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [subscribe dispatch]]
[status-im.components.react :refer [view
text
image
icon
scroll-view
touchable-highlight
touchable-opacity]]
text
image
icon
scroll-view
touchable-highlight
touchable-opacity]]
[status-im.components.chat-icon.screen :refer [profile-icon
my-profile-icon]]
my-profile-icon]]
[status-im.profile.styles :as st]
[status-im.components.qr-code :refer [qr-code]]
[status-im.utils.types :refer [clj->json]]
@ -62,13 +62,13 @@
[text {:style st/report-user-text} (label :t/report-user)]]]]])
(defview my-profile []
[username [:get :username]
photo-path [:get :photo-path]
[username [:get :username]
photo-path [:get :photo-path]
phone-number [:get :phone-number]
email [:get :email]
status [:get :status]
email [:get :email]
status [:get :status]
identity [:get-in [:user-identity :public]]]
[view {:style st/profile}
[scroll-view {:style st/profile}
[touchable-highlight {:style st/back-btn-touchable
:on-press #(dispatch [:navigate-back])}
[view st/back-btn-container

View File

@ -1,9 +1,10 @@
(ns status-im.utils.crypt
(:require [goog.crypt :refer [byteArrayToHex]]
[clojure.string :as s])
[clojure.string :as s]
[status-im.utils.utils :as u])
(:import goog.crypt.Sha256))
(set! js/window.RnRandomBytes (js/require "react-native-randombytes"))
(def random-bytes (u/require "react-native-randombytes"))
(def sha-256 (Sha256.))
@ -19,7 +20,7 @@
(byteArrayToHex (.digest sha-256)))
(defn gen-random-bytes [length cb]
(.randomBytes js/window.RnRandomBytes length (fn [& [err buf]]
(if err
(cb {:error err})
(cb {:buffer buf})))))
#_(.randomBytes random-bytes length (fn [& [err buf]]
(if err
(cb {:error err})
(cb {:buffer buf})))))

View File

@ -1,6 +1,5 @@
(ns status-im.utils.listview
(:require-macros [natal-shell.data-source :refer [data-source]])
(:require [status-im.components.realm]))
(:require-macros [natal-shell.data-source :refer [data-source]]))
(defn clone-with-rows [ds rows]
(.cloneWithRows ds (reduce (fn [ac el] (.push ac el) ac)

View File

@ -1,16 +1,17 @@
(ns status-im.utils.phone-number)
(ns status-im.utils.phone-number
(:require [status-im.utils.utils :as u]))
(def i18n (js/require "react-native-i18n"))
(def locale (.-locale i18n))
(def i18n (u/require "react-native-i18n"))
(def locale (or (.-locale i18n) "___en"))
(def country-code (subs locale 3 5))
(set! js/PhoneNumber (js/require "awesome-phonenumber"))
(def awesome-phonenumber (u/require "awesome-phonenumber"))
;; todo check wrong numbers, .getNumber returns empty string
(defn format-phone-number [number]
(str (.getNumber (js/PhoneNumber. number country-code "international"))))
(str (.getNumber (awesome-phonenumber. number country-code "international"))))
(defn valid-mobile-number? [number]
(when (string? number)
(let [number-obj (js/PhoneNumber. number country-code "international")]
(let [number-obj (awesome-phonenumber. number country-code "international")]
(and (.isValid number-obj)
(.isMobile number-obj)))))

View File

@ -1,7 +1,8 @@
(ns status-im.utils.sms-listener
(:require [status-im.components.react :refer [android?]]))
(:require [status-im.components.react :refer [android?]]
[status-im.utils.utils :as u]))
(def sms-listener (.-default (js/require "react-native-android-sms-listener")))
(def sms-listener (.-default (u/require "react-native-android-sms-listener")))
;; Only android is supported!

View File

@ -5,6 +5,11 @@
[natal-shell.toast-android :as toast])
(:require [status-im.constants :as const]))
(defn require [module]
(if (exists? js/window)
(js/require module)
#js {}))
(defn log [obj]
(.log js/console obj))

View File

@ -0,0 +1,86 @@
(ns status-im.appium
(:require [clojure.java.io :as io]
[clojure.test :refer :all])
(:import (org.openqa.selenium.remote DesiredCapabilities)
(org.openqa.selenium By)
(io.appium.java_client.android AndroidDriver)
(java.net URL)
(java.util.concurrent TimeUnit)))
(defn init []
(let [dir (io/file (str (System/getProperty "user.dir")
"/android/app/build/outputs/apk"))
app (io/file dir "app-debug.apk")
capabilities (doto (DesiredCapabilities.)
(.setCapability "deviceName" "device")
(.setCapability "platformVersion" "6.0.0")
(.setCapability "app" (.getAbsolutePath app))
(.setCapability "appPackage" "com.statusim")
(.setCapability "appActivity" ".MainActivity"))
driver (AndroidDriver. (URL. "http://127.0.0.1:4723/wd/hub") capabilities)]
(-> driver
.manage
.timeouts
(.implicitlyWait 25 TimeUnit/SECONDS))
driver))
(defn by-xpath [driver xpath]
(.findElement driver (By/xpath xpath)))
(defn elements-by-xpath [driver xpath]
(.findElements driver (By/xpath xpath)))
(defn by-id [driver id]
(.findElementByAccessibilityId driver (name id)))
(defn get-element [driver id]
(if (keyword? id)
(by-id driver id)
(by-xpath driver id)))
(defn click [driver id]
(.click (get-element driver id)))
(defn write [driver input-xpath text]
(.sendKeys (get-element driver input-xpath) (into-array [text])))
(defn get-text [driver xpath]
(.getText (by-xpath driver xpath)))
(defn xpath-by-text [text]
(str ".//*[@text='" text "']"))
(defn contains-text [driver text]
(is (= 1 (->> (xpath-by-text text)
(elements-by-xpath driver)
(.size)))))
(defn quit [driver]
(.quit driver))
(defmacro appium-test
"Defines test which will create new appium session and will pass that
session as first argument to each command inside it's body. After execution
of all commands session will be closed.
For instance,
(appium-test my-test
(click :button)
(write :input \"oops\"))
will be expanded to
(deftest my-test
(let [session (init)]
(click session :button)
(write session :input \"oops\")
(quit session)))"
[name & body]
(let [sym (gensym)]
`(deftest ~name
(let [~sym (init)]
~@(for [[f & rest] body]
`(~f ~sym ~@rest))
(quit ~sym)))))

View File

@ -0,0 +1,15 @@
(ns status-im.console
(:require [clojure.test :refer :all]
[status-im.appium :refer :all]))
(def message-text
(str "Your phone number is also required to use the app. Type"
" the exclamation mark or hit the icon to open the command "
"list and choose the !phone command"))
(appium-test console-test
(click :request-keypair-password)
(write :command-input "123")
(click :stage-command)
(click :send-message)
(contains-text message-text))

View File

@ -0,0 +1,6 @@
(ns status-im.test.handlers
(:require [cljs.test :refer-macros [deftest is]]
[status-im.handlers :as h]))
(deftest test-set-val
(is (= {:key :val} (h/set-el {} [nil :key :val]))))

View File

@ -0,0 +1,5 @@
(ns status-im.test.runner
(:require [doo.runner :refer-macros [doo-tests]]
[status-im.test.handlers]))
(doo-tests 'status-im.test.handlers)

View File

@ -1,7 +0,0 @@
(ns status-im.core-test
(:require [clojure.test :refer :all]
[status-im.core :refer :all]))
(deftest a-test
(testing "FIXME, I fail."
(is (= 0 1))))