Merge remote-tracking branch 'origin/develop' into response-design

# Conflicts:
#	src/status_im/db.cljs


Former-commit-id: 86dc0ad06e
This commit is contained in:
virvar 2016-06-13 19:54:39 +03:00
commit 5f8f390bd1
60 changed files with 606 additions and 74 deletions

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",
@ -16,7 +16,9 @@
"react-native-randombytes",
"dismissKeyboard",
"react-native-linear-gradient",
"react-native-android-sms-listener"
"react-native-android-sms-listener",
"react-native-camera",
"react-native-qrcode"
],
"imageDirs": [
"images"

View File

@ -130,6 +130,7 @@ dependencies {
compile project(':react-native-i18n')
compile project(':react-native-linear-gradient')
compile project(':ReactNativeAndroidSmsListener')
compile project(':react-native-camera')
// compile(name:'geth', ext:'aar')
compile(group: 'status-im', name: 'android-geth', version: '1.4.0-201604110816-a97a114', ext: 'aar')

View File

@ -8,30 +8,34 @@ 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;
import java.io.File;
import com.lwansbrough.RCTCamera.*;
import com.i18n.reactnativei18n.ReactNativeI18n;
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");
@ -43,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();
}
}
/**
@ -82,6 +131,7 @@ public class MainActivity extends ReactActivity {
new ReactNativeI18n(),
new RandomBytesPackage(),
new LinearGradientPackage(),
new RCTCameraPackage(),
new SmsListener(this)
);
}

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 526 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 614 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 613 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 537 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 800 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 330 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 826 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 686 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 823 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 825 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 767 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 467 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

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

@ -18,3 +18,5 @@ include ':react-native-linear-gradient'
project(':react-native-linear-gradient').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-linear-gradient/android')
include ':ReactNativeAndroidSmsListener'
project(':ReactNativeAndroidSmsListener').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-android-sms-listener/android')
include ':react-native-camera'
project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android')

View File

@ -10,7 +10,7 @@
(def root-el (r/as-element [reloader]))
(figwheel/watch-and-reload
:websocket-url "ws://localhost:3449/figwheel-ws"
:websocket-url "ws://10.0.3.2:3449/figwheel-ws"
:heads-up-display false
:jsload-callback #(swap! cnt inc))

View File

@ -11,12 +11,14 @@
"react-native": "^0.24.1",
"react-native-action-button": "^1.1.4",
"react-native-android-sms-listener": "^0.1.3",
"react-native-camera": "github:codyhazelwood/react-native-camera",
"react-native-circle-checkbox": "^0.1.3",
"react-native-contacts": "^0.2.4",
"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-qrcode": "^0.2.2",
"react-native-randombytes": "^2.0.0",
"react-native-vector-icons": "^1.3.4",
"realm": "^0.11.1"

View File

@ -8,6 +8,8 @@
[status-im.components.react :refer [navigator app-registry]]
[status-im.components.main-tabs :refer [main-tabs]]
[status-im.contacts.screen :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]]
@ -44,6 +46,8 @@
:new-group [new-group]
:group-settings [group-settings]
:contact-list [main-tabs]
:new-contact [new-contact]
:qr-scanner [qr-scanner]
:chat [chat]
:profile [profile]
:my-profile [my-profile]))))

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

@ -0,0 +1,7 @@
(ns status-im.components.camera
(:require [reagent.core :as r]))
(def class (.-default (js/require "react-native-camera")))
(defn camera [props]
(r/create-element class (clj->js (merge {:inverted true} props))))

View File

@ -0,0 +1,7 @@
(ns status-im.components.qr-code
(:require [reagent.core :as r]))
(def class (js/require "react-native-qrcode"))
(defn qr-code [props]
(r/create-element class (clj->js (merge {:inverted true} props))))

View File

@ -19,6 +19,7 @@
(def text1-color color-black)
(def text2-color color-gray)
(def text3-color color-blue)
(def text4-color color-white)
(def online-color color-blue)
(def new-messages-count-color color-blue-transparent)
(def chat-background color-light-gray)
@ -28,5 +29,73 @@
(def toolbar-background2 color-light-gray)
(def default-chat-color color-purple)
(def toolbar-height 56)
(def flex
{:style {:flex 1}})
(def hamburger-icon
{:width 16
:height 12})
(def icon-search
{:width 17
:height 17})
(def create-icon
{:fontSize 20
:height 22
:color :white})
(def icon-back
{:width 8
:height 14})
(def icon-add
{:width 14
:height 14})
(def icon-ok
{:width 18
:height 14})
(def icon-qr
{:width 23
:height 22})
(def icon-plus
{:width 18
:height 18})
(def form-text-input
{:marginLeft -4
:fontSize 14
:fontFamily font
:color text1-color})
(def white-form-text-input
{:marginLeft -4
:fontSize 14
:fontFamily font
:color color-white})
(def toolbar-title-container
{:flex 1
:alignItems :center
:justifyContent :center})
(def toolbar-title-text
{:marginTop -2.5
:color text1-color
:fontSize 16
:fontFamily font})
(def button-input-container
{:flex 1
:flexDirection :row
:height 50})
(def button-input
{:flex 1
:flexDirection :column
:height 50})

View File

@ -1,24 +1,28 @@
(ns status-im.components.toolbar
(:require [re-frame.core :refer [subscribe dispatch]]
[status-im.components.react :refer [view
text-input
icon
text
image
touchable-highlight]]
text-input
icon
text
image
touchable-highlight]]
[status-im.components.styles :refer [font
title-font
color-white
color-purple
text1-color
text2-color
toolbar-background1]]))
title-font
color-white
color-purple
text1-color
text2-color
toolbar-background1
toolbar-title-container
toolbar-title-text
icon-back
toolbar-height]]))
(defn toolbar [{:keys [title nav-action hide-nav? action custom-action
background-color custom-content style]}]
(let [style (merge {:flexDirection :row
:backgroundColor (or background-color toolbar-background1)
:height 56
:height toolbar-height
:elevation 2} style)]
[view {:style style}
(when (not hide-nav?)
@ -31,20 +35,14 @@
[image (:image nav-action)]]]
[touchable-highlight {:on-press #(dispatch [:navigate-back])}
[view {:width 56
:height 56}
:height 56
:alignItems :center
:justifyContent :center}
[image {:source {:uri :icon_back}
:style {:marginTop 21
:marginLeft 23
:width 8
:height 14}}]]]))
:style icon-back}]]]))
(or custom-content
[view {:style {:flex 1
:alignItems :center
:justifyContent :center}}
[text {:style {:marginTop -2.5
:color text1-color
:fontSize 16
:fontFamily font}}
[view {:style toolbar-title-container}
[text {:style toolbar-title-text}
title]])
custom-action
(when action

View File

@ -104,3 +104,21 @@
(register-handler :add-contacts
(after save-contacts!)
add-new-contacts)
(defn add-new-contact [db [_ {:keys [whisper-identity] :as contact}]]
(-> db
(update :contacts assoc whisper-identity contact)
(assoc :new-contact {:name ""
:address ""
:whisper-identity ""
:phone-number ""})))
(register-handler :add-new-contact
(after save-contact)
add-new-contact)
(defn set-new-contact-from-qr
[{:keys [new-contact] :as db} [_ _ qr-contact]]
(assoc db :new-contact (merge new-contact qr-contact)))
(register-handler :set-new-contact-from-qr set-new-contact-from-qr)

View File

@ -6,9 +6,18 @@
touchable-highlight
list-view
list-item]]
[status-im.components.action-button :refer [action-button
action-button-item]]
[status-im.contacts.views.contact :refer [contact-view]]
[status-im.components.styles :refer [toolbar-background2]]
[status-im.components.toolbar :refer [toolbar]]
[status-im.components.drawer.view :refer [drawer-view open-drawer]]
[status-im.components.icons.ionicons :refer [icon]]
[status-im.components.styles :refer [color-blue
hamburger-icon
icon-search
create-icon
toolbar-background2]]
[status-im.contacts.styles :as st]
[status-im.utils.listview :as lw]
[status-im.i18n :refer [label]]))
@ -17,20 +26,34 @@
(list-item [contact-view row]))
(defn contact-list-toolbar []
[toolbar {:title (label :t/contacts)
[toolbar {:nav-action {:image {:source {:uri :icon_hamburger}
:style hamburger-icon}
:handler open-drawer}
:title (label :t/contacts)
:background-color toolbar-background2
:action {:image {:source {:uri :icon_search}
:style st/search-icon}
:style icon-search}
:handler (fn [])}}])
(defview contact-list []
[contacts [:get-contacts]]
[view st/contacts-list-container
[contact-list-toolbar]
;; todo what if there is no contacts, should we show some information
;; about this?
(when contacts
[list-view {:dataSource (lw/to-datasource contacts)
:enableEmptySections true
:renderRow render-row
:style st/contacts-list}])])
[drawer-view
[view st/contacts-list-container
[contact-list-toolbar]
;; todo what if there is no contacts, should we show some information
;; about this?
(when contacts
[list-view {:dataSource (lw/to-datasource contacts)
:enableEmptySections true
:renderRow render-row
:style st/contacts-list}])
[action-button {:buttonColor color-blue
:offsetY 16
:offsetX 16}
[action-button-item
{:title (label :t/new-contact)
:buttonColor :#9b59b6
:onPress #(dispatch [:navigate-to :new-contact])}
[icon {:name :android-create
:style create-icon}]]
]]])

View File

@ -1,13 +1,12 @@
(ns status-im.contacts.styles
(:require [status-im.components.styles :refer [font
title-font
text1-color
color-white
online-color]]))
title-font
text1-color
color-white
toolbar-background2
online-color]]))
(def search-icon
{:width 17
:height 17})
(def contacts-list-container
{:flex 1
@ -67,3 +66,20 @@
:fontSize 16
:fontFamily font
:color text1-color})
; new contact
(def contact-form-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 50})

View File

@ -0,0 +1,78 @@
(ns status-im.contacts.views.new-contact
(:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
[status-im.components.react :refer [view
text
text-input
image
linear-gradient
touchable-highlight]]
[status-im.components.toolbar :refer [toolbar]]
[status-im.components.drawer.view :refer [drawer-view open-drawer]]
[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.import-button :refer [import-button]]
[status-im.i18n :refer [label]]
[status-im.contacts.styles :as st]))
(def toolbar-title
[view toolbar-title-container
[text {:style (merge toolbar-title-text {:color color-white})}
(label :t/new-contact)]])
(defview contact-name-input [name]
[]
[text-input
{:underlineColorAndroid color-white
:placeholderTextColor color-white
:style white-form-text-input
:autoFocus true
:placeholder (label :t/contact-name)
:onChangeText #(dispatch [:set-in [:new-contact :name] %])}
name])
(defview contact-whisper-id-input [whisper-identity]
[view button-input-container
[text-input
{:underlineColorAndroid color-white
:placeholderTextColor color-white
:style (merge white-form-text-input button-input)
:autoFocus true
:placeholder (label :t/whisper-identity)
:onChangeText #(dispatch [:set-in [:new-contact :whisper-identity] %])}
whisper-identity]
[import-button #(dispatch [:scan-qr-code {:toolbar-title (label :t/new-contact)} :set-new-contact-from-qr])]])
(defview new-contact []
[{:keys [name whisper-identity phone-number] :as new-contact} [:get :new-contact]]
[drawer-view
[view st/contact-form-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 {:source {:uri :icon_add}
:style icon-search}
:handler #(dispatch [:add-new-contact new-contact])}}]
[view st/form-container
[contact-whisper-id-input whisper-identity]
[contact-name-input name]
]]])

View File

@ -31,6 +31,11 @@
:email "myemail@gmail.com"
:status "Hi, this is my status"
:current-tag nil
:qr-codes {}
:new-contact {:name ""
:address ""
:whisper-identity ""
:phone-number ""}
:disable-group-creation false
:animations {;; mutable data
:to-response-height nil

View File

@ -17,6 +17,7 @@
status-im.discovery.handlers
status-im.new-group.handlers
status-im.participants.handlers
status-im.qr-scanner.handlers
status-im.protocol.handlers))
;; -- Middleware ------------------------------------------------------------

View File

@ -9,13 +9,15 @@
(set! (.-translations i18n) (clj->js {:en en/translations}))
(defn label [path & options]
(if (exists? i18n.t)
(.t i18n (name path) (clj->js options))
(name path)))
(defn label
([path] (label path {}))
([path options]
(if (exists? i18n.t)
(.t i18n (name path) (clj->js options))
(name path))))
(defn label-pluralize [count path & options]
(if (exists? i18n.t)
(.p i18n count (name path) (clj->js options))
(name path)))
(name path)))

View File

@ -11,6 +11,8 @@
[status-im.components.chat-icon.screen :refer [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]]
[status-im.i18n :refer [label]]))
(defn profile-property-view [{:keys [name value]}]
@ -64,7 +66,8 @@
photo-path [:get :photo-path]
phone-number [:get :phone-number]
email [:get :email]
status [:get :status]]
status [:get :status]
identity [:get-in [:user-identity :public]]]
[scroll-view {:style st/profile}
[touchable-highlight {:style st/back-btn-touchable
:on-press #(dispatch [:navigate-back])}
@ -81,10 +84,14 @@
[my-profile-icon]]
[text {:style st/user-name} username]
[text {:style st/status} status]]
[view st/profile-properties-container
[scroll-view st/profile-properties-container
[profile-property-view {:name (label :t/username)
:value username}]
[profile-property-view {:name (label :t/phone-number)
:value phone-number}]
[profile-property-view {:name (label :t/email)
:value email}]]])
:value email}]
[view st/qr-code-container
[qr-code {:value (clj->json {:name username
:whisper-identity identity})
:size 200}]]]])

View File

@ -135,3 +135,8 @@
:color text2-color
;; IOS:
:letterSpacing 0.5})
(def qr-code-container
{:flex 1
:alignItems :center
:margin 15})

View File

@ -0,0 +1,38 @@
(ns status-im.qr-scanner.handlers
(:require [re-frame.core :refer [register-handler after dispatch debug enrich]]
[status-im.navigation.handlers :as nav]
[status-im.utils.handlers :as u]))
(defmethod nav/preload-data! :qr-scanner
[db [_ _ identifier]]
(assoc db :current-qr-context identifier))
(defn set-current-identifier [db [_ identifier handler]]
(assoc-in db [:qr-codes identifier] handler))
(defn navigate-to-scanner
[_ [_ identifier]]
(dispatch [:navigate-to :qr-scanner identifier]))
(register-handler :scan-qr-code
(after navigate-to-scanner)
set-current-identifier)
(register-handler :clear-qr-code
(fn [db [_ identifier]]
(update db :qr-codes dissoc identifier)))
(defn handle-qr-request
[db [_ context data]]
(let [handler (get-in db [:qr-codes context])]
(dispatch [handler context data])))
(defn clear-qr-request [db [_ context]]
(-> db
(update :qr-codes dissoc context)
(dissoc :current-qr-context)))
(register-handler :set-qr-code
(-> (u/side-effect! handle-qr-request)
((enrich clear-qr-request))
((after #(dispatch [:navigate-back])))))

View File

@ -0,0 +1,37 @@
(ns status-im.qr-scanner.screen
(:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
[status-im.components.react :refer [view
image]]
[status-im.components.camera :refer [camera]]
[status-im.components.styles :refer [toolbar-background1
icon-search]]
[status-im.components.toolbar :refer [toolbar]]
[status-im.qr-scanner.styles :as st]
[status-im.utils.types :refer [json->clj]]))
(defn qr-scanner-toolbar [title]
[toolbar {:title title
:background-color toolbar-background1
:action {:image {:source {:uri :icon_lock_white}
:style icon-search}
:handler #()}}])
(defview qr-scanner []
[identifier [:get :current-qr-context]]
[view st/barcode-scanner-container
[qr-scanner-toolbar (:toolbar-title identifier)]
[camera {;:on-bar-code-read #(js/alert "ok")
:onBarCodeRead #(let [data (json->clj (.-data %))]
(dispatch [:set-qr-code identifier data]))
:style st/barcode-scanner}]
[view st/rectangle-container
[view st/rectangle
[image {:source {:uri :corner_left_top}
:style st/corner-left-top}]
[image {:source {:uri :corner_right_top}
:style st/corner-right-top}]
[image {:source {:uri :corner_right_bottom}
:style st/corner-right-bottom}]
[image {:source {:uri :corner_left_bottom}
:style st/corner-left-bottom}]]]])

View File

@ -0,0 +1,76 @@
(ns status-im.qr-scanner.styles
(:require [status-im.components.styles :refer [toolbar-height
color-white]]))
(def barcode-scanner-container
{:flex 1
:backgroundColor :white})
(def barcode-scanner
{:flex 1
:justifyContent :flex-end
:alignItems :center})
(def rectangle-container
{:position :absolute
:left 0
:top toolbar-height
:bottom 0
:right 0
:flex 1
:alignItems :center
:justifyContent :center
:backgroundColor :transparent})
(def rectangle
{:height 250
:width 250
:backgroundColor :transparent})
(def corner-left-top
{:position :absolute
:left 0
:top 0
:width 56
:height 56})
(def corner-right-top
{:position :absolute
:right 0
:top 0
:width 56
:height 56})
(def corner-right-bottom
{:position :absolute
:right 0
:bottom 0
:width 56
:height 56})
(def corner-left-bottom
{:position :absolute
:left 0
:bottom 0
:width 56
:height 56})
(def import-button
{:position :absolute
:right 16
:flex 1
:height 50
:alignItems :center})
(def import-button-content
{:flex 1
:flexDirection :row
:height 50
:alignItems :center
:alignSelf :center})
(def import-text
{:flex 1
:flexDirection :column
:color color-white
:margin-left 8})

View File

@ -0,0 +1,23 @@
(ns status-im.qr-scanner.views.import-button
(:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
[status-im.components.react :refer [view
text
image
touchable-highlight]]
[status-im.components.toolbar :refer [toolbar]]
[status-im.components.drawer.view :refer [drawer-view open-drawer]]
[status-im.components.styles :refer [icon-qr]]
[status-im.i18n :refer [label]]
[status-im.qr-scanner.styles :as st]))
(defview import-button [handler]
[]
[view st/import-button
[touchable-highlight
{:on-press handler}
[view st/import-button-content
[image {:source {:uri :icon_qr}
:style icon-qr}]
[text {:style st/import-text} (label :t/import-qr)]]]])

View File

@ -115,8 +115,18 @@
:You "You"
;new-contact
:import-qr "Import from QR"
:import-qr "Import"
:contact-name "Contact Name"
:contact-address "Contact Address"
:whisper-identity "Whisper Identity"
;login
:recover-from-passphrase "Recover from passphrase"
:connect "Connect"
:address "Address"
:password "Password"
:login "Login"
;users
:add-account "Add account"
})

View File

@ -6,4 +6,10 @@
s))
(defn to-edn-string [value]
(with-out-str (pr value)))
(with-out-str (pr value)))
(defn clj->json [data]
(.stringify js/JSON (clj->js data)))
(defn json->clj [data]
(js->clj (.parse js/JSON data) :keywordize-keys true))