Merge pull request #185 from status-im/feature/profile-screen

Editable profile screen

Former-commit-id: 05798fc552
This commit is contained in:
Roman Volosovskyi 2016-08-08 08:51:06 +03:00 committed by GitHub
commit 8f39f113fa
48 changed files with 786 additions and 397 deletions

View File

@ -11,6 +11,7 @@
"realm/react-native",
"react-native-action-button",
"react-native-vector-icons/Ionicons",
"react-native-vector-icons/Octicons",
"react-native-circle-checkbox",
"react-native-randombytes",
"dismissKeyboard",
@ -21,7 +22,10 @@
"react-native-qrcode",
"react-native-orientation",
"identicon.js",
"react-native-fs"
"react-native-fs",
"react-native-dialogs",
"react-native-image-resizer",
"react-native-image-crop-picker"
],
"imageDirs": [
"images"

View File

@ -82,7 +82,7 @@ android {
defaultConfig {
applicationId "com.statusim"
minSdkVersion 16
minSdkVersion 18
targetSdkVersion 22
versionCode 1
versionName "1.0"
@ -120,6 +120,8 @@ android {
}
dependencies {
compile project(':react-native-image-resizer')
compile project(':react-native-dialogs')
compile project(':react-native-randombytes')
compile project(':react-native-android-sms-listener')
compile project(':realm')
@ -134,6 +136,7 @@ dependencies {
compile project(':react-native-status')
compile project(':react-native-orientation')
compile project(':react-native-fs')
compile project(':react-native-image-crop-picker')
//compile(name:'statusgo-android-16', ext:'aar')
compile(group: 'status-im', name: 'status-go', version: '0.1.0-201607011545-da53ec', ext: 'aar')

View File

@ -19,6 +19,9 @@ import com.centaurwarchief.smslistener.SmsListenerPackage;
import com.github.yamill.orientation.OrientationPackage;
import com.rnfs.RNFSPackage;
import com.statusim.geth.module.GethPackage;
import com.aakashns.reactnativedialogs.ReactNativeDialogsPackage;
import fr.bamlab.rnimageresizer.ImageResizerPackage;
import com.reactnative.picker.PickerPackage;
import java.util.Arrays;
import java.util.List;
@ -46,7 +49,10 @@ public class MainApplication extends Application implements ReactApplication {
new SmsListenerPackage(),
new OrientationPackage(),
new RNFSPackage(),
new GethPackage()
new GethPackage(),
new ReactNativeDialogsPackage(),
new ImageResizerPackage(),
new PickerPackage()
);
}
};

View File

@ -3,6 +3,8 @@
<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>

View File

@ -16,16 +16,10 @@ allprojects {
repositories {
mavenLocal()
jcenter()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
maven { url "$rootDir/../node_modules/react-native/android" }
// for geth
flatDir {
dirs 'libs'
}
maven {
url "http://185.90.37.89:8081/artifactory/libs-release-local"
}
flatDir { dirs 'libs' }
maven { url "http://185.90.37.89:8081/artifactory/libs-release-local" }
maven { url "https://jitpack.io" }
}
}

View File

@ -1,6 +1,10 @@
rootProject.name = 'StatusIm'
include ':app'
include ':react-native-image-resizer'
project(':react-native-image-resizer').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-image-resizer/android')
include ':react-native-dialogs'
project(':react-native-dialogs').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-dialogs/android')
include ':react-native-randombytes'
project(':react-native-randombytes').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-randombytes/android')
include ':react-native-android-sms-listener'
@ -23,3 +27,5 @@ include ':react-native-orientation', ':app'
project(':react-native-orientation').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-orientation/android')
include ':react-native-fs'
project(':react-native-fs').projectDir = new File(settingsDir, '../node_modules/react-native-fs/android')
include ':react-native-image-crop-picker'
project(':react-native-image-crop-picker').projectDir = new File(settingsDir, '../node_modules/react-native-image-crop-picker/android')

View File

@ -5,7 +5,6 @@
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; };
00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; };
@ -49,6 +48,7 @@
D28AEFB4C39548EB80416889 /* Entypo.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 52E205D210BC48B7A553BB62 /* Entypo.ttf */; };
EF2B5857B4A34E0C9707FB3F /* Octicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = B3B19223008342D096AA356E /* Octicons.ttf */; };
FD4F213C3873473CB703B1D2 /* libRNFS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 674B3D9595A047AB8D518F4E /* libRNFS.a */; };
E0AD9E8F495A4907B65104BF /* libRCTImageResizer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2BEE3436791D42248F853999 /* libRCTImageResizer.a */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -284,6 +284,8 @@
CEB0E2659D1A4F5FA842057A /* EvilIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = EvilIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf"; sourceTree = "<group>"; };
DF1CD4C3D1254774ACCAE4E8 /* libBVLinearGradient.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libBVLinearGradient.a; sourceTree = "<group>"; };
F090E261B9854867A728CE4F /* RealmReact.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RealmReact.xcodeproj; path = "../node_modules/realm/react-native/ios/RealmReact.xcodeproj"; sourceTree = "<group>"; };
5E5A7625B76441D984EA8C0D /* RCTImageResizer.xcodeproj */ = {isa = PBXFileReference; name = "RCTImageResizer.xcodeproj"; path = "../node_modules/react-native-image-resizer/ios/RCTImageResizer.xcodeproj"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; };
2BEE3436791D42248F853999 /* libRCTImageResizer.a */ = {isa = PBXFileReference; name = "libRCTImageResizer.a"; path = "libRCTImageResizer.a"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -323,6 +325,7 @@
BA68A2377A20496EA737000D /* libz.tbd in Frameworks */,
3E15DFEC1F6F4D7CAE088F49 /* libTcpSockets.a in Frameworks */,
AD5063BC2B2A4C52ACE0A0B4 /* libUdpSockets.a in Frameworks */,
E0AD9E8F495A4907B65104BF /* libRCTImageResizer.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -581,6 +584,7 @@
38E1A2C8D0734EE99E2B16CE /* TcpSockets.xcodeproj */,
2F0276A9E90843E996A0E762 /* UdpSockets.xcodeproj */,
439B6B4B407A4E2AACAFE5BE /* RCTJail.xcodeproj */,
5E5A7625B76441D984EA8C0D /* RCTImageResizer.xcodeproj */,
);
name = Libraries;
sourceTree = "<group>";
@ -1074,6 +1078,7 @@
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
);
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/StatusIm.app/StatusIm";
@ -1107,6 +1112,7 @@
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
);
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/StatusIm.app/StatusIm";
@ -1140,6 +1146,7 @@
"$(SRCROOT)/../node_modules/react-native-udp/ios/**",
"$(SRCROOT)/../node_modules/react-native-status/ios/RCTJail/RCTJail/**",
"$(SRCROOT)/../node_modules/react-native-status/ios/RCTJail/RCTJail/**",
"$(SRCROOT)/../node_modules/react-native-image-resizer/ios/RCTImageResizer",
);
INFOPLIST_FILE = StatusIm/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@ -1180,6 +1187,7 @@
"$(SRCROOT)/../node_modules/react-native-udp/ios/**",
"$(SRCROOT)/../node_modules/react-native-status/ios/RCTJail/RCTJail/**",
"$(SRCROOT)/../node_modules/react-native-status/ios/RCTJail/RCTJail/**",
"$(SRCROOT)/../node_modules/react-native-image-resizer/ios/RCTImageResizer",
);
INFOPLIST_FILE = StatusIm/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@ -1244,6 +1252,7 @@
"$(SRCROOT)/../node_modules/react-native-udp/ios/**",
"$(SRCROOT)/../node_modules/react-native-status/ios/RCTJail/RCTJail/**",
"$(SRCROOT)/../node_modules/react-native-status/ios/RCTJail/RCTJail/**",
"$(SRCROOT)/../node_modules/react-native-image-resizer/ios/RCTImageResizer",
);
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
MTL_ENABLE_DEBUG_INFO = YES;
@ -1297,6 +1306,7 @@
"$(SRCROOT)/../node_modules/react-native-udp/ios/**",
"$(SRCROOT)/../node_modules/react-native-status/ios/RCTJail/RCTJail/**",
"$(SRCROOT)/../node_modules/react-native-status/ios/RCTJail/RCTJail/**",
"$(SRCROOT)/../node_modules/react-native-image-resizer/ios/RCTImageResizer",
);
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
MTL_ENABLE_DEBUG_INFO = NO;

View File

@ -34,9 +34,12 @@
"react-native-circle-checkbox": "github:paramoshkinandrew/ReactNativeCircleCheckbox",
"react-native-contacts": "^0.2.4",
"react-native-crypto": "^2.0.1",
"react-native-dialogs": "0.0.16",
"react-native-fs": "^1.5.1",
"react-native-http": "github:tradle/react-native-http#834492d",
"react-native-i18n": "0.0.8",
"react-native-image-crop-picker": "^0.5.4",
"react-native-image-resizer": "github:danieldunderfelt/react-native-image-resizer",
"react-native-invertible-scroll-view": "^1.0.0",
"react-native-level-fs": "^2.0.1",
"react-native-linear-gradient": "1.5.7",

View File

@ -9,7 +9,7 @@
[re-frame "0.7.0"]
[prismatic/schema "1.0.4"]
^{:voom {:repo "git@github.com:status-im/status-lib.git"
:branch "master"}}
:branch "discover-rework"}}
[status-im/protocol "0.1.1-20160706_085008-ge61756a"]
[natal-shell "0.3.0"]
[com.andrewmcveigh/cljs-time "0.4.0"]]

View File

@ -17,56 +17,64 @@
(defn save-account [_ [_ account]]
(accounts/save-accounts [account]))
(accounts/save-accounts [account] false))
(register-handler :add-account
(register-handler
:add-account
(-> (fn [db [_ {:keys [address] :as account}]]
(update db :accounts assoc address account))
(update db :accounts assoc address account))
((after save-account))))
(defn save-password [password]
(storage/put kv/kv-store :password password))
(defn account-created [db result password]
(let [data (json->clj result)
(let [data (json->clj result)
public-key (:pubkey data)
address (:address data)
account {:public-key public-key
:address address
:name address
:photo-path (identicon address)}
]
address (:address data)
account {:public-key public-key
:address address
:name address
:photo-path (identicon address)}]
(log/debug "account-created: " account)
(when (not (str/blank? public-key))
(do
;(save-password password)
(dispatch-sync [:add-account account])
(dispatch [:login-account address password])))))
(register-handler :create-account
(-> (fn [db [_ password]]
(geth/create-account password (fn [result] (account-created db result password)))
db)))
(register-handler
:create-account
(fn [db [_ password]]
(geth/create-account password (fn [result] (account-created db result password)))
db))
(defn initialize-account [db account]
(register-handler
:account-update
(fn [db [_ data]]
(let [current-account-id (get db :current-account-id)
account (-> (get-in db [:accounts current-account-id])
(merge data))]
(accounts/save-accounts [account] true)
(assoc-in db [:accounts current-account-id] account))))
(defn initialize-account [db address]
(let [is-login-screen? (= (:view-id db) :login)]
(dispatch [:set :login {}])
(dispatch [:set :is-logged-in true])
(dispatch [:set :user-identity account])
(dispatch [:initialize-account account])
(dispatch [:set :current-account-id address])
(dispatch [:initialize-account address])
(when is-login-screen? (dispatch [:navigate-to-clean default-view]))))
(defn logged-in [db address]
(let [account (get-in db [:accounts address])
is-login-screen? (= (:view-id db) :login)
(let [is-login-screen? (= (:view-id db) :login)
new-account? (not is-login-screen?)]
(log/debug "Logged in: " address account)
(log/debug "Logged in: " address)
(realm/change-account-realm address new-account?
#(if (nil? %)
(initialize-account db account)
(initialize-account db address)
(log/debug "Error changing acount realm: " %)))))
(register-handler :login-account
(register-handler
:login-account
(-> (fn [db [_ address password]]
(geth/login address password (fn [result]
(let [data (json->clj result)

View File

@ -59,7 +59,8 @@
(dispatch [:set-in [:login :error] ""]))}]])
(defview login [{platform-specific :platform-specific}]
[{:keys [address password error]} [:get :login]]
[{:keys [address password error]} [:get :login]
keyboard-height [:get :keyboard-height]]
[view st/screen-container
[linear-gradient {:colors ["rgba(182, 116, 241, 1)" "rgba(107, 147, 231, 1)" "rgba(43, 171, 238, 1)"]
:start [0, 0]
@ -79,20 +80,19 @@
[view st/form-container-inner
[address-input (or address "")]
[password-input error]]]
(let [keyboard-height @(subscribe [:get :keyboard-height])]
[view st/bottom-actions-container
(when (= keyboard-height 0)
[view st/recover-button-container
[touchable-highlight
{:on-press #()}
[view st/recover-button
[text {:style st/recover-button-text
:platform-specific platform-specific}
(label :t/recover-access)]]]])
[view st/connect-button-container
[view st/bottom-actions-container
(when (= keyboard-height 0)
[view st/recover-button-container
[touchable-highlight
{:on-press #(dispatch [:login-account address password])}
[view st/connect-button
[text {:style st/connect-button-text
{:on-press #()}
[view st/recover-button
[text {:style st/recover-button-text
:platform-specific platform-specific}
(label :t/connect)]]]]])])
(label :t/recover-access)]]]])
[view st/connect-button-container
[touchable-highlight
{:on-press #(dispatch [:login-account address password])}
[view st/connect-button
[text {:style st/connect-button-text
:platform-specific platform-specific}
(label :t/connect)]]]]]])

View File

@ -16,7 +16,7 @@
(dispatch [:set-in [:login :address] address]))
(defview account-view [{:keys [address photo-path name] :as account}]
[current-account [:get :user-identity]]
[current-account [:get-current-account]]
[touchable-highlight
{:onPress #(on-press address)}
[view st/account-container

View File

@ -8,7 +8,8 @@
[status-im.android.styles :refer [styles]]
[status-im.components.react :refer [app-registry
keyboard
orientation]]
orientation
show-dialog]]
[status-im.components.main-tabs :refer [main-tabs]]
[status-im.contacts.views.contact-list :refer [contact-list]]
[status-im.contacts.views.new-contact :refer [new-contact]]
@ -24,6 +25,7 @@
[status-im.participants.views.remove :refer [remove-participants]]
[status-im.group-settings.screen :refer [group-settings]]
[status-im.profile.screen :refer [profile my-profile]]
[status-im.profile.photo-capture.screen :refer [profile-photo-capture]]
[status-im.utils.utils :refer [toast]]
[status-im.utils.encryption]
status-im.persistence.realm.core
@ -48,9 +50,9 @@
(let [signed-up (subscribe [:get :signed-up])
_ (log/debug "signed up: " @signed-up)
view-id (subscribe [:get :view-id])
account (subscribe [:get :user-identity])
account-id (subscribe [:get :current-account-id])
keyboard-height (subscribe [:get :keyboard-height])]
(log/debug "Current account: " @account)
(log/debug "Current account: " @account-id)
(r/create-class
{:component-will-mount
(fn []
@ -72,7 +74,7 @@
(dispatch [:set :keyboard-height 0]))))
:render
(fn []
(let [startup-view (if @account
(let [startup-view (if @account-id
(if @signed-up
@view-id
:chat)
@ -94,10 +96,12 @@
:qr-scanner qr-scanner
:chat chat
:profile profile
:profile-photo-capture profile-photo-capture
:accounts accounts
:login login
:my-profile my-profile)]
[component {:platform-specific {:styles styles}}])))})))
[component {:platform-specific {:styles styles
:list-selection-fn show-dialog}}])))})))
(defn init [& [env]]
(dispatch-sync [:reset-app])

View File

@ -310,8 +310,9 @@
(assoc db :password-saved true)))
(register-handler :sign-up
(after (fn [_ [_ phone-number]]
(dispatch [:account-update {:phone phone-number}])))
(fn [db [_ phone-number]]
;; todo save phone number to db
(let [formatted (format-phone-number phone-number)]
(-> db
(assoc :user-phone-number formatted)

View File

@ -19,7 +19,7 @@
toolbar-background2]]
[status-im.components.status-bar :refer [status-bar]]
[status-im.components.toolbar :refer [toolbar]]
[status-im.components.icons.ionicons :refer [icon]]
[status-im.components.icons.custom-icons :refer [ion-icon]]
[status-im.i18n :refer [label]]
[status-im.chats-list.styles :as st]
[status-im.components.styles :as cst]
@ -80,12 +80,12 @@
{:title (label :t/new-chat)
:buttonColor :#9b59b6
:onPress #(dispatch [:show-group-contacts :people])}
[icon {:name :md-create
:style st/create-icon}]]
[ion-icon {:name :md-create
:style st/create-icon}]]
[action-button-item
{:title (label :t/new-group-chat)
:buttonColor :#1abc9c
:onPress #(dispatch [:show-group-new])}
[icon {:name :md-person
:style st/person-stalker-icon}]]]]
[ion-icon {:name :md-person
:style st/person-stalker-icon}]]]]
[bottom-gradient]])))

View File

@ -1,7 +1,16 @@
(ns status-im.components.camera
(:require [reagent.core :as r]))
(:require [reagent.core :as r]
[clojure.walk :refer [keywordize-keys]]))
(def class (.-default (js/require "react-native-camera")))
(def camera-class (js/require "react-native-camera"))
(defn constants [t]
(-> (aget camera-class "default" "constants" t)
(js->clj)
(keywordize-keys)))
(def aspects (constants "Aspect"))
(def capture-targets (constants "CaptureTarget"))
(defn camera [props]
(r/create-element class (clj->js (merge {:inverted true} props))))
(r/create-element (.-default camera-class) (clj->js (merge {:inverted true} props))))

View File

@ -5,6 +5,7 @@
text
image
icon]]
[status-im.components.icons.custom-icons :refer [oct-icon]]
[status-im.components.chat-icon.styles :as st]
[status-im.components.styles :refer [default-chat-color]]
[clojure.string :as s]))
@ -18,20 +19,25 @@
[image {:source {:uri photo-path}
:style (:chat-icon styles)}])
(defn contact-online [online styles]
(when online
(defn contact-badge [type styles]
(when (= type :edit)
[view (:online-view styles)
[view (:online-dot-left styles)]
[view (:online-dot-right styles)]]))
(case type
:online [view
[view (:online-dot-left styles)]
[view (:online-dot-right styles)]]
:edit [view
[oct-icon {:name :pencil
:style st/photo-pencil}]])]))
(defview chat-icon-view [chat-id group-chat name online styles]
[photo-path [:chat-photo chat-id]]
[view (:container styles)
[photo-path [:chat-photo chat-id]]
[view (:container styles)
(if-not (s/blank? photo-path)
[chat-icon photo-path styles]
[default-chat-icon name styles])
(when-not group-chat
[contact-online online styles])])
[contact-badge (if online :online :blank) styles])])
(defn chat-icon-view-chat-list [chat-id group-chat name color online]
[chat-icon-view chat-id group-chat name online
@ -65,13 +71,13 @@
(defn contact-icon-view [contact styles]
(let [photo-path (:photo-path contact)
;; TODO stub data
online true]
;; TODO: stub
type :online]
[view (:container styles)
(if-not (s/blank? photo-path)
[chat-icon photo-path styles]
[default-chat-icon (:name contact) styles])
[contact-online online styles]]))
[contact-badge type styles]]))
(defn contact-icon-contacts-tab [contact]
[contact-icon-view contact
@ -83,7 +89,7 @@
:default-chat-icon (st/default-chat-icon-chat-list default-chat-color)
:default-chat-icon-text st/default-chat-icon-text}])
(defn profile-icon-view [photo-path name color online]
(defn profile-icon-view [photo-path name color badge-type]
(let [styles {:container st/container-profile
:online-view st/online-view-profile
:online-dot-left st/online-dot-left-profile
@ -95,19 +101,17 @@
(if (and photo-path (not (empty? photo-path)))
[chat-icon photo-path styles]
[default-chat-icon name styles])
[contact-online online styles]]))
[contact-badge badge-type styles]]))
(defview profile-icon []
[contact [:contact]]
(let [;; TODO stub data
online true
color default-chat-color]
[profile-icon-view (:photo-path contact) (:name contact) color online]))
(let [;; TODO: stub
type :online
color default-chat-color]
[profile-icon-view (:photo-path @contact) (:name @contact) color type]))
(defview my-profile-icon []
[name [:get :username]
photo-path [:get :photo-path]]
(let [;; TODO stub data
online true
color default-chat-color]
[profile-icon-view photo-path name color online]))
(defn my-profile-icon [{{:keys [photo-path name]} :account
edit? :edit?}]
(let [type (if edit? :edit :blank)
color default-chat-color]
[profile-icon-view photo-path name color type]))

View File

@ -59,8 +59,9 @@
(def chat-icon-profile
(merge chat-icon
{:width 64
:height 64}))
{:width 64
:height 64
:border-radius 32}))
(def online-view
{:position :absolute
@ -75,13 +76,15 @@
(def online-view-menu-item
(merge online-view
{:width 15
:height 15}))
{:width 14
:height 14
:border-radius 7}))
(def online-view-profile
(merge online-view
{:width 24
:height 24}))
{:width 24
:height 24
:border-radius 12}))
(def online-dot
{:position :absolute
@ -93,6 +96,12 @@
(def online-dot-left (merge online-dot {:left 3}))
(def online-dot-right (merge online-dot {:left 9}))
(def photo-pencil
{:margin-left 6
:margin-top 3
:font-size 12
:color :white})
(def online-dot-menu-item
(merge online-dot
{:top 4

View File

@ -1,21 +1,43 @@
(ns status-im.components.drawer.styles
(:require [status-im.components.styles :refer [font
color-light-blue-transparent
color-white
color-black
color-blue
color-blue-transparent
selected-message-color
online-color
separator-color
text1-color
text2-color
text3-color]]))
color-light-blue-transparent
color-white
color-black
color-blue
color-blue-transparent
selected-message-color
online-color
separator-color
text1-color
text2-color
text3-color]]))
(def drawer-menu
{:flex 1
:background-color color-white
:flex-direction :column})
(def user-photo-container
{:margin-top 40
:align-items :center
:justify-content :center})
(def user-photo
{:borderRadius 32
:width 64
:height 64})
{:border-radius 32
:width 64
:height 64})
(def name-container
{:margin-top 20
:margin-left 16
:margin-right 16
:align-items :center})
(def menu-items-container
{:flex 1
:margin-top 50
:align-items :stretch
:flex-direction :column})
(def menu-item-touchable
{:height 48
@ -23,42 +45,19 @@
:paddingTop 14})
(def menu-item-text
{:fontSize 14
:fontFamily font
:lineHeight 21
:color text1-color})
(def drawer-menu
{:flex 1
:backgroundColor color-white
:flexDirection :column})
(def user-photo-container
{:marginTop 40
:alignItems :center
:justifyContent :center})
(def name-container
{:marginTop 20
:alignItems :center})
{:font-size 14
:line-height 21
:color text1-color})
(def name-text
{:marginTop -2.5
:color text1-color
:fontSize 16})
(def menu-items-container
{:flex 1
:marginTop 80
:alignItems :stretch
:flexDirection :column})
{:color text1-color
:font-size 16})
(def switch-users-container
{:paddingVertical 36
:alignItems :center})
{:padding-vertical 36
:align-items :center})
(def switch-users-text
{:fontSize 14
:fontFamily font
:lineHeight 21
:color text3-color})
{:font-size 14
:line-height 21
:color text3-color})

View File

@ -1,4 +1,5 @@
(ns status-im.components.drawer.view
(:require-macros [status-im.utils.views :refer [defview]])
(:require [clojure.string :as s]
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
[reagent.core :as r]
@ -27,53 +28,67 @@
{:uri photo-path})
:style st/user-photo}])
(defn menu-item [{:keys [name handler]}]
(defn menu-item [{:keys [name handler platform-specific]}]
[touchable-opacity {:style st/menu-item-touchable
:onPress (fn []
(close-drawer)
(handler))}
[text {:style st/menu-item-text}
[text {:style st/menu-item-text
:platform-specific platform-specific
:font :default}
name]])
(defn drawer-menu []
(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)
(dispatch [:navigate-to :accounts])
;; TODO not implemented
)}
[text {:style st/switch-users-text}
(label :t/switch-users)]]]])))
(defview drawer-menu [{platform-specific :platform-specific}]
[{:keys [name address photo-path]} [:get-current-account]]
[view st/drawer-menu
[view st/user-photo-container
[user-photo {:photo-path photo-path}]]
[view st/name-container
[text {:style st/name-text
:platform-specific platform-specific
:number-of-lines 1
:font :default}
(if (= name address)
(label :t/user-anonymous)
name)]]
[view st/menu-items-container
[menu-item {:name (label :t/profile)
:handler #(dispatch [:navigate-to :my-profile])
:platform-specific platform-specific}]
[menu-item {:name (label :t/settings)
:handler (fn []
;; TODO not implemented
)
:platform-specific platform-specific}]
[menu-item {:name (label :t/discovery)
:handler #(dispatch [:navigate-to :discovery])
:platform-specific platform-specific}]
[menu-item {:name (label :t/contacts)
:handler #(dispatch [:show-contacts navigator])
:platform-specific platform-specific}]
[menu-item {:name (label :t/invite-friends)
:handler (fn []
;; TODO not implemented
)
:platform-specific platform-specific}]
[menu-item {:name (label :t/faq)
:handler (fn [])
:platform-specific platform-specific}]]
[view st/switch-users-container
[touchable-opacity {:onPress (fn []
(close-drawer)
(dispatch [:navigate-to :accounts])
;; TODO not implemented
)}
[text {:style st/switch-users-text
:platform-specific platform-specific
:font :default}
(label :t/switch-users)]]]])
(defn drawer-view [items]
(defn drawer-view [opts items]
[drawer-layout-android {:drawerWidth 260
:drawerPosition js/ReactNative.DrawerLayoutAndroid.positions.Left
:render-navigation-view #(r/as-element [drawer-menu])
:render-navigation-view #(r/as-element [drawer-menu opts])
:ref (fn [drawer]
(reset! drawer-atom drawer))}
items])

View File

@ -0,0 +1,8 @@
(ns status-im.components.icons.custom-icons
(:require [reagent.core :as r]))
(def ion-icon
(r/adapt-react-class (js/require "react-native-vector-icons/Ionicons")))
(def oct-icon
(r/adapt-react-class (js/require "react-native-vector-icons/Octicons")))

View File

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

View File

@ -10,6 +10,7 @@
image
touchable-highlight
get-dimensions]]
[status-im.components.status-bar :refer [status-bar]]
[status-im.components.drawer.view :refer [drawer-view]]
[status-im.components.animation :as anim]
[status-im.chats-list.screen :refer [chats-list]]
@ -99,12 +100,15 @@
[tab-view-container view-id
[screen]])
(defview main-tabs []
(defview main-tabs [{platform-specific :platform-specific}]
[view-id [:get :view-id]
tab-animation? [:get :prev-tab-view-id]]
[drawer-view
[view {:style common-st/flex
:pointerEvents (if tab-animation? :none :auto)}
(doall (map #(tab-view %) tab-list))
[tabs {:selected-view-id view-id
:tab-list tab-list}]]])
[view common-st/flex
[status-bar {:platform-specific platform-specific}]
[view common-st/flex
[drawer-view {:platform-specific platform-specific}
[view {:style common-st/flex
:pointerEvents (if tab-animation? :none :auto)}
(doall (map #(tab-view %) tab-list))
[tabs {:selected-view-id view-id
:tab-list tab-list}]]]]])

View File

@ -4,4 +4,6 @@
(def class (js/require "react-native-qrcode"))
(defn qr-code [props]
(r/create-element class (clj->js (merge {:inverted true} props))))
(r/create-element
class
(clj->js (merge {:inverted true} props))))

View File

@ -6,6 +6,7 @@
(def react-native (u/require "react-native"))
(def native-modules (.-NativeModules react-native))
(def geth (.-Geth native-modules))
(def react-native-dialogs (u/require "react-native-dialogs"))
(def linear-gradient-module (u/require "react-native-linear-gradient"))
(def dismiss-keyboard! (u/require "dismissKeyboard"))
@ -57,7 +58,6 @@
(def dimensions (.-Dimensions js/ReactNative))
(def keyboard (.-Keyboard react-native))
;; Accessor methods for React Components
(defn text
@ -110,6 +110,33 @@
(vec (concat [linear-gradient-class (merge {:inverted true} props)] children)))
;; List dialogs
(defn show-dialog [{:keys [title options callback]}]
(let [dialog (new react-native-dialogs)]
(.set dialog (clj->js {:title title
:items options
:itemsCallback callback}))
(.show dialog)))
(defn show-action-sheet [{:keys [options callback cancel-text]}]
(.showActionSheetWithOptions (get-class "ActionSheetIOS")
(clj->js {:options (conj options cancel-text)
:cancelButtonIndex (count options)})
callback))
;; Image picker
(def image-picker-class (u/require "react-native-image-crop-picker"))
(defn show-image-picker [images-fn]
(let [image-picker (.-default image-picker-class)]
(-> image-picker
(.openPicker (clj->js {:multiple false}))
(.then images-fn))))
;; Platform
(def platform

View File

@ -38,7 +38,7 @@
:alignItems :center
:justifyContent :center}
[image (:image nav-action)]]]
[touchable-highlight {:on-press #(dispatch [:navigate-back])
[touchable-highlight {:on-press #(dispatch [:navigate-back])
:accessibility-label :navigate-back}
[view {:width 56
:height 56

View File

@ -15,7 +15,7 @@
[status-im.components.status-bar :refer [status-bar]]
[status-im.components.toolbar :refer [toolbar]]
[status-im.components.drawer.view :refer [open-drawer]]
[status-im.components.icons.ionicons :refer [icon]]
[status-im.components.icons.custom-icons :refer [ion-icon]]
[status-im.components.styles :refer [color-blue
hamburger-icon
icon-search
@ -101,6 +101,6 @@
{:title (label :t/new-contact)
:buttonColor :#9b59b6
:onPress #(dispatch [:navigate-to :new-contact])}
[icon {:name :md-create
:style create-icon}]]]]
[ion-icon {:name :md-create
:style create-icon}]]]]
[bottom-gradient]])))

View File

@ -10,7 +10,6 @@
[status-im.components.status-bar :refer [status-bar]]
[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
@ -39,7 +38,7 @@
(defview contact-list [{platform-specific :platform-specific}]
[contacts [:contacts-with-letters]]
[drawer-view
[drawer-view {:platform-specific platform-specific}
[view st/contacts-list-container
[contact-list-toolbar platform-specific]
;; todo what if there is no contacts, should we show some information

View File

@ -11,9 +11,16 @@
;; initial state of app-db
(def app-db {:identity-password "replace-me-with-user-entered-password"
:identity "me"
:is-logged-in false
:accounts {}
:user-identity nil
:current-account-id nil
:profile-edit {:edit? false
:name nil
:email nil
:status nil
:photo-path nil}
:contacts []
:contacts-ids #{}
:selected-contacts #{}
@ -27,12 +34,6 @@
:signed-up false
:view-id default-view
:navigation-stack (list default-view)
;; TODO fix hardcoded values
:photo-path nil
:username "My Name"
:phone-number "3147984309"
:email "myemail@gmail.com"
:status "Hi, this is my status"
:current-tag nil
:qr-codes {}
:new-contact {:name ""
@ -42,7 +43,7 @@
:keyboard-height 0
:disable-group-creation false
:animations {;; todo clear this
:tabs-bar-value (anim/create-value 0)}})
:tabs-bar-value (anim/create-value 0)}})
(def protocol-initialized-path [:protocol-initialized])
(defn chat-input-text-path [chat-id]

View File

@ -17,6 +17,7 @@
status-im.discovery.handlers
status-im.new-group.handlers
status-im.participants.handlers
status-im.profile.handlers
status-im.commands.handlers.loading
status-im.commands.handlers.jail
status-im.qr-scanner.handlers
@ -56,7 +57,7 @@
(register-handler :initialize-db
(fn [_ _]
(realm/reset-account)
(assoc app-db :user-identity nil)))
(assoc app-db :current-account-id nil)))
(register-handler :initialize-account-db
(fn [db _]
@ -66,8 +67,8 @@
(register-handler :initialize-account
(u/side-effect!
(fn [_ [_ account]]
(dispatch [:initialize-protocol account])
(fn [_ [_ address]]
(dispatch [:initialize-protocol address])
(dispatch [:initialize-account-db])
(dispatch [:initialize-chats])
(dispatch [:load-contacts])

View File

@ -5,7 +5,8 @@
(defn sign-up
[db phone-number handler]
(let [{:keys [public-key address] :as account} (get-in db [:user-identity])]
(let [current-account-id (get db :current-account-id)
{:keys [public-key address]} (get-in db [:accounts current-account-id])]
;(user-data/save-phone-number phone-number)
(log/debug "signing up with public-key" public-key "and phone " phone-number)
(http-post "sign-up" {:phone-number phone-number

View File

@ -6,7 +6,8 @@
[status-im.ios.styles :refer [styles]]
[status-im.components.react :refer [app-registry
keyboard
orientation]]
orientation
show-action-sheet]]
[status-im.components.main-tabs :refer [main-tabs]]
[status-im.contacts.views.contact-list :refer [contact-list]]
[status-im.contacts.views.new-contact :refer [new-contact]]
@ -22,6 +23,7 @@
[status-im.participants.views.remove :refer [remove-participants]]
[status-im.group-settings.screen :refer [group-settings]]
[status-im.profile.screen :refer [profile my-profile]]
[status-im.profile.photo-capture.screen :refer [profile-photo-capture]]
[status-im.utils.utils :refer [toast]]
[status-im.utils.encryption]
status-im.persistence.realm.core
@ -34,9 +36,9 @@
(let [signed-up (subscribe [:get :signed-up])
_ (log/debug "signed up: " @signed-up)
view-id (subscribe [:get :view-id])
account (subscribe [:get :user-identity])
account-id (subscribe [:get :current-account-id])
keyboard-height (subscribe [:get :keyboard-height])]
(log/debug "Current account: " @account)
(log/debug "Current account: " @account-id)
(r/create-class
{:component-will-mount
(fn []
@ -58,7 +60,7 @@
#(dispatch [:set :keyboard-height 0]))))
:render
(fn []
(let [startup-view (if @account
(let [startup-view (if @account-id
(if @signed-up
@view-id
:chat)
@ -80,10 +82,12 @@
:qr-scanner qr-scanner
:chat chat
:profile profile
:profile-photo-capture profile-photo-capture
:accounts accounts
:login login
:my-profile my-profile)]
[component {:platform-specific {:styles styles}}])))})))
[component {:platform-specific {:styles styles
:list-selection-fn show-action-sheet}}])))})))
(defn init []
(dispatch-sync [:reset-app])

View File

@ -2,21 +2,20 @@
(:require [status-im.persistence.realm.core :as r]))
(defn get-accounts []
(-> (r/get-all :base :accounts)
r/collection->map))
(-> (r/get-all :base :accounts)
r/collection->map))
(defn create-account [{:keys [address public-key] :as account}]
(->> account
(r/create :base :accounts)))
(defn save-account [update?]
#(r/create :base :accounts % update?))
(defn save-accounts [accounts]
(r/write :base #(mapv create-account accounts)))
(defn save-accounts [accounts update?]
(r/write :base #(mapv (save-account update?) accounts)))
;;;;;;;;;;;;;;;;;;;;----------------------------------------------
(defn accounts-list []
(r/get-all :base :accounts))
(r/get-all :base :accounts))
(defn account-by-address [address]
(r/single-cljs (r/get-by-field :base :accounts :address address)))
(r/single-cljs (r/get-by-field :base :accounts :address address)))

View File

@ -11,10 +11,10 @@
(defn set-initialized [db initialized?]
(assoc-in db db/protocol-initialized-path initialized?))
(defn update-identity [db identity]
(defn update-identity [db {:keys [address] :as identity}]
(let [identity-string (to-edn-string identity)]
(s/put kv/kv-store :identity identity-string)
(assoc db :user-identity identity)))
(assoc-in db [:accounts address] identity)))
(defn stored-identity [db]
(let [identity (s/get kv/kv-store :identity)]

View File

@ -81,6 +81,12 @@
(register-handler :show-profile show-profile)
(defn show-profile-photo-capture
[db [_ image-captured-fn]]
(push-view db :profile-photo-capture))
(register-handler :show-profile-photo-capture show-profile-photo-capture)
(defn navigate-to-clean
[db [_ view-id]]
(-> db

View File

@ -1,32 +1,35 @@
(ns status-im.persistence.realm.schemas
(:require [status-im.components.styles :refer [default-chat-color]]))
(def base {:schema [{:name :accounts
:primaryKey :address
:properties {:address "string"
:public-key "string"
:name "string"
:photo-path "string"}}
{:name :tag
:primaryKey :name
:properties {:name "string"
:count {:type "int"
:optional true
:default 0}}}
{:name :discoveries
:primaryKey :whisper-id
:properties {:name "string"
:status "string"
:whisper-id "string"
:photo "string"
:location "string"
:tags {:type "list"
:objectType "tag"}
:last-updated "date"}}
{:name :kv-store
:primaryKey :key
:properties {:key "string"
:value "string"}}]
(def base {:schema [{:name :accounts
:primaryKey :address
:properties {:address "string"
:public-key "string"
:name "string"
:phone {:type "string" :optional true}
:email {:type "string" :optional true}
:status {:type "string" :optional true}
:photo-path "string"}}
{:name :tag
:primaryKey :name
:properties {:name "string"
:count {:type "int"
:optional true
:default 0}}}
{:name :discoveries
:primaryKey :whisper-id
:properties {:name "string"
:status "string"
:whisper-id "string"
:photo "string"
:location "string"
:tags {:type "list"
:objectType "tag"}
:last-updated "date"}}
{:name :kv-store
:primaryKey :key
:properties {:key "string"
:value "string"}}]
:schemaVersion 0})
(def account {:schema [{:name :contacts

View File

@ -0,0 +1,33 @@
(ns status-im.profile.handlers
(:require [re-frame.core :refer [subscribe dispatch]]
[status-im.utils.handlers :refer [register-handler]]
[status-im.components.react :refer [show-image-picker]]
[status-im.utils.image-processing :refer [img->base64]]
[status-im.i18n :refer [label]]
[status-im.utils.handlers :as u]))
(register-handler :open-image-picker
(u/side-effect!
(fn [_ _]
(show-image-picker
(fn [image]
(let [path (-> (js->clj image)
(get "path")
(subs 7))
on-success (fn [base64]
(dispatch [:set-in [:profile-edit :photo-path] (str "data:image/jpeg;base64," base64)]))
on-error (fn [type error]
(.log js/console type error))]
(img->base64 path on-success on-error)))))))
(register-handler :open-image-source-selector
(u/side-effect!
(fn [_ [_ list-selection-fn]]
(list-selection-fn {:title (label :t/image-source-title)
:options [(label :t/image-source-make-photo) (label :t/image-source-gallery)]
:callback (fn [index]
(case index
0 (dispatch [:show-profile-photo-capture])
1 (dispatch [:open-image-picker])
:default))
:cancel-text (label :t/image-source-cancel)}))))

View File

@ -0,0 +1,53 @@
(ns status-im.profile.photo-capture.screen
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
[clojure.walk :refer [keywordize-keys]]
[status-im.components.react :refer [view
image
touchable-highlight]]
[status-im.components.camera :refer [camera
aspects
capture-targets]]
[status-im.components.styles :refer [toolbar-background1
icon-search
icon-back]]
[status-im.components.icons.custom-icons :refer [ion-icon]]
[status-im.components.status-bar :refer [status-bar]]
[status-im.components.toolbar :refer [toolbar]]
[status-im.utils.image-processing :refer [img->base64]]
[status-im.profile.photo-capture.styles :as st]
[status-im.i18n :refer [label]]
[reagent.core :as r]))
(defn image-captured [path]
(let [path (subs path 5)
on-success (fn [base64]
(dispatch [:set-in [:profile-edit :photo-path] (str "data:image/jpeg;base64," base64)])
(dispatch [:navigate-back]))
on-error (fn [type error]
(.log js/console type error))]
(img->base64 path on-success on-error)))
(defn profile-photo-capture [{platform-specific :platform-specific}]
(let [camera-ref (r/atom nil)]
[view st/container
[status-bar {:platform-specific platform-specific}]
[toolbar {:title (label :t/image-source-title)
:nav-action {:image {:source {:uri :icon_back}
:style icon-back}
:handler #(dispatch [:navigate-back])}
:background-color toolbar-background1}]
[camera {:style {:flex 1}
:aspect (:fill aspects)
:captureTarget (:disk capture-targets)
:type "front"
:ref #(reset! camera-ref %)}]
[view {:style {:padding 10
:background-color toolbar-background1}}
[touchable-highlight {:style {:align-self "center"}
:on-press (fn []
(let [camera @camera-ref]
(-> (.capture camera)
(.then image-captured))))}
[view
[ion-icon {:name :md-camera
:style {:font-size 36}}]]]]]))

View File

@ -0,0 +1,5 @@
(ns status-im.profile.photo-capture.styles)
(def container
{:flex 1
:background-color :white})

View File

@ -1,30 +1,127 @@
(ns status-im.profile.screen
(:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [subscribe dispatch]]
(:require [reagent.core :as r]
[re-frame.core :refer [subscribe dispatch]]
[status-im.components.react :refer [view
text
text-input
image
icon
scroll-view
touchable-highlight
touchable-opacity]]
touchable-opacity
show-image-picker]]
[status-im.components.icons.custom-icons :refer [oct-icon]]
[status-im.components.chat-icon.screen :refer [profile-icon
my-profile-icon]]
[status-im.components.status-bar :refer [status-bar]]
[status-im.profile.styles :as st]
[status-im.components.qr-code :refer [qr-code]]
[status-im.utils.phone-number :refer [format-phone-number
valid-mobile-number?]]
[status-im.utils.fs :refer [read-file]]
[status-im.utils.types :refer [clj->json]]
[status-im.i18n :refer [label]]))
[status-im.utils.image-processing :refer [img->base64]]
[status-im.i18n :refer [label]]
[clojure.string :as str]))
(defn profile-property-view [{:keys [name value]}]
[view st/profile-property-view-container
[view st/profile-property-view-sub-container
[text {:style st/profile-property-view-label} name]
[text {:style st/profile-property-view-value} value]]])
(defn- get-hashtags [status]
(let [hashtags (map #(subs % 1) (re-seq #"#[^ !?,;:.]+" status))]
(or hashtags [])))
(defn message-user [identity]
(defn- message-user [identity]
(when identity
(dispatch [:navigate-to :chat identity])))
(defn- update-profile [{name :name
email :email
photo-path :photo-path
status :status}
{new-name :name
new-email :email
new-status :status
new-photo-path :photo-path}]
(let [new-name (if (or (not new-name) (str/blank? new-name)) name new-name)
status-updated? (and (not= new-status nil)
(not= status new-status))]
(when status-updated?
(dispatch [:broadcast-status new-status (get-hashtags new-status)]))
(dispatch [:account-update {:name new-name
:email (or new-email email)
:status (or new-status status)
:photo-path (or new-photo-path photo-path)}])))
(defview toolbar [{:keys [account profile-edit-data edit?]}]
[view
[touchable-highlight {:style st/back-btn-touchable
:on-press (fn []
(dispatch [:set :profile-edit {:edit? false
:name nil
:email nil
:status nil
:photo-path nil}])
(dispatch [:navigate-back]))}
[view st/back-btn-container
[icon :back st/back-btn-icon]]]
[touchable-highlight {:style st/actions-btn-touchable
:on-press (fn []
(when edit?
(update-profile account profile-edit-data))
(dispatch [:set-in [:profile-edit :edit?] (not edit?)]))}
[view st/actions-btn-container
(if edit?
[oct-icon {:name :check
:style st/ok-btn-icon}]
[icon :dots st/edit-btn-icon])]]])
(defview status-image-view [{{:keys [list-selection-fn]} :platform-specific
{address :address
username :name} :account
photo-path :photo-path
status :status
edit? :edit?}]
[view st/status-block
[view st/user-photo-container
(if edit?
[touchable-highlight {:on-press (fn []
(dispatch [:open-image-source-selector list-selection-fn]))}
[view
[my-profile-icon {:account {:photo-path photo-path
:name username}
:edit? edit?}]]]
[my-profile-icon {:account {:photo-path photo-path
:name username}
:edit? edit?}])]
[text {:style st/username
:platform-specific platform-specific
:font :default}
(if (= username address)
(label :t/user-anonymous)
username)]
[text-input {:style st/status-input
:editable edit?
:placeholder (label :t/profile-no-status)
:on-change-text #(dispatch [:set-in [:profile-edit :status] %])}
status]])
(defview profile-property-view [{name :name
value :value
empty-value :empty-value
on-change-text :on-change-text
{edit-mode? :edit?} :profile-data
platform-specific :platform-specific}]
[view st/profile-property-view-container
[view st/profile-property-view-sub-container
[text {:style st/profile-property-view-label
:platform-specific platform-specific
:font :medium}
name]
[text-input {:style st/profile-property-view-value
:editable (and on-change-text edit-mode?)
:on-change-text on-change-text}
(or value (when-not edit-mode? empty-value))]]])
(defview profile []
[{:keys [name whisper-identity phone-number]} [:contact]]
[scroll-view {:style st/profile}
@ -35,9 +132,9 @@
[view st/status-block
[view st/user-photo-container
[profile-icon]]
[text {:style st/user-name} name]
[text {:style st/username} name]
;; TODO stub data
[text {:style st/status} (label :t/not-implemented)]
[text {:style st/status-input} (label :t/not-implemented)]
[view st/btns-container
[touchable-highlight {:onPress #(message-user whisper-identity)}
[view st/message-btn
@ -61,37 +158,53 @@
)}
[view [text {:style st/report-user-text} (label :t/report-user)]]]]]])
(defview my-profile [_]
[username [:get :username]
photo-path [:get :photo-path]
phone-number [:get :phone-number]
email [:get :email]
status [:get :status]
identity [:get-in [:user-identity :public-key]]]
(defview my-profile [{platform-specific :platform-specific}]
[{public-key :public-key
address :address
username :name
email :email
photo-path :photo-path
phone :phone
status :status
:as account} [:get-current-account]
{edit? :edit?
new-status :status
new-photo-path :photo-path
:as profile-edit-data} [:get :profile-edit]]
[scroll-view {:style st/profile}
[touchable-highlight {:style st/back-btn-touchable
:on-press #(dispatch [:navigate-back])}
[view st/back-btn-container
[icon :back st/back-btn-icon]]]
[touchable-highlight {:style st/actions-btn-touchable
:on-press (fn []
;; TODO not implemented
)}
[view st/actions-btn-container
[icon :dots st/actions-btn-icon]]]
[view st/status-block
[view st/user-photo-container
[my-profile-icon]]
[text {:style st/user-name} username]
[text {:style st/status} status]]
[status-bar {:platform-specific platform-specific}]
[toolbar {:account account
:profile-edit-data profile-edit-data
:edit? edit?}]
[status-image-view {:platform-specific platform-specific
:account account
:photo-path (or new-photo-path photo-path)
:status (if (and new-status (not (str/blank? new-status))) new-status status)
:edit? edit?}]
[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}]
[profile-property-view {:name (label :t/username)
:value (if (not= username address)
username)
:empty-value (label :t/not-specified)
:on-change-text #(dispatch [:set-in [:profile-edit :name] %])
:profile-data profile-edit-data
:platform-specific platform-specific}]
[profile-property-view {:name (label :t/phone-number)
:value (if-not (or (not phone) (str/blank? phone))
(format-phone-number phone))
:empty-value (label :t/not-specified)
:profile-data profile-edit-data
:platform-specific platform-specific}]
[profile-property-view {:name (label :t/email)
:value (if-not (or (not email) (str/blank? email))
email)
:empty-value (label :t/not-specified)
:on-change-text #(dispatch [:set-in [:profile-edit :email] %])
:profile-data profile-edit-data
:platform-specific platform-specific}]
[view st/qr-code-container
[qr-code {:value (clj->json {:name username
:whisper-identity identity})
:size 200}]]]])
[qr-code {:value (clj->js {:name username
:whisper-identity public-key})
:size 150}]]]])

View File

@ -1,41 +1,20 @@
(ns status-im.profile.styles
(:require [status-im.components.styles :refer [font
color-light-blue-transparent
color-white
color-black
color-blue
color-blue-transparent
selected-message-color
online-color
separator-color
text1-color
text2-color]]))
(def profile-property-view-container
{:height 85
:paddingHorizontal 16})
(def profile-property-view-sub-container
{:borderBottomWidth 1
:borderBottomColor separator-color})
(def profile-property-view-label
{:marginTop 16
:fontSize 14
:fontFamily font
:color text2-color})
(def profile-property-view-value
{:marginTop 11
:height 40
:fontSize 16
:fontFamily font
:color text1-color})
color-light-blue-transparent
color-white
color-black
color-blue
color-blue-transparent
selected-message-color
online-color
separator-color
text1-color
text2-color]]))
(def profile
{:flex 1
:backgroundColor color-white
:flexDirection :column})
{:flex 1
:background-color color-white
:flex-direction :column})
(def back-btn-touchable
{:position :absolute})
@ -45,98 +24,133 @@
:height 56})
(def back-btn-icon
{:marginTop 21
:marginLeft 23
:width 8
:height 14})
{:margin-top 21
:margin-left 23
:width 8
:height 14})
(def actions-btn-touchable
{:position :absolute
:right 0})
(def actions-btn-container
{:width 56
:height 56
:alignItems :center
:justifyContent :center})
{:width 56
:height 56
:align-items :center
:justify-content :center})
(def actions-btn-icon
(def edit-btn-icon
{:width 4
:height 16})
(def status-block
{:alignSelf :center
:alignItems :center
:width 249})
(def ok-btn-icon
{:font-size 22
:color :black})
(def user-photo-container
{:marginTop 22})
{:margin-top 22})
(def user-name
{:marginTop 16
:fontSize 18
:fontFamily font
(def username
{:margin-top 12
:font-size 18
:color text1-color})
(def status
{:marginTop 10
:fontFamily font
:fontSize 14
:lineHeight 20
:textAlign :center
:color text2-color})
(def username-input
{:align-self "stretch"
:margin-top -8
:margin-bottom -22
:font-size 18
:text-align :center
:color text1-color})
(def status-block
{:flex-direction "column"
:align-items "center"
:justifyContent "center"})
(def status-input
{:align-self "stretch"
:margin-left 16
:margin-right 16
:height 40
:margin-top -4
:font-size 14
:line-height 20
:text-align :center
:color text2-color})
(def btns-container
{:marginTop 18
:flexDirection :row})
{:margin-top 18
:flex-direction :row})
(def message-btn
{:height 40
:justifyContent :center
:backgroundColor color-blue
:paddingLeft 25
:paddingRight 25
:borderRadius 20})
{:height 40
:justify-content :center
:background-color color-blue
:padding-left 25
:padding-right 25
:border-radius 20})
(def message-btn-text
{:marginTop -2.5
:fontSize 14
:fontFamily font
:color color-white})
{:margin-top -2.5
:font-size 14
:font-family font
:color color-white})
(def more-btn
{:marginLeft 10
:width 40
:height 40
:alignItems :center
:justifyContent :center
:backgroundColor color-blue-transparent
:padding 8
:borderRadius 20})
{:margin-left 10
:width 40
:height 40
:align-items :center
:justify-content :center
:background-color color-blue-transparent
:padding 8
:border-radius 20})
(def more-btn-image
{:width 4
:height 16})
(def profile-properties-container
{:marginTop 20
:alignItems :stretch
:flexDirection :column})
{:margin-top 20
:align-items :stretch
:flex-firection :column})
(def profile-property-view-container
{:padding-left 16})
(def profile-property-view-sub-container
{:border-bottom-width 1
:border-bottom-color separator-color
:padding-right 16})
(def profile-property-view-label
{:margin-top 18
:font-size 14
:color text2-color})
(def profile-property-view-value
{:margin-top 8
:margin-bottom 8
:padding 0
:height 40
:font-size 16
:color text1-color})
(def report-user-container
{:marginTop 50
:marginBottom 43
:alignItems :center})
{:margin-top 50
:margin-bottom 43
:align-items :center})
(def report-user-text
{:fontSize 14
:fontFamily font
:lineHeight 21
:color text2-color
{:font-size 14
:font-family font
:line-height 21
:color text2-color
;; IOS:
:letterSpacing 0.5})
:letter-spacing 0.5})
(def qr-code-container
{:flex 1
{:flex 1
:alignItems :center
:margin 15})
:margin 32})

View File

@ -18,8 +18,9 @@
(register-handler :initialize-protocol
(u/side-effect!
(fn [{:keys [user-identity] :as db} [_ account]]
(init-protocol (or account user-identity) (make-handler db)))))
(fn [db [_ current-account-id]]
(let [current-account (get-in db [:accounts current-account-id])]
(init-protocol current-account (make-handler db))))))
(register-handler :protocol-initialized
(fn [db [_ identity]]

View File

@ -6,7 +6,6 @@
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]))

View File

@ -6,7 +6,6 @@
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-scan]]
[status-im.i18n :refer [label]]
[status-im.qr-scanner.styles :as st]))

View File

@ -12,6 +12,11 @@
(fn [db [_ k]]
(reaction (k @db))))
(register-sub :get-current-account
(fn [db [_ _]]
(reaction (let [current-account-id (:current-account-id @db)]
(get-in @db [:accounts current-account-id])))))
(register-sub :get-in
(fn [db [_ path]]
(reaction (get-in @db path))))

View File

@ -27,8 +27,17 @@
:report-user "REPORT USER"
:message "Message"
:username "Username"
:user-anonymous "Anonymous"
:not-specified "Not specified"
:phone-number "Phone number"
:email "Email"
:profile-no-status "No status"
;;make_photo
:image-source-title "Profile image"
:image-source-make-photo "Capture"
:image-source-gallery "Select from gallery"
:image-source-cancel "Cancel"
;sign-up
:contacts-syncronized "Your contacts have been synchronized"

View File

@ -8,4 +8,9 @@
(let [result (.moveFile fs src dst)
result (.then result #(handler nil %))
result (.catch result #(handler % nil))]
result))
result))
(defn read-file [path encoding on-read on-error]
(-> (.readFile fs path encoding)
(.then on-read)
(.catch on-error)))

View File

@ -0,0 +1,25 @@
(ns status-im.utils.image-processing
(:require [reagent.core :as r]
[status-im.utils.fs :refer [read-file]]))
(def resizer-class (js/require "react-native-image-resizer"))
(defn- resize [path max-width max-height on-resize on-error]
(let [resize-fn (aget resizer-class "default" "createResizedImage")]
(-> (resize-fn path max-width max-height "JPEG" 75 0 nil)
(.then on-resize)
(.catch on-error))))
(defn- image-base64-encode [path on-success on-error]
(let [on-encoded (fn [data]
(on-success data))
on-error (fn [error]
(on-error :base64 error))]
(read-file path "base64" on-encoded on-error)))
(defn img->base64 [path on-success on-error]
(let [on-resized (fn [path]
(image-base64-encode (subs path 5) on-success on-error))
on-error (fn [error]
(on-error :resize error))]
(resize path 150 150 on-resized on-error)))