commit
23a17b2632
|
@ -50,3 +50,12 @@ target/
|
||||||
#
|
#
|
||||||
figwheel_server.log
|
figwheel_server.log
|
||||||
.nrepl-port
|
.nrepl-port
|
||||||
|
|
||||||
|
# Lein
|
||||||
|
#
|
||||||
|
.lein-failures
|
||||||
|
|
||||||
|
## Doo
|
||||||
|
#
|
||||||
|
out
|
||||||
|
doo-index.html
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "StatusIm",
|
"name": "StatusIm",
|
||||||
"interface": "reagent",
|
"interface": "reagent",
|
||||||
"androidHost": "localhost",
|
"androidHost": "10.0.3.2",
|
||||||
"modules": [
|
"modules": [
|
||||||
"react-native-contacts",
|
"react-native-contacts",
|
||||||
"react-native-invertible-scroll-view",
|
"react-native-invertible-scroll-view",
|
||||||
|
|
|
@ -8,11 +8,18 @@ import com.facebook.react.shell.MainReactPackage;
|
||||||
import com.rt2zz.reactnativecontacts.ReactNativeContacts;
|
import com.rt2zz.reactnativecontacts.ReactNativeContacts;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Environment;
|
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.github.ethereum.go_ethereum.cmd.Geth;
|
||||||
import com.bitgo.randombytes.RandomBytesPackage;
|
import com.bitgo.randombytes.RandomBytesPackage;
|
||||||
import com.BV.LinearGradient.LinearGradientPackage;
|
import com.BV.LinearGradient.LinearGradientPackage;
|
||||||
import com.centaurwarchief.smslistener.SmsListener;
|
import com.centaurwarchief.smslistener.SmsListener;
|
||||||
|
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
@ -25,15 +32,10 @@ import io.realm.react.RealmReactPackage;
|
||||||
|
|
||||||
public class MainActivity extends ReactActivity {
|
public class MainActivity extends ReactActivity {
|
||||||
|
|
||||||
@Override
|
final Handler handler = new Handler();
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
// Required for android-16 (???)
|
protected void startStatus() {
|
||||||
System.loadLibrary("gethraw");
|
// Required because of crazy APN settings redirecting localhost (found in GB)
|
||||||
System.loadLibrary("geth");
|
|
||||||
|
|
||||||
// Required because of crazy APN settings redirecting localhost
|
|
||||||
Properties properties = System.getProperties();
|
Properties properties = System.getProperties();
|
||||||
properties.setProperty("http.nonProxyHosts", "localhost|127.0.0.1");
|
properties.setProperty("http.nonProxyHosts", "localhost|127.0.0.1");
|
||||||
properties.setProperty("https.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;
|
getApplicationInfo().dataDir;
|
||||||
|
|
||||||
// Launch!
|
// 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() {
|
new Thread(new Runnable() {
|
||||||
public void run() {
|
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();
|
}).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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,6 @@
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">StatusIm</string>
|
<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>
|
</resources>
|
18
project.clj
18
project.clj
|
@ -8,7 +8,7 @@
|
||||||
[reagent "0.5.1" :exclusions [cljsjs/react]]
|
[reagent "0.5.1" :exclusions [cljsjs/react]]
|
||||||
[re-frame "0.6.0"]
|
[re-frame "0.6.0"]
|
||||||
[prismatic/schema "1.0.4"]
|
[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"}}
|
:branch "master"}}
|
||||||
[status-im/protocol "0.1.1-20160525_083359-g53ab2c2"]
|
[status-im/protocol "0.1.1-20160525_083359-g53ab2c2"]
|
||||||
[natal-shell "0.1.6"]
|
[natal-shell "0.1.6"]
|
||||||
|
@ -20,9 +20,12 @@
|
||||||
["do" "clean"
|
["do" "clean"
|
||||||
["with-profile" "prod" "cljsbuild" "once" "ios"]
|
["with-profile" "prod" "cljsbuild" "once" "ios"]
|
||||||
["with-profile" "prod" "cljsbuild" "once" "android"]]}
|
["with-profile" "prod" "cljsbuild" "once" "android"]]}
|
||||||
|
:test-paths ["test/clj"]
|
||||||
:figwheel {:nrepl-port 7888}
|
:figwheel {:nrepl-port 7888}
|
||||||
:profiles {:dev {:dependencies [[figwheel-sidecar "0.5.0-2"]
|
: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"]
|
:source-paths ["src" "env/dev"]
|
||||||
:cljsbuild {:builds {:ios {:source-paths ["src" "env/dev"]
|
:cljsbuild {:builds {:ios {:source-paths ["src" "env/dev"]
|
||||||
:figwheel true
|
:figwheel true
|
||||||
|
@ -35,7 +38,13 @@
|
||||||
:compiler {:output-to "target/android/not-used.js"
|
:compiler {:output-to "target/android/not-used.js"
|
||||||
:main "env.android.main"
|
:main "env.android.main"
|
||||||
:output-dir "target/android"
|
: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]}}
|
:repl-options {:nrepl-middleware [cemerick.piggieback/wrap-cljs-repl]}}
|
||||||
:prod {:cljsbuild {:builds {:ios {:source-paths ["src" "env/prod"]
|
:prod {:cljsbuild {:builds {:ios {:source-paths ["src" "env/prod"]
|
||||||
:compiler {:output-to "index.ios.js"
|
:compiler {:output-to "index.ios.js"
|
||||||
|
@ -46,5 +55,4 @@
|
||||||
:compiler {:output-to "index.android.js"
|
:compiler {:output-to "index.android.js"
|
||||||
:main "env.android.main"
|
:main "env.android.main"
|
||||||
:output-dir "target/android"
|
:output-dir "target/android"
|
||||||
:optimizations :simple}}}}
|
:optimizations :simple}}}}}})
|
||||||
}})
|
|
||||||
|
|
17
run-osx.sh
17
run-osx.sh
|
@ -17,14 +17,16 @@ function tab () {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
osascript &>/dev/null <<EOF
|
osascript &>/dev/null <<EOF
|
||||||
tell application "iTerm"
|
tell application "iTerm2"
|
||||||
tell current terminal
|
tell current window
|
||||||
launch session "Default Session"
|
set newTab to (create tab with default profile)
|
||||||
tell the last session
|
tell newTab
|
||||||
|
tell current session
|
||||||
write text "cd \"$cdto\"$cmd"
|
write text "cd \"$cdto\"$cmd"
|
||||||
end tell
|
end tell
|
||||||
end tell
|
end tell
|
||||||
end tell
|
end tell
|
||||||
|
end tell
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,3 +61,10 @@ sleep 10s
|
||||||
adb reverse tcp:8081 tcp:8081 && adb reverse tcp:3449 tcp:3449
|
adb reverse tcp:8081 tcp:8081 && adb reverse tcp:3449 tcp:3449
|
||||||
|
|
||||||
react-native run-android
|
react-native run-android
|
||||||
|
|
||||||
|
if [ ! -z $2 ]
|
||||||
|
then
|
||||||
|
tab "appium"
|
||||||
|
lein test
|
||||||
|
lein doo node test once
|
||||||
|
fi
|
|
@ -1 +1,4 @@
|
||||||
(ns cljsjs.react)
|
(ns cljsjs.react)
|
||||||
|
|
||||||
|
(when (exists? js/window)
|
||||||
|
(set! js/window.React (js/require "react-native")))
|
||||||
|
|
|
@ -230,9 +230,9 @@
|
||||||
(sign-up-service/stop-listening-confirmation-code-sms db)))
|
(sign-up-service/stop-listening-confirmation-code-sms db)))
|
||||||
|
|
||||||
(register-handler :sign-up-confirm
|
(register-handler :sign-up-confirm
|
||||||
(fn [db [_ confirmation-code]]
|
(u/side-effect!
|
||||||
(server/sign-up-confirm confirmation-code sign-up-service/on-send-code-response)
|
(fn [_ [_ confirmation-code]]
|
||||||
db))
|
(server/sign-up-confirm confirmation-code sign-up-service/on-send-code-response))))
|
||||||
|
|
||||||
(register-handler :set-signed-up
|
(register-handler :set-signed-up
|
||||||
(fn [db [_ signed-up]]
|
(fn [db [_ signed-up]]
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
[status-im.components.toolbar :refer [toolbar]]
|
[status-im.components.toolbar :refer [toolbar]]
|
||||||
[status-im.chat.views.message :refer [chat-message]]
|
[status-im.chat.views.message :refer [chat-message]]
|
||||||
[status-im.chat.views.new-message :refer [chat-message-new]]
|
[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]
|
(defn contacts-by-identity [contacts]
|
||||||
|
@ -186,7 +186,7 @@
|
||||||
[icon :group st/group-icon]
|
[icon :group st/group-icon]
|
||||||
[text {:style st/members}
|
[text {:style st/members}
|
||||||
(let [cnt (inc (count @contacts))]
|
(let [cnt (inc (count @contacts))]
|
||||||
(label :t/members {:count cnt}))]]
|
(label-pluralize cnt :t/members))]]
|
||||||
;; TODO stub data: last activity
|
;; TODO stub data: last activity
|
||||||
[text {:style st/last-activity} (label :t/last-active)])])))
|
[text {:style st/last-activity} (label :t/last-active)])])))
|
||||||
|
|
||||||
|
|
|
@ -38,11 +38,13 @@
|
||||||
:onChangeText set-input-message
|
:onChangeText set-input-message
|
||||||
:onSubmitEditing (fn []
|
:onSubmitEditing (fn []
|
||||||
(when (valid? message validator)
|
(when (valid? message validator)
|
||||||
(send-command)))}
|
(send-command)))
|
||||||
|
:accessibility-label :command-input}
|
||||||
input-options)
|
input-options)
|
||||||
message]
|
message]
|
||||||
(if (valid? message validator)
|
(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]]]
|
[view st/send-container [icon :send st/send-icon]]]
|
||||||
[touchable-highlight {:on-press cancel-command-input}
|
[touchable-highlight {:on-press cancel-command-input}
|
||||||
[view st/cancel-container
|
[view st/cancel-container
|
||||||
|
|
|
@ -72,13 +72,18 @@
|
||||||
(defn set-chat-command [msg-id command]
|
(defn set-chat-command [msg-id command]
|
||||||
(dispatch [:set-response-chat-command msg-id (:command command)]))
|
(dispatch [:set-response-chat-command msg-id (:command command)]))
|
||||||
|
|
||||||
|
(defn label [{:keys [command]}]
|
||||||
|
(->> (name command)
|
||||||
|
(str "request-")))
|
||||||
|
|
||||||
(defn message-content-command-request
|
(defn message-content-command-request
|
||||||
[{:keys [msg-id content from incoming-group]}]
|
[{:keys [msg-id content from incoming-group]}]
|
||||||
(let [commands-atom (subscribe [:get-commands])]
|
(let [commands-atom (subscribe [:get-commands])]
|
||||||
(fn [{:keys [msg-id content from incoming-group]}]
|
(fn [{:keys [msg-id content from incoming-group]}]
|
||||||
(let [commands @commands-atom
|
(let [commands @commands-atom
|
||||||
{:keys [command content]} (parse-command-request commands content)]
|
{: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/comand-request-view
|
||||||
[view st/command-request-message-view
|
[view st/command-request-message-view
|
||||||
(when incoming-group
|
(when incoming-group
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
;; TODO emoticons: not implemented
|
;; TODO emoticons: not implemented
|
||||||
[icon :smile st/smile-icon]
|
[icon :smile st/smile-icon]
|
||||||
(when (message-valid? @staged-commands-atom input-message)
|
(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
|
[view st/send-container
|
||||||
[icon :send st/send-icon]]])]]))))
|
[icon :send st/send-icon]]])]]))))
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
[drawer-view
|
[drawer-view
|
||||||
[view st/chats-container
|
[view st/chats-container
|
||||||
[chats-list-toolbar]
|
[chats-list-toolbar]
|
||||||
[list-view {:dataSource (to-datasource (vals @chats))
|
[list-view {:dataSource (to-datasource @chats)
|
||||||
:renderRow (fn [row _ _]
|
:renderRow (fn [row _ _]
|
||||||
(list-item [chat-list-item row]))
|
(list-item [chat-list-item row]))
|
||||||
:style st/list-container}]
|
:style st/list-container}]
|
||||||
|
|
|
@ -8,10 +8,11 @@
|
||||||
[status-im.chats-list.views.inner-item :refer
|
[status-im.chats-list.views.inner-item :refer
|
||||||
[chat-list-item-inner-view]]))
|
[chat-list-item-inner-view]]))
|
||||||
|
|
||||||
(defn chat-list-item [{:keys [chat-id] :as chat}]
|
(defn chat-list-item [[chat-id chat]]
|
||||||
[touchable-highlight
|
[touchable-highlight
|
||||||
{:on-press #(dispatch [:navigate-to :chat chat-id])}
|
{:on-press #(dispatch [:navigate-to :chat chat-id])}
|
||||||
[view [chat-list-item-inner-view (merge chat
|
[view [chat-list-item-inner-view (merge chat
|
||||||
;; TODO stub data
|
;; TODO stub data
|
||||||
{:new-messages-count 3
|
{:chat-id chat-id
|
||||||
|
:new-messages-count 3
|
||||||
:online true})]]])
|
:online true})]]])
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
(ns status-im.components.action-button
|
(ns status-im.components.action-button
|
||||||
(:require [reagent.core :as r]))
|
(: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 (r/adapt-react-class (.-default class)))
|
||||||
(def action-button-item (r/adapt-react-class (.. js/ActionButton -default -Item)))
|
(def action-button-item (r/adapt-react-class (.. class -default -Item)))
|
||||||
|
|
|
@ -5,11 +5,12 @@
|
||||||
touchable-without-feedback
|
touchable-without-feedback
|
||||||
text]]
|
text]]
|
||||||
[status-im.components.carousel.styles :as st]
|
[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 []
|
(defn window-page-width []
|
||||||
(.-width (.get (.. js/React -Dimensions) "window")))
|
(.-width (.get (.. r/react -Dimensions) "window")))
|
||||||
|
|
||||||
(def defaults {:gap 10
|
(def defaults {:gap 10
|
||||||
:sneak 10
|
:sneak 10
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
image
|
image
|
||||||
icon]]
|
icon]]
|
||||||
[status-im.components.chat-icon.styles :as st]
|
[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]
|
(defn default-chat-icon [name styles]
|
||||||
[view (:default-chat-icon styles)
|
[view (:default-chat-icon styles)
|
||||||
|
@ -26,10 +27,10 @@
|
||||||
(defview chat-icon-view [chat-id group-chat name online styles]
|
(defview chat-icon-view [chat-id group-chat name online styles]
|
||||||
[photo-path [:chat-photo chat-id]]
|
[photo-path [:chat-photo chat-id]]
|
||||||
[view (:container styles)
|
[view (:container styles)
|
||||||
(if (and photo-path (not (empty? photo-path)))
|
(if-not (s/blank? photo-path)
|
||||||
[chat-icon photo-path styles]
|
[chat-icon photo-path styles]
|
||||||
[default-chat-icon name styles])
|
[default-chat-icon name styles])
|
||||||
(when (not group-chat)
|
(when-not group-chat
|
||||||
[contact-online online styles])])
|
[contact-online online styles])])
|
||||||
|
|
||||||
(defn chat-icon-view-chat-list [chat-id group-chat name color online]
|
(defn chat-icon-view-chat-list [chat-id group-chat name color online]
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
(:require [clojure.string :as s]
|
(:require [clojure.string :as s]
|
||||||
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||||
[reagent.core :as r]
|
[reagent.core :as r]
|
||||||
[status-im.components.react :refer [android?
|
[status-im.components.react :refer [react
|
||||||
view
|
view
|
||||||
text
|
text
|
||||||
image
|
image
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
(ns status-im.components.icons.ionicons
|
(ns status-im.components.icons.ionicons
|
||||||
(:require [reagent.core :as r]))
|
(:require [reagent.core :as r]))
|
||||||
|
|
||||||
(set! js/window.Ionicons (js/require "react-native-vector-icons/Ionicons"))
|
(def icon (r/adapt-react-class (js/require "react-native-vector-icons/Ionicons")))
|
||||||
|
|
||||||
(def icon (r/adapt-react-class js/Ionicons))
|
|
||||||
|
|
|
@ -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]
|
(defn invertible-scroll-view [props]
|
||||||
(js/React.createElement js/InvertibleScrollView
|
(r/create-element class (clj->js (merge {:inverted true} props))))
|
||||||
(clj->js (merge {:inverted true} props))))
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
(ns status-im.components.item-checkbox
|
(ns status-im.components.item-checkbox
|
||||||
(:require [reagent.core :as r]))
|
(:require [reagent.core :as r]))
|
||||||
|
|
||||||
(set! js/window.ItemCheckbox (js/require "react-native-circle-checkbox"))
|
(def item-checkbox (r/adapt-react-class (js/require "react-native-circle-checkbox")))
|
||||||
|
|
||||||
(def item-checkbox (r/adapt-react-class js/ItemCheckbox))
|
|
||||||
|
|
||||||
|
|
|
@ -1,26 +1,36 @@
|
||||||
(ns status-im.components.react
|
(ns status-im.components.react
|
||||||
(:require [reagent.core :as r]
|
(: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))
|
(defn get-react-property [name]
|
||||||
(def navigator (r/adapt-react-class (.-Navigator js/React)))
|
(aget react name))
|
||||||
(def text (r/adapt-react-class (.-Text js/React)))
|
|
||||||
(def view (r/adapt-react-class (.-View js/React)))
|
(defn adapt-class [class]
|
||||||
(def image (r/adapt-react-class (.-Image js/React)))
|
(when class (r/adapt-react-class class)))
|
||||||
(def touchable-highlight-class (r/adapt-react-class (.-TouchableHighlight js/React)))
|
|
||||||
|
(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]
|
(defn touchable-highlight [props content]
|
||||||
[touchable-highlight-class
|
[touchable-highlight-class
|
||||||
(merge {:underlay-color :transparent} props)
|
(merge {:underlay-color :transparent} props)
|
||||||
content])
|
content])
|
||||||
(def toolbar-android (r/adapt-react-class (.-ToolbarAndroid js/React)))
|
(def toolbar-android (get-class "ToolbarAndroid"))
|
||||||
(def list-view-class (r/adapt-react-class (.-ListView js/React)))
|
(def list-view-class (get-class "ListView"))
|
||||||
(defn list-view [props]
|
(defn list-view [props]
|
||||||
[list-view-class (merge {:enableEmptySections true} props)])
|
[list-view-class (merge {:enableEmptySections true} props)])
|
||||||
(def scroll-view (r/adapt-react-class (.-ScrollView js/React)))
|
(def scroll-view (get-class "ScrollView"))
|
||||||
(def touchable-without-feedback (r/adapt-react-class (.-TouchableWithoutFeedback js/React)))
|
(def touchable-without-feedback (get-class "TouchableWithoutFeedback"))
|
||||||
(def text-input-class (r/adapt-react-class (.-TextInput js/React)))
|
(def text-input-class (get-class "TextInput"))
|
||||||
(defn text-input [props text]
|
(defn text-input [props text]
|
||||||
[text-input-class (merge
|
[text-input-class (merge
|
||||||
{:underlineColorAndroid :transparent
|
{:underlineColorAndroid :transparent
|
||||||
|
@ -28,11 +38,13 @@
|
||||||
:placeholder "Type"}
|
:placeholder "Type"}
|
||||||
props)
|
props)
|
||||||
text])
|
text])
|
||||||
(def drawer-layout-android (r/adapt-react-class (.-DrawerLayoutAndroid js/React)))
|
(def drawer-layout-android (get-class "DrawerLayoutAndroid"))
|
||||||
(def touchable-opacity (r/adapt-react-class (.-TouchableOpacity js/React)))
|
(def touchable-opacity (get-class "TouchableOpacity"))
|
||||||
(def modal (r/adapt-react-class (.-Modal js/React)))
|
(def modal (get-class "Modal"))
|
||||||
(def picker (r/adapt-react-class (.-Picker js/React)))
|
(def picker (get-class "Picker"))
|
||||||
(def picker-item (r/adapt-react-class (.-Item (.-Picker js/React))))
|
(def picker-item
|
||||||
|
(when-let [picker (get-react-property "Picker")]
|
||||||
|
(adapt-class (.-Item picker))))
|
||||||
|
|
||||||
|
|
||||||
(defn icon
|
(defn icon
|
||||||
|
@ -41,20 +53,18 @@
|
||||||
[image {:source {:uri (keyword (str "icon_" (name n)))}
|
[image {:source {:uri (keyword (str "icon_" (name n)))}
|
||||||
:style style}]))
|
:style style}]))
|
||||||
|
|
||||||
;(def react-linear-gradient (.-default (js/require "react-native-linear-gradient")))
|
(def linear-gradient-class (u/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"))
|
|
||||||
(defn linear-gradient [props]
|
(defn linear-gradient [props]
|
||||||
(js/React.createElement js/LinearGradient
|
(r/create-element linear-gradient-class
|
||||||
(clj->js (merge {:inverted true} props))))
|
(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"))
|
(def android? (= platform "android"))
|
||||||
|
|
||||||
(defn list-item [component]
|
(defn list-item [component]
|
||||||
(r/as-element component))
|
(r/as-element component))
|
||||||
|
|
||||||
(def dismiss-keyboard! (js/require "dismissKeyboard"))
|
(def dismiss-keyboard! (u/require "dismissKeyboard"))
|
||||||
|
|
|
@ -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)])
|
|
|
@ -16,9 +16,7 @@
|
||||||
toolbar-title-container
|
toolbar-title-container
|
||||||
toolbar-title-text
|
toolbar-title-text
|
||||||
icon-back
|
icon-back
|
||||||
toolbar-height]]
|
toolbar-height]]))
|
||||||
[status-im.components.realm :refer [list-view]]
|
|
||||||
[reagent.core :as r]))
|
|
||||||
|
|
||||||
(defn toolbar [{:keys [title nav-action hide-nav? action custom-action
|
(defn toolbar [{:keys [title nav-action hide-nav? action custom-action
|
||||||
background-color custom-content style]}]
|
background-color custom-content style]}]
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
[clojure.string :as s]
|
[clojure.string :as s]
|
||||||
[status-im.utils.utils :refer [http-post]]
|
[status-im.utils.utils :refer [http-post]]
|
||||||
[status-im.utils.phone-number :refer [format-phone-number]]
|
[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
|
(defn save-contact
|
||||||
[_ [_ contact]]
|
[_ [_ contact]]
|
||||||
|
@ -26,7 +27,7 @@
|
||||||
(register-handler :load-contacts load-contacts!)
|
(register-handler :load-contacts load-contacts!)
|
||||||
|
|
||||||
;; TODO see https://github.com/rt2zz/react-native-contacts/issues/45
|
;; 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]
|
(defn contact-name [contact]
|
||||||
(->> contact
|
(->> contact
|
||||||
|
@ -91,10 +92,14 @@
|
||||||
(defn add-new-contacts
|
(defn add-new-contacts
|
||||||
[{:keys [contacts] :as db} [_ new-contacts]]
|
[{:keys [contacts] :as db} [_ new-contacts]]
|
||||||
(let [identities (set (map :whisper-identity 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
|
(-> db
|
||||||
(update :contacts concat new-contacts')
|
(update :contacts merge new-contacts')
|
||||||
(assoc :new-contacts new-contacts'))))
|
(assoc :new-contacts (vals new-contacts')))))
|
||||||
|
|
||||||
(register-handler :add-contacts
|
(register-handler :add-contacts
|
||||||
(after save-contacts!)
|
(after save-contacts!)
|
||||||
|
|
|
@ -2,16 +2,16 @@
|
||||||
(:require-macros [status-im.utils.views :refer [defview]])
|
(:require-macros [status-im.utils.views :refer [defview]])
|
||||||
(:require
|
(:require
|
||||||
[re-frame.core :refer [subscribe]]
|
[re-frame.core :refer [subscribe]]
|
||||||
[status-im.utils.logging :as log]
|
|
||||||
[status-im.components.react :refer [android?
|
[status-im.components.react :refer [android?
|
||||||
text]]
|
text]]
|
||||||
[status-im.components.carousel.carousel :refer [carousel]]
|
[status-im.components.carousel.carousel :refer [carousel]]
|
||||||
[status-im.discovery.styles :as st]
|
[status-im.discovery.styles :as st]
|
||||||
[status-im.discovery.views.popular-list :refer [discovery-popular-list]]
|
[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 []
|
(defn page-width []
|
||||||
(.-width (.get (.. js/React -Dimensions) "window")))
|
(.-width (.get (.. r/react -Dimensions) "window")))
|
||||||
|
|
||||||
(defview popular []
|
(defview popular []
|
||||||
[popular-tags [:get-popular-tags 3]]
|
[popular-tags [:get-popular-tags 3]]
|
||||||
|
|
|
@ -36,15 +36,19 @@
|
||||||
|
|
||||||
;; -- Common --------------------------------------------------------------
|
;; -- Common --------------------------------------------------------------
|
||||||
|
|
||||||
|
(defn set-el [db [_ k v]]
|
||||||
|
(assoc db k v))
|
||||||
|
|
||||||
(register-handler :set
|
(register-handler :set
|
||||||
(debug
|
debug
|
||||||
(fn [db [_ k v]]
|
set-el)
|
||||||
(assoc db k v))))
|
|
||||||
|
(defn set-in [db [_ path v]]
|
||||||
|
(assoc-in db path v))
|
||||||
|
|
||||||
(register-handler :set-in
|
(register-handler :set-in
|
||||||
(debug
|
debug
|
||||||
(fn [db [_ path v]]
|
set-in)
|
||||||
(assoc-in db path v))))
|
|
||||||
|
|
||||||
(register-handler :initialize-db
|
(register-handler :initialize-db
|
||||||
(fn [_ _]
|
(fn [_ _]
|
||||||
|
|
|
@ -1,25 +1,23 @@
|
||||||
(ns status-im.i18n
|
(ns status-im.i18n
|
||||||
(:require
|
(: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"))
|
(def i18n (u/require "react-native-i18n"))
|
||||||
(set! (.-fallbacks js/I18n) true)
|
(set! (.-fallbacks i18n) true)
|
||||||
(set! (.-defaultSeparator js/I18n) "/")
|
(set! (.-defaultSeparator i18n) "/")
|
||||||
|
|
||||||
(set! (.-translations js.I18n) (clj->js {:en en/translations}))
|
(set! (.-translations i18n) (clj->js {:en en/translations}))
|
||||||
|
|
||||||
(defn label
|
(defn label
|
||||||
([path] (label path {}))
|
([path] (label path {}))
|
||||||
([path options]
|
([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]
|
(defn label-pluralize [count path & options]
|
||||||
(let [translations (.-translations js/I18n)]
|
(if (exists? i18n.t)
|
||||||
(set! (.-translations js/I18n) (clj->js (deep-merge (js->clj translations) new-translations)))))
|
(.p i18n count (name path) (clj->js options))
|
||||||
)
|
(name path)))
|
|
@ -2,11 +2,10 @@
|
||||||
(:require [cljs.reader :refer [read-string]]
|
(:require [cljs.reader :refer [read-string]]
|
||||||
[status-im.components.styles :refer [default-chat-color]]
|
[status-im.components.styles :refer [default-chat-color]]
|
||||||
[status-im.utils.logging :as log]
|
[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?]))
|
(:refer-clojure :exclude [exists?]))
|
||||||
|
|
||||||
(set! js/window.Realm (js/require "realm"))
|
|
||||||
|
|
||||||
(def opts {:schema [{:name :contacts
|
(def opts {:schema [{:name :contacts
|
||||||
:primaryKey :whisper-identity
|
:primaryKey :whisper-identity
|
||||||
:properties {:phone-number {:type "string"
|
:properties {:phone-number {:type "string"
|
||||||
|
@ -70,7 +69,10 @@
|
||||||
:objectType "tag"}
|
:objectType "tag"}
|
||||||
:last-updated "date"}}]})
|
: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)
|
(def schema-by-name (->> (:schema opts)
|
||||||
(mapv (fn [{:keys [name] :as schema}]
|
(mapv (fn [{:keys [name] :as schema}]
|
||||||
|
|
|
@ -68,7 +68,7 @@
|
||||||
email [:get :email]
|
email [:get :email]
|
||||||
status [:get :status]
|
status [:get :status]
|
||||||
identity [:get-in [:user-identity :public]]]
|
identity [:get-in [:user-identity :public]]]
|
||||||
[view {:style st/profile}
|
[scroll-view {:style st/profile}
|
||||||
[touchable-highlight {:style st/back-btn-touchable
|
[touchable-highlight {:style st/back-btn-touchable
|
||||||
:on-press #(dispatch [:navigate-back])}
|
:on-press #(dispatch [:navigate-back])}
|
||||||
[view st/back-btn-container
|
[view st/back-btn-container
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
(ns status-im.utils.crypt
|
(ns status-im.utils.crypt
|
||||||
(:require [goog.crypt :refer [byteArrayToHex]]
|
(:require [goog.crypt :refer [byteArrayToHex]]
|
||||||
[clojure.string :as s])
|
[clojure.string :as s]
|
||||||
|
[status-im.utils.utils :as u])
|
||||||
(:import goog.crypt.Sha256))
|
(: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.))
|
(def sha-256 (Sha256.))
|
||||||
|
|
||||||
|
@ -19,7 +20,7 @@
|
||||||
(byteArrayToHex (.digest sha-256)))
|
(byteArrayToHex (.digest sha-256)))
|
||||||
|
|
||||||
(defn gen-random-bytes [length cb]
|
(defn gen-random-bytes [length cb]
|
||||||
(.randomBytes js/window.RnRandomBytes length (fn [& [err buf]]
|
#_(.randomBytes random-bytes length (fn [& [err buf]]
|
||||||
(if err
|
(if err
|
||||||
(cb {:error err})
|
(cb {:error err})
|
||||||
(cb {:buffer buf})))))
|
(cb {:buffer buf})))))
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
(ns status-im.utils.listview
|
(ns status-im.utils.listview
|
||||||
(:require-macros [natal-shell.data-source :refer [data-source]])
|
(:require-macros [natal-shell.data-source :refer [data-source]]))
|
||||||
(:require [status-im.components.realm]))
|
|
||||||
|
|
||||||
(defn clone-with-rows [ds rows]
|
(defn clone-with-rows [ds rows]
|
||||||
(.cloneWithRows ds (reduce (fn [ac el] (.push ac el) ac)
|
(.cloneWithRows ds (reduce (fn [ac el] (.push ac el) ac)
|
||||||
|
|
|
@ -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 i18n (u/require "react-native-i18n"))
|
||||||
(def locale (.-locale i18n))
|
(def locale (or (.-locale i18n) "___en"))
|
||||||
(def country-code (subs locale 3 5))
|
(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
|
;; todo check wrong numbers, .getNumber returns empty string
|
||||||
(defn format-phone-number [number]
|
(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]
|
(defn valid-mobile-number? [number]
|
||||||
(when (string? 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)
|
(and (.isValid number-obj)
|
||||||
(.isMobile number-obj)))))
|
(.isMobile number-obj)))))
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
(ns status-im.utils.sms-listener
|
(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!
|
;; Only android is supported!
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,11 @@
|
||||||
[natal-shell.toast-android :as toast])
|
[natal-shell.toast-android :as toast])
|
||||||
(:require [status-im.constants :as const]))
|
(:require [status-im.constants :as const]))
|
||||||
|
|
||||||
|
(defn require [module]
|
||||||
|
(if (exists? js/window)
|
||||||
|
(js/require module)
|
||||||
|
#js {}))
|
||||||
|
|
||||||
(defn log [obj]
|
(defn log [obj]
|
||||||
(.log js/console obj))
|
(.log js/console obj))
|
||||||
|
|
||||||
|
|
|
@ -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)))))
|
|
@ -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))
|
|
@ -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]))))
|
|
@ -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)
|
|
@ -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))))
|
|
Loading…
Reference in New Issue