Desktop branch merged into develop (#5266)
* Desktop branch merged into develop * Fixed review notes by yenda
This commit is contained in:
parent
bdc7284308
commit
457f2a157a
|
@ -1 +1,2 @@
|
|||
*.pbxproj -text
|
||||
*.patch eol=lf
|
||||
|
|
|
@ -108,3 +108,8 @@ fastlane/README.md
|
|||
# emacs
|
||||
.dir-locals.el
|
||||
|
||||
#ignore platform-specific files in the root since they are only symlinks to files in folders 'desktop_files' and 'mobile_files'
|
||||
/VERSION
|
||||
/package-lock.json
|
||||
/package.json
|
||||
/.re-natal
|
||||
|
|
|
@ -9,6 +9,7 @@ def installJSDeps() {
|
|||
def installed = false
|
||||
while (!installed && attempt <= maxAttempts) {
|
||||
println "#${attempt} attempt to install npm deps"
|
||||
sh 'scripts/prepare-for-platform.sh mobile'
|
||||
sh 'npm install'
|
||||
installed = fileExists('node_modules/web3/index.js')
|
||||
attemp = attempt + 1
|
||||
|
@ -72,7 +73,7 @@ timeout(90) {
|
|||
hash = sh(returnStdout: true, script: "curl -vvv 'https://upload.diawi.com/status?token="+token+"&job="+job+"'|jq -r '.hash'").trim()
|
||||
}
|
||||
apkUrl = 'https://i.diawi.com/' + hash
|
||||
|
||||
|
||||
sh ('echo ARTIFACT Android: ' + apkUrl)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,197 @@
|
|||
env.LANG="en_US.UTF-8"
|
||||
env.LANGUAGE="en_US.UTF-8"
|
||||
env.LC_ALL="en_US.UTF-8"
|
||||
|
||||
def installJSDeps() {
|
||||
def attempt = 1
|
||||
def maxAttempts = 10
|
||||
def installed = false
|
||||
sh 'node -v'
|
||||
sh 'npm -v'
|
||||
while (!installed && attempt <= maxAttempts) {
|
||||
println "#${attempt} attempt to install npm deps"
|
||||
sh 'scripts/prepare-for-platform.sh desktop'
|
||||
sh 'npm install --verbose'
|
||||
installed = fileExists('node_modules/web3/index.js')
|
||||
attemp = attempt + 1
|
||||
}
|
||||
}
|
||||
|
||||
def doGitRebase() {
|
||||
try {
|
||||
sh 'git rebase origin/develop'
|
||||
} catch (e) {
|
||||
sh 'git rebase --abort'
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
def cleanupBuild(packageFolder) {
|
||||
sh 'rm -rf node_modules'
|
||||
sh ( 'rm -rf ' + packageFolder )
|
||||
sh 'rm -rf desktop/modules'
|
||||
sh 'rm -rf desktop/node_modules'
|
||||
}
|
||||
|
||||
parallel (
|
||||
"MacOS parallel build stream" : {
|
||||
timeout(90) {
|
||||
node ('macos1') {
|
||||
def apkUrl = ''
|
||||
def ipaUrl = ''
|
||||
def testPassed = true
|
||||
def branch;
|
||||
def scriptOutput = ''
|
||||
def packageFolder = './StatusImPackage'
|
||||
def scriptPath = sh(script: 'pwd -P', returnStdout: true).trim()
|
||||
|
||||
load "$HOME/env.groovy"
|
||||
|
||||
try {
|
||||
|
||||
stage('Git & Dependencies') {
|
||||
slackSend channel: '#jenkins-desktop', color: 'good', message: BRANCH_NAME + '(' + env.CHANGE_BRANCH + ') MacOS build started. ' + env.BUILD_URL
|
||||
|
||||
sh ('echo ' + scriptPath)
|
||||
|
||||
checkout scm
|
||||
|
||||
doGitRebase()
|
||||
|
||||
cleanupBuild(packageFolder)
|
||||
sh 'cp .env.jenkins .env'
|
||||
sh 'lein deps'
|
||||
|
||||
installJSDeps()
|
||||
}
|
||||
|
||||
stage('Build ClojureScript') {
|
||||
sh 'rm -f index.desktop.js'
|
||||
sh 'lein prod-build-desktop'
|
||||
|
||||
sh ( 'mkdir ' + packageFolder )
|
||||
sh ( 'react-native bundle --entry-file index.desktop.js --bundle-output ' + packageFolder + '/StatusIm.jsbundle --dev false --platform desktop --assets-dest ' + packageFolder + '/assets' )
|
||||
}
|
||||
|
||||
stage('Build MacOS binaries') {
|
||||
sh 'cd desktop && rm -rf CMakeFiles CMakeCache.txt cmake_install.cmake Makefile'
|
||||
sh 'export PATH=/Users/administrator/qt/5.9.1/clang_64/bin:$PATH && cd desktop && cmake -DCMAKE_BUILD_TYPE=Release -DEXTERNAL_MODULES_DIR="node_modules/react-native-i18n/desktop;node_modules/react-native-config/desktop;node_modules/react-native-fs/desktop;node_modules/react-native-http-bridge/desktop;node_modules/react-native-webview-bridge/desktop;node_modules/react-native-keychain/desktop;node_modules/react-native-securerandom/desktop;modules/react-native-status/desktop"\
|
||||
-DJS_BUNDLE_PATH="' + scriptPath + '/' + packageFolder + '/StatusIm.jsbundle" -DCMAKE_CXX_FLAGS:="-DBUILD_FOR_BUNDLE=1" . && make'
|
||||
}
|
||||
|
||||
stage('Prepare and create MacOS Bundle') {
|
||||
sh ('cd ' + packageFolder + ' && ../scripts/download-package-files.sh "StatusIm.app.zip" "1Vkb6MD3nsmT02Az6rRRZywQSwCz1ZN9V" && unzip ./StatusIm.app.zip')
|
||||
sh ('cp -r ' + packageFolder + '/assets/share/assets ' + packageFolder +'/StatusIm.app/Contents/MacOs')
|
||||
sh ('chmod +x ' + packageFolder + '/StatusIm.app/Contents/MacOs/ubuntu-server')
|
||||
sh ('cp ./desktop/bin/StatusIm ' + packageFolder +'/StatusIm.app/Contents/MacOs')
|
||||
|
||||
sh ('export PATH=/Users/administrator/qt/5.9.1/clang_64/bin:$PATH && cd ' + packageFolder + ' && macdeployqt StatusIm.app -verbose=1 -dmg -qmldir="' + scriptPath + '/node_modules/react-native/ReactQt/runtime/src/qml/"')
|
||||
|
||||
sh 'rm -f StatusIm.app.zip'
|
||||
}
|
||||
|
||||
stage('Archive built artifact') {
|
||||
archiveArtifacts "StatusImPackage/*.dmg"
|
||||
}
|
||||
|
||||
cleanupBuild(packageFolder)
|
||||
slackSend channel: '#jenkins-desktop', color: 'good', message: BRANCH_NAME + '(' + env.CHANGE_BRANCH + ') MacOS build finished successfully. ' + env.BUILD_URL
|
||||
} catch (e) {
|
||||
cleanupBuild(packageFolder)
|
||||
slackSend channel: '#jenkins-desktop', color: 'bad', message: BRANCH_NAME + ' failed to build on MacOS. ' + env.BUILD_URL
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Linux parallel build stream" : {
|
||||
timeout(90) {
|
||||
node ('linux1') {
|
||||
def apkUrl = ''
|
||||
def ipaUrl = ''
|
||||
def testPassed = true
|
||||
def branch;
|
||||
def scriptOutput = ''
|
||||
def packageFolder = './StatusImPackage'
|
||||
def scriptPath = sh(script: 'pwd -P', returnStdout: true).trim()
|
||||
|
||||
sh ('echo ' + scriptPath)
|
||||
|
||||
try {
|
||||
|
||||
stage('Git & Dependencies') {
|
||||
slackSend channel: '#jenkins-desktop', color: 'good', message: BRANCH_NAME + '(' + env.CHANGE_BRANCH + ') Linux build started. ' + env.BUILD_URL
|
||||
|
||||
sh ('echo ' + scriptPath)
|
||||
|
||||
checkout scm
|
||||
|
||||
doGitRebase()
|
||||
|
||||
cleanupBuild(packageFolder)
|
||||
sh 'cp .env.jenkins .env'
|
||||
sh 'lein deps'
|
||||
|
||||
installJSDeps()
|
||||
}
|
||||
|
||||
stage('Build ClojureScript') {
|
||||
sh 'rm -f index.desktop.js'
|
||||
sh 'lein prod-build-desktop'
|
||||
|
||||
sh ( 'mkdir ' + packageFolder )
|
||||
sh ( 'react-native bundle --entry-file index.desktop.js --bundle-output ' + packageFolder + '/StatusIm.jsbundle --dev false --platform desktop --assets-dest ' + packageFolder + '/assets' )
|
||||
}
|
||||
|
||||
stage('Build Linux binaries') {
|
||||
sh 'cd desktop && rm -rf CMakeFiles CMakeCache.txt cmake_install.cmake Makefile'
|
||||
sh 'export PATH=/home/maxr/Qt5.9.1/5.9.1/gcc_64/bin:/usr/local/go/bin:$PATH && cd desktop && cmake -DCMAKE_BUILD_TYPE=Release -DEXTERNAL_MODULES_DIR="node_modules/react-native-i18n/desktop;node_modules/react-native-config/desktop;node_modules/react-native-fs/desktop;node_modules/react-native-http-bridge/desktop;node_modules/react-native-webview-bridge/desktop;node_modules/react-native-keychain/desktop;node_modules/react-native-securerandom/desktop;modules/react-native-status/desktop"\
|
||||
-DJS_BUNDLE_PATH="' + scriptPath + '/' + packageFolder + '/StatusIm.jsbundle" -DCMAKE_CXX_FLAGS:="-DBUILD_FOR_BUNDLE=1" . && make'
|
||||
}
|
||||
|
||||
stage('Prepare and create Linux AppImage') {
|
||||
sh ('rm -rf ' + packageFolder + '/StatusImAppImage')
|
||||
sh ('cd ' + packageFolder + ' && cp /home/maxr/qttools/StatusImAppImage.zip ./ && unzip ./StatusImAppImage.zip')
|
||||
|
||||
sh ('rm -rf ' + packageFolder + '/AppDir && mkdir ' + packageFolder + '/AppDir')
|
||||
sh ('cp -r ./deployment/linux/usr ' + packageFolder + '/AppDir')
|
||||
sh ('cp ./deployment/linux/.env ' + packageFolder + '/AppDir')
|
||||
sh ('cp ./desktop/bin/StatusIm ' + packageFolder+ '/AppDir/usr/bin')
|
||||
|
||||
sh ('cp -f /home/maxr/qttools/linuxdeployqt-continuous-x86_64.AppImage ./')
|
||||
sh ('chmod a+x ./linuxdeployqt-continuous-x86_64.AppImage')
|
||||
|
||||
sh 'rm -f Application-x86_64.AppImage'
|
||||
sh 'rm -f StatusIm-x86_64.AppImage'
|
||||
|
||||
sh 'ldd ' + packageFolder+ '/AppDir/usr/bin/StatusIm'
|
||||
sh ('export PATH=/home/maxr/Qt5.9.1/5.9.1/gcc_64/bin:/usr/local/go/bin:$PATH && ./linuxdeployqt-continuous-x86_64.AppImage ' + packageFolder+ '/AppDir/usr/share/applications/StatusIm.desktop -verbose=3 -always-overwrite -no-strip -no-translations -bundle-non-qt-libs -qmake=/home/maxr/Qt5.9.1/5.9.1/gcc_64/bin/qmake -extra-plugins=imageformats/libqsvg.so -qmldir="' + scriptPath + '/node_modules/react-native"')
|
||||
sh 'ldd ' + packageFolder+ '/AppDir/usr/bin/StatusIm'
|
||||
|
||||
sh ('cp -r ' + packageFolder + '/assets/share/assets ' + packageFolder +'/AppDir/usr/bin')
|
||||
sh ('cp -rf ' + packageFolder + '/StatusImAppImage/* ' + packageFolder +'/AppDir/usr/bin')
|
||||
sh ('rm -f ' + packageFolder +'/AppDir/usr/bin/StatusIm.AppImage')
|
||||
|
||||
sh ('export PATH=/home/maxr/Qt5.9.1/5.9.1/gcc_64/bin:/usr/local/go/bin:$PATH && ./linuxdeployqt-continuous-x86_64.AppImage ' + packageFolder+ '/AppDir/usr/share/applications/StatusIm.desktop -verbose=3 -appimage -qmake=/home/maxr/Qt5.9.1/5.9.1/gcc_64/bin/qmake')
|
||||
sh 'ldd ' + packageFolder+ '/AppDir/usr/bin/StatusIm'
|
||||
|
||||
sh ('rm -rf ' + packageFolder +'/StatusIm.AppImage')
|
||||
sh ('cp -f ./StatusIm-x86_64.AppImage ' + packageFolder + '/StatusIm.AppImage')
|
||||
|
||||
}
|
||||
|
||||
stage('Archive built artifact') {
|
||||
archiveArtifacts "StatusImPackage/*.AppImage"
|
||||
}
|
||||
|
||||
cleanupBuild(packageFolder)
|
||||
slackSend channel: '#jenkins-desktop', color: 'good', message: BRANCH_NAME + '(' + env.CHANGE_BRANCH + ') Linux build finished successfully. ' + env.BUILD_URL
|
||||
} catch (e) {
|
||||
cleanupBuild(packageFolder)
|
||||
slackSend channel: '#jenkins-desktop', color: 'bad', message: BRANCH_NAME + ' failed to build on Linux. ' + env.BUILD_URL
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
|
@ -12,6 +12,7 @@ def installJSDeps() {
|
|||
def installed = false
|
||||
while (!installed && attempt <= maxAttempts) {
|
||||
println "#${attempt} attempt to install npm deps"
|
||||
sh 'scripts/prepare-for-platform.sh mobile'
|
||||
sh 'npm install'
|
||||
installed = fileExists('node_modules/web3/index.js')
|
||||
attemp = attempt + 1
|
||||
|
|
|
@ -12,6 +12,7 @@ def installJSDeps() {
|
|||
def installed = false
|
||||
while (!installed && attempt <= maxAttempts) {
|
||||
println "#${attempt} attempt to install npm deps"
|
||||
sh 'scripts/prepare-for-platform.sh mobile'
|
||||
sh 'npm install'
|
||||
installed = fileExists('node_modules/web3/index.js')
|
||||
attemp = attempt + 1
|
||||
|
|
|
@ -9,6 +9,7 @@ def installJSDeps() {
|
|||
def installed = false
|
||||
while (!installed && attempt <= maxAttempts) {
|
||||
println "#${attempt} attempt to install npm deps"
|
||||
sh 'scripts/prepare-for-platform.sh mobile'
|
||||
sh 'npm install'
|
||||
installed = fileExists('node_modules/web3/index.js')
|
||||
attemp = attempt + 1
|
||||
|
|
|
@ -12,6 +12,7 @@ def installJSDeps() {
|
|||
def installed = false
|
||||
while (!installed && attempt <= maxAttempts) {
|
||||
println "#${attempt} attempt to install npm deps"
|
||||
sh 'scripts/prepare-for-platform.sh mobile'
|
||||
sh 'npm install'
|
||||
installed = fileExists('node_modules/web3/index.js')
|
||||
attemp = attempt + 1
|
||||
|
|
|
@ -12,6 +12,7 @@ def installJSDeps() {
|
|||
def installed = false
|
||||
while (!installed && attempt <= maxAttempts) {
|
||||
println "#${attempt} attempt to install npm deps"
|
||||
sh 'scripts/prepare-for-platform.sh mobile'
|
||||
sh 'npm install'
|
||||
installed = fileExists('node_modules/web3/index.js')
|
||||
attemp = attempt + 1
|
||||
|
|
|
@ -12,6 +12,7 @@ def installJSDeps() {
|
|||
def installed = false
|
||||
while (!installed && attempt <= maxAttempts) {
|
||||
println "#${attempt} attempt to install npm deps"
|
||||
sh 'scripts/prepare-for-platform.sh mobile'
|
||||
sh 'npm install'
|
||||
installed = fileExists('node_modules/web3/index.js')
|
||||
attemp = attempt + 1
|
||||
|
|
2
Makefile
2
Makefile
|
@ -30,8 +30,10 @@ setup: ##@prepare Install all the requirements for status-react
|
|||
./scripts/setup
|
||||
|
||||
prepare: ##@prepare Install dependencies and prepare workspace
|
||||
scripts/prepare-for-platform.sh mobile
|
||||
npm install
|
||||
|
||||
|
||||
prepare-ios: prepare ##@prepare Install iOS specific dependencies
|
||||
mvn -f modules/react-native-status/ios/RCTStatus dependency:unpack
|
||||
cd ios && pod install && cd ..
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
(def cljsbuild-config
|
||||
{:dev
|
||||
{:ios
|
||||
{:source-paths ["components/src" "react-native/src" "src"]
|
||||
{:source-paths ["components/src" "react-native/src/cljsjs" "react-native/src/mobile" "src"]
|
||||
:compiler {:output-to "target/ios/app.js"
|
||||
:main "env.ios.main"
|
||||
:output-dir "target/ios"
|
||||
|
@ -16,7 +16,7 @@
|
|||
:optimizations :none}
|
||||
:warning-handlers '[status-im.utils.build/warning-handler]}
|
||||
:android
|
||||
{:source-paths ["components/src" "react-native/src" "src"]
|
||||
{:source-paths ["components/src" "react-native/src/cljsjs" "react-native/src/mobile" "src"]
|
||||
:compiler {:output-to "target/android/app.js"
|
||||
:main "env.android.main"
|
||||
:output-dir "target/android"
|
||||
|
@ -26,7 +26,7 @@
|
|||
|
||||
:prod
|
||||
{:ios
|
||||
{:source-paths ["components/src" "react-native/src" "src" "env/prod"]
|
||||
{:source-paths ["components/src" "react-native/src/cljsjs" "react-native/src/mobile" "src" "env/prod"]
|
||||
:compiler {:output-to "index.ios.js"
|
||||
:output-dir "target/ios-prod"
|
||||
:static-fns true
|
||||
|
@ -38,7 +38,7 @@
|
|||
:language-in :ecmascript5}
|
||||
:warning-handlers '[status-im.utils.build/warning-handler]}
|
||||
:android
|
||||
{:source-paths ["components/src" "react-native/src" "src" "env/prod"]
|
||||
{:source-paths ["components/src" "react-native/src/cljsjs" "react-native/src/mobile" "src" "env/prod"]
|
||||
:compiler {:output-to "index.android.js"
|
||||
:output-dir "target/android-prod"
|
||||
:static-fns true
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
(def view (get-class "View"))
|
||||
(def safe-area-view (get-class "SafeAreaView"))
|
||||
|
||||
(def status-bar (get-class "StatusBar"))
|
||||
(def status-bar (get-class (if platform/desktop? "View" "StatusBar")))
|
||||
|
||||
(def scroll-view (get-class "ScrollView"))
|
||||
(def web-view (get-class "WebView"))
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
TESTFAIRY_ENABLED=0
|
||||
STUB_STATUS_GO=0
|
||||
ETHEREUM_DEV_CLUSTER=1
|
||||
MAINNET_NETWORKS_ENABLED=1
|
||||
OFFLINE_INBOX_ENABLED=1
|
||||
OFFLINE_INBOX_MANY_ENABLED=1
|
||||
LOG_LEVEL=debug
|
||||
LOG_LEVEL_STATUS_GO=info
|
||||
JSC_ENABLED=1
|
||||
QUEUE_MESSAGE_ENABLED=1
|
||||
MANY_WHISPER_TOPICS_ENABLED=0
|
||||
RN_BRIDGE_THRESHOLD_WARNINGS=0
|
||||
COMPILE_VIEWS_ENABLED=0
|
||||
POW_TARGET=0.002
|
||||
POW_TIME=1
|
||||
MIXPANEL_TOKEN=3f2e1a8970f159aa2a3d5dc5d65eab38
|
||||
DEFAULT_NETWORK=mainnet_rpc
|
||||
TESTFAIRY_TOKEN=969f6c921cb435cea1d41d1ea3f5b247d6026d55
|
||||
INSTABUG_TOKEN=758630ed52864cbad9c5eeeac596c60c
|
|
@ -0,0 +1,7 @@
|
|||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=StatusIm
|
||||
Comment=StatusIm Desktop
|
||||
Exec=StatusIm
|
||||
Icon=StatusIm
|
||||
Categories=Network;
|
Binary file not shown.
After Width: | Height: | Size: 86 KiB |
2
deps.edn
2
deps.edn
|
@ -1,4 +1,4 @@
|
|||
{:paths ["components/src" "src" "react-native/src" "resources"]
|
||||
{:paths ["components/src" "src" "react-native/src/cljsjs" "react-native/src/mobile" "resources"]
|
||||
:deps {org.clojure/clojure {:mvn/version "1.9.0"}
|
||||
org.clojure/clojurescript {:mvn/version "1.10.238"}
|
||||
org.clojure/core.async {:mvn/version "0.4.474"}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
# Copyright (C) 2016, Canonical Ltd.
|
||||
# All rights reserved.
|
||||
|
||||
# This source code is licensed under the BSD-style license found in the
|
||||
# LICENSE file in the root directory of this source tree. An additional grant
|
||||
# of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
|
||||
set(APP_NAME StatusIm)
|
||||
set(REACT_BUILD_STATIC_LIB ON)
|
||||
|
||||
message(STATUS "EXTERNAL_MODULES_DIR: ${EXTERNAL_MODULES_DIR}")
|
||||
|
||||
foreach(external_module ${EXTERNAL_MODULES_DIR})
|
||||
message(STATUS "external_module: ${external_module}")
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../${external_module} ${CMAKE_CURRENT_BINARY_DIR}/${external_module})
|
||||
endforeach(external_module)
|
||||
|
||||
# APPLICATION_MAIN_CPP_PATH contains absolute path to generated template copy of main.cpp for application executable
|
||||
get_filename_component(APPLICATION_MAIN_CPP_PATH main.cpp ABSOLUTE)
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../node_modules/react-native/React/Layout)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../node_modules/react-native/ReactQt/runtime/src ${CMAKE_CURRENT_BINARY_DIR}/lib)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../node_modules/react-native/ReactQt/application/src ${CMAKE_CURRENT_BINARY_DIR}/bin)
|
||||
|
||||
if (WIN32)
|
||||
set(RUN_SCRIPT_FILE_NAME "run-app.bat")
|
||||
else()
|
||||
set(RUN_SCRIPT_FILE_NAME "run-app.sh")
|
||||
endif()
|
||||
|
||||
configure_file(
|
||||
${RUN_SCRIPT_FILE_NAME}.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${RUN_SCRIPT_FILE_NAME}
|
||||
@ONLY
|
||||
)
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
@rem Copyright (c) 2017-present, Status Research and Development GmbH.
|
||||
@rem All rights reserved.
|
||||
@rem
|
||||
@rem This source code is licensed under the BSD-style license found in the
|
||||
@rem LICENSE file in the root directory of this source tree. An additional grant
|
||||
@rem of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
@echo off
|
||||
setlocal EnableDelayedExpansion
|
||||
|
||||
set "option="
|
||||
for %%a in (%*) do (
|
||||
if not defined option (
|
||||
set arg=%%a
|
||||
if "!arg:~0,1!" equ "-" set "option=!arg!"
|
||||
) else (
|
||||
set "option!option!=%%a"
|
||||
set "option="
|
||||
)
|
||||
)
|
||||
|
||||
SET option
|
||||
@echo on
|
||||
|
||||
echo "build.bat external modules paths: "%option-e%
|
||||
echo "build.bat JS bundle path: "%option-j%
|
||||
echo "build.bat cmake generator: "%option-g%
|
||||
|
||||
@rem Workaround
|
||||
@rem rm -rf CMakeFiles CMakeCache.txt cmake_install.cmake Makefile
|
||||
|
||||
@rem Build project
|
||||
echo %CD%
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -G %option-g% -DEXTERNAL_MODULES_DIR=%option-e% -DJS_BUNDLE_PATH=%option-j% . && cmake --build .
|
|
@ -0,0 +1,32 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Copyright (C) 2016, Canonical Ltd.
|
||||
# All rights reserved.
|
||||
|
||||
# This source code is licensed under the BSD-style license found in the
|
||||
# LICENSE file in the root directory of this source tree. An additional grant
|
||||
# of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
# XXX: Don't move this script
|
||||
cd $(dirname $0)
|
||||
|
||||
while (( "$#" )); do
|
||||
if [[ $1 == "-e" ]]; then
|
||||
shift
|
||||
ExternalModulesPaths="$1"
|
||||
fi
|
||||
if [[ $1 == "-j" ]]; then
|
||||
shift
|
||||
JsBundlePath="$1"
|
||||
fi
|
||||
shift
|
||||
done
|
||||
|
||||
echo "build.sh external modules paths: "$ExternalModulesPaths
|
||||
echo "build.sh JS bundle path: "$JsBundlePath
|
||||
|
||||
# Workaround
|
||||
rm -rf CMakeFiles CMakeCache.txt cmake_install.cmake Makefile
|
||||
|
||||
# Build project
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DEXTERNAL_MODULES_DIR="$ExternalModulesPaths" -DJS_BUNDLE_PATH="$JsBundlePath" . && make
|
|
@ -0,0 +1,284 @@
|
|||
|
||||
/**
|
||||
* Copyright (C) 2016, Canonical Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
// #define BUILD_FOR_BUNDLE
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QFile>
|
||||
#include <QGuiApplication>
|
||||
#include <QProcess>
|
||||
#include <QQuickView>
|
||||
#include <QTimer>
|
||||
#include <QUrl>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include "attachedproperties.h"
|
||||
#include "reactitem.h"
|
||||
#include "rootview.h"
|
||||
#include "utilities.h"
|
||||
|
||||
#ifdef BUILD_FOR_BUNDLE
|
||||
QStringList consoleOutputStrings;
|
||||
bool ubuntuServerStarted = false;
|
||||
#endif
|
||||
|
||||
// TODO: some way to change while running
|
||||
class ReactNativeProperties : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool liveReload READ liveReload WRITE setLiveReload NOTIFY
|
||||
liveReloadChanged)
|
||||
Q_PROPERTY(QUrl codeLocation READ codeLocation WRITE setCodeLocation NOTIFY
|
||||
codeLocationChanged)
|
||||
Q_PROPERTY(QString pluginsPath READ pluginsPath WRITE setPluginsPath NOTIFY
|
||||
pluginsPathChanged)
|
||||
Q_PROPERTY(
|
||||
QString executor READ executor WRITE setExecutor NOTIFY executorChanged)
|
||||
public:
|
||||
ReactNativeProperties(QObject *parent = 0) : QObject(parent) {
|
||||
m_codeLocation = m_packagerTemplate.arg(m_packagerHost).arg(m_packagerPort);
|
||||
}
|
||||
bool liveReload() const { return m_liveReload; }
|
||||
void setLiveReload(bool liveReload) {
|
||||
if (m_liveReload == liveReload)
|
||||
return;
|
||||
m_liveReload = liveReload;
|
||||
Q_EMIT liveReloadChanged();
|
||||
}
|
||||
QUrl codeLocation() const { return m_codeLocation; }
|
||||
void setCodeLocation(const QUrl &codeLocation) {
|
||||
if (m_codeLocation == codeLocation)
|
||||
return;
|
||||
m_codeLocation = codeLocation;
|
||||
Q_EMIT codeLocationChanged();
|
||||
}
|
||||
QString pluginsPath() const { return m_pluginsPath; }
|
||||
void setPluginsPath(const QString &pluginsPath) {
|
||||
if (m_pluginsPath == pluginsPath)
|
||||
return;
|
||||
m_pluginsPath = pluginsPath;
|
||||
Q_EMIT pluginsPathChanged();
|
||||
}
|
||||
QString executor() const { return m_executor; }
|
||||
void setExecutor(const QString &executor) {
|
||||
if (m_executor == executor)
|
||||
return;
|
||||
m_executor = executor;
|
||||
Q_EMIT executorChanged();
|
||||
}
|
||||
QString packagerHost() const { return m_packagerHost; }
|
||||
void setPackagerHost(const QString &packagerHost) {
|
||||
if (m_packagerHost == packagerHost)
|
||||
return;
|
||||
m_packagerHost = packagerHost;
|
||||
setCodeLocation(m_packagerTemplate.arg(m_packagerHost).arg(m_packagerPort));
|
||||
}
|
||||
QString packagerPort() const { return m_packagerPort; }
|
||||
void setPackagerPort(const QString &packagerPort) {
|
||||
if (m_packagerPort == packagerPort)
|
||||
return;
|
||||
m_packagerPort = packagerPort;
|
||||
setCodeLocation(m_packagerTemplate.arg(m_packagerHost).arg(m_packagerPort));
|
||||
}
|
||||
void setLocalSource(const QString &source) {
|
||||
if (m_localSource == source)
|
||||
return;
|
||||
|
||||
// overrides packager*
|
||||
if (source.startsWith("file:")) {
|
||||
setCodeLocation(source);
|
||||
} else {
|
||||
QFileInfo fi(source);
|
||||
if (!fi.exists()) {
|
||||
qWarning() << "Attempt to set non-existent local source file";
|
||||
return;
|
||||
}
|
||||
setCodeLocation(QUrl::fromLocalFile(fi.absoluteFilePath()));
|
||||
setLiveReload(false);
|
||||
}
|
||||
}
|
||||
Q_SIGNALS:
|
||||
void liveReloadChanged();
|
||||
void codeLocationChanged();
|
||||
void pluginsPathChanged();
|
||||
void executorChanged();
|
||||
|
||||
private:
|
||||
bool m_liveReload = false;
|
||||
QString m_packagerHost = "localhost";
|
||||
QString m_packagerPort = "8081";
|
||||
QString m_localSource;
|
||||
QString m_packagerTemplate =
|
||||
"http://%1:%2/index.desktop.bundle?platform=desktop&dev=true";
|
||||
QUrl m_codeLocation;
|
||||
QString m_pluginsPath;
|
||||
#ifdef BUILD_FOR_BUNDLE
|
||||
QString m_executor = "RemoteServerConnection";
|
||||
#else
|
||||
QString m_executor = "LocalServerConnection";
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef BUILD_FOR_BUNDLE
|
||||
void runUbuntuServer();
|
||||
void saveMessage(QtMsgType type, const QMessageLogContext &context,
|
||||
const QString &msg);
|
||||
|
||||
void writeLogsToFile();
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
Q_INIT_RESOURCE(react_resources);
|
||||
|
||||
#ifdef BUILD_FOR_BUNDLE
|
||||
QString dataFolder = QDir::homePath() + "/Library/StatusIm/";
|
||||
qInstallMessageHandler(saveMessage);
|
||||
|
||||
QDir dir(dataFolder + "ethereum/mainnet_rpc");
|
||||
if (!dir.exists()) {
|
||||
dir.mkpath(".");
|
||||
}
|
||||
|
||||
runUbuntuServer();
|
||||
#endif
|
||||
|
||||
QQuickView view;
|
||||
ReactNativeProperties *rnp = new ReactNativeProperties(&view);
|
||||
#ifdef BUILD_FOR_BUNDLE
|
||||
rnp->setCodeLocation("file:" + QGuiApplication::applicationDirPath() +
|
||||
"/assets");
|
||||
#endif
|
||||
|
||||
utilities::registerReactTypes();
|
||||
|
||||
QCommandLineParser p;
|
||||
p.setApplicationDescription("React Native host application");
|
||||
p.addHelpOption();
|
||||
p.addOptions({
|
||||
{{"R", "live-reload"}, "Enable live reload."},
|
||||
{{"H", "host"}, "Set packager host address.", rnp->packagerHost()},
|
||||
{{"P", "port"}, "Set packager port number.", rnp->packagerPort()},
|
||||
{{"L", "local"}, "Set path to the local packaged source", "not set"},
|
||||
{{"M", "plugins-path"}, "Set path to node modules", "./plugins"},
|
||||
{{"E", "executor"}, "Set Javascript executor", rnp->executor()},
|
||||
});
|
||||
p.process(app);
|
||||
rnp->setLiveReload(p.isSet("live-reload"));
|
||||
if (p.isSet("host"))
|
||||
rnp->setPackagerHost(p.value("host"));
|
||||
if (p.isSet("port"))
|
||||
rnp->setPackagerPort(p.value("port"));
|
||||
if (p.isSet("local"))
|
||||
rnp->setLocalSource(p.value("local"));
|
||||
if (p.isSet("plugins-path"))
|
||||
rnp->setPluginsPath(p.value("plugins-path"));
|
||||
if (p.isSet("executor"))
|
||||
rnp->setExecutor(p.value("executor"));
|
||||
|
||||
view.rootContext()->setContextProperty("ReactNativeProperties", rnp);
|
||||
view.setSource(QUrl("qrc:///main.qml"));
|
||||
view.setResizeMode(QQuickView::SizeRootObjectToView);
|
||||
view.show();
|
||||
|
||||
#ifdef BUILD_FOR_BUNDLE
|
||||
QTimer t;
|
||||
t.setInterval(500);
|
||||
QObject::connect(&t, &QTimer::timeout, [=]() { writeLogsToFile(); });
|
||||
t.start();
|
||||
#endif
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
#ifdef BUILD_FOR_BUNDLE
|
||||
|
||||
void writeLogsToFile() {
|
||||
QFile logFile(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/StatusIm.log");
|
||||
if (logFile.open(QIODevice::WriteOnly | QIODevice::Append)) {
|
||||
for (QString message : consoleOutputStrings) {
|
||||
logFile.write(message.toStdString().c_str());
|
||||
}
|
||||
consoleOutputStrings.clear();
|
||||
|
||||
logFile.flush();
|
||||
logFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
void runUbuntuServer() {
|
||||
QProcess *process = new QProcess();
|
||||
process->setProgram(QGuiApplication::applicationDirPath() + "/ubuntu-server");
|
||||
QObject::connect(process, &QProcess::errorOccurred,
|
||||
[=](QProcess::ProcessError) {
|
||||
qDebug() << "process name: " << process->program();
|
||||
qDebug() << "process error: " << process->errorString();
|
||||
});
|
||||
|
||||
QObject::connect(process, &QProcess::readyReadStandardOutput, [=] {
|
||||
qDebug() << "ubuntu-server std: "
|
||||
<< process->readAllStandardOutput().trimmed();
|
||||
});
|
||||
QObject::connect(process, &QProcess::readyReadStandardError, [=] {
|
||||
QString output = process->readAllStandardError().trimmed();
|
||||
qDebug() << "ubuntu-server err: " << output;
|
||||
if (output.contains("Server starting")) {
|
||||
ubuntuServerStarted = true;
|
||||
}
|
||||
});
|
||||
|
||||
QObject::connect(QGuiApplication::instance(), &QCoreApplication::aboutToQuit,
|
||||
[=]() {
|
||||
qDebug() << "Kill ubuntu server";
|
||||
process->kill();
|
||||
});
|
||||
|
||||
qDebug() << "starting ubuntu server...";
|
||||
process->start();
|
||||
qDebug() << "wait for started...";
|
||||
|
||||
while (!ubuntuServerStarted) {
|
||||
QGuiApplication::processEvents();
|
||||
}
|
||||
|
||||
qDebug() << "waiting finished";
|
||||
}
|
||||
|
||||
void saveMessage(QtMsgType type, const QMessageLogContext &context,
|
||||
const QString &msg) {
|
||||
|
||||
QByteArray localMsg = msg.toLocal8Bit();
|
||||
QString message = localMsg + "\n";
|
||||
|
||||
switch (type) {
|
||||
case QtDebugMsg:
|
||||
consoleOutputStrings << "Debug: " << message << "\n";
|
||||
break;
|
||||
case QtInfoMsg:
|
||||
consoleOutputStrings << "Info: " << message << "\n";
|
||||
break;
|
||||
case QtWarningMsg:
|
||||
consoleOutputStrings << "Warning: " << message << "\n";
|
||||
break;
|
||||
case QtCriticalMsg:
|
||||
consoleOutputStrings << "Critical: " << message << "\n";
|
||||
break;
|
||||
case QtFatalMsg:
|
||||
|
||||
consoleOutputStrings << "Fatal: " << message << "\n";
|
||||
writeLogsToFile();
|
||||
abort();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "main.moc"
|
|
@ -0,0 +1,11 @@
|
|||
@rem Copyright (c) 2017-present, Status Research and Development GmbH.
|
||||
@rem All rights reserved.
|
||||
@rem
|
||||
@rem This source code is licensed under the BSD-style license found in the
|
||||
@rem LICENSE file in the root directory of this source tree. An additional grant
|
||||
@rem of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
|
||||
@rem Run app locally
|
||||
@CMAKE_BINARY_DIR@/bin/@APP_NAME@
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Copyright (C) 2016, Canonical Ltd.
|
||||
# All rights reserved.
|
||||
|
||||
# This source code is licensed under the BSD-style license found in the
|
||||
# LICENSE file in the root directory of this source tree. An additional grant
|
||||
# of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
args=""
|
||||
on_device=0
|
||||
plugins_path=""
|
||||
asset_path="share"
|
||||
executor=""
|
||||
|
||||
react_host=`hostname -I`
|
||||
|
||||
# Parse args
|
||||
for arg in "$@"
|
||||
do
|
||||
IFS="=" read -a parts <<< "$arg"
|
||||
if [[ $parts == "--on-device" ]]; then
|
||||
on_device=1
|
||||
elif [[ $parts == "--plugins-path" ]]; then
|
||||
plugins_path=${parts[1]}
|
||||
args=$args" --plugins-path=./plugins"
|
||||
elif [[ $parts == "--asset-path" ]]; then
|
||||
asset_path=${parts[1]}
|
||||
elif [[ $parts == "--executor" ]]; then
|
||||
if [[ $on_device == 1 ]]; then
|
||||
# Force net executor for now
|
||||
executor="ReactNetExecutor"
|
||||
else
|
||||
executor=${parts[1]}
|
||||
fi
|
||||
args=$args" --executor=$executor"
|
||||
else
|
||||
args=$args" $parts"
|
||||
fi
|
||||
done
|
||||
|
||||
# Handle defaults
|
||||
if [[ -z "$executor" ]]; then
|
||||
if [[ $on_device == 1 ]]; then
|
||||
executor="ReactNetExecutor"
|
||||
args=$args" --executor=ReactNetExecutor"
|
||||
fi
|
||||
|
||||
# The RN application selects pipe executor by default
|
||||
fi
|
||||
|
||||
# For net case, try and run executor; it is probably OK if this fails - it's
|
||||
# just running elsewhere
|
||||
if [[ "$executor" == "ReactNetExecutor" ]]; then
|
||||
(node @CMAKE_BINARY_DIR@/bin/ubuntu-server.js 2>&1 > /dev/null) &
|
||||
fi
|
||||
|
||||
if [[ $on_device == 1 ]]; then
|
||||
app_path="/home/phablet/@APP_NAME@"
|
||||
|
||||
# Push binaries
|
||||
adb push @CMAKE_BINARY_DIR@/bin/@APP_NAME@ "$app_path/@APP_NAME@"
|
||||
[ -d "$plugins_path" ] && adb push "$plugins_path" "$app_path/plugins/"
|
||||
[ -d "$asset_path" ] && adb push "$asset_path" "$app_path/share/"
|
||||
# adb reverse --no-rebind tcp:8081 tcp:808
|
||||
|
||||
# Run app on device
|
||||
adb shell "cd $app_path && REACT_SERVER_HOST=$react_host ./@APP_NAME@ --host $react_host $args -- --desktop_file_hint=/usr/share/applications/webbrowser-app.desktop"
|
||||
else
|
||||
# Run app locally
|
||||
@CMAKE_BINARY_DIR@/bin/@APP_NAME@ $args
|
||||
fi
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
{
|
||||
"name": "StatusIm",
|
||||
"interface": "reagent",
|
||||
"platforms": {
|
||||
"ios": {
|
||||
"host": "localhost",
|
||||
"modules": [
|
||||
"react-native-image-resizer",
|
||||
"react-native-camera",
|
||||
"instabug-reactnative",
|
||||
"nfc-react-native",
|
||||
"react-native-background-timer",
|
||||
"react-native-testfairy"
|
||||
]
|
||||
},
|
||||
"android": {
|
||||
"host": "10.0.2.2",
|
||||
"modules": [
|
||||
"react-native-image-resizer",
|
||||
"react-native-camera",
|
||||
"instabug-reactnative",
|
||||
"nfc-react-native",
|
||||
"react-native-background-timer",
|
||||
"react-native-testfairy"
|
||||
]
|
||||
},
|
||||
"desktop": {
|
||||
"host": "localhost",
|
||||
"modules": []
|
||||
}
|
||||
},
|
||||
"modules": [
|
||||
"realm",
|
||||
"react-native-i18n",
|
||||
"realm/react-native",
|
||||
"dismissKeyboard",
|
||||
"react-native-splash-screen",
|
||||
"react-native-status",
|
||||
"react-native-qrcode",
|
||||
"identicon.js",
|
||||
"react-native-fs",
|
||||
"react-native-dialogs",
|
||||
"react-native-image-crop-picker",
|
||||
"react-native-securerandom",
|
||||
"react-native-webview-bridge",
|
||||
"react-native-fcm",
|
||||
"homoglyph-finder",
|
||||
"web3",
|
||||
"chance",
|
||||
"react-native-http-bridge",
|
||||
"emojilib",
|
||||
"react-native-config",
|
||||
"react-native-svg",
|
||||
"react-native-keychain",
|
||||
"rn-snoopy",
|
||||
"rn-snoopy/stream/bars",
|
||||
"rn-snoopy/stream/filter",
|
||||
"rn-snoopy/stream/buffer",
|
||||
"react-native/Libraries/vendor/emitter/EventEmitter",
|
||||
"react-native-fetch-polyfill"
|
||||
],
|
||||
"imageDirs": [
|
||||
"resources/images",
|
||||
"resources/icons"
|
||||
],
|
||||
"envRoots": {
|
||||
"dev": "env/dev",
|
||||
"prod": "env/prod"
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
0.0.1
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,83 @@
|
|||
{
|
||||
"name": "StatusIm",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "node node_modules/react-native/local-cli/cli.js start",
|
||||
"prepare": "patch-package"
|
||||
},
|
||||
"desktopExternalModules": [
|
||||
"node_modules/react-native-i18n/desktop",
|
||||
"node_modules/react-native-config/desktop",
|
||||
"node_modules/react-native-fs/desktop",
|
||||
"node_modules/react-native-http-bridge/desktop",
|
||||
"node_modules/react-native-webview-bridge/desktop",
|
||||
"node_modules/react-native-keychain/desktop",
|
||||
"node_modules/react-native-securerandom/desktop",
|
||||
"modules/react-native-status/desktop"
|
||||
],
|
||||
"dependencies": {
|
||||
"assert": "1.4.1",
|
||||
"asyncstorage-down": "4.0.1",
|
||||
"babel-core": "6.24.1",
|
||||
"babel-generator": "6.24.1",
|
||||
"babel-helper-builder-react-jsx": "6.18.0",
|
||||
"babel-plugin-transform-es2015-block-scoping": "6.15.0",
|
||||
"babel-preset-react-native": "4.0.0",
|
||||
"babel-register": "6.18.0",
|
||||
"bignumber.js": "github:status-im/bignumber.js#master",
|
||||
"buffer": "3.6.0",
|
||||
"chance": "1.0.12",
|
||||
"create-react-class": "15.6.2",
|
||||
"dns.js": "1.0.1",
|
||||
"emojilib": "2.2.9",
|
||||
"events": "1.1.1",
|
||||
"homoglyph-finder": "1.1.1",
|
||||
"identicon.js": "github:status-im/identicon.js",
|
||||
"instabug-reactnative": "2.12.0",
|
||||
"level-filesystem": "1.2.0",
|
||||
"metro": "^0.30.2",
|
||||
"nfc-react-native": "github:status-im/nfc-react-native",
|
||||
"process": "0.11.10",
|
||||
"prop-types": "15.6.0",
|
||||
"punycode": "1.4.1",
|
||||
"querystring-es3": "0.2.1",
|
||||
"re-natal": "git+https://github.com/status-im/re-natal.git#master",
|
||||
"react": "16.3.1",
|
||||
"react-dom": "16.3.1",
|
||||
"react-native": "git+https://github.com/status-im/react-native-desktop.git",
|
||||
"react-native-background-timer": "2.0.0",
|
||||
"react-native-camera": "0.10.0",
|
||||
"react-native-config": "git+https://github.com/status-im/react-native-config.git",
|
||||
"react-native-crypto": "2.1.1",
|
||||
"react-native-dialogs": "0.0.20",
|
||||
"react-native-fcm": "10.0.3",
|
||||
"react-native-fetch-polyfill": "1.1.2",
|
||||
"react-native-fs": "git+https://github.com/status-im/react-native-fs.git",
|
||||
"react-native-http": "github:tradle/react-native-http#834492d",
|
||||
"react-native-http-bridge": "git+https://github.com/status-im/react-native-http-bridge.git#desktop",
|
||||
"react-native-i18n": "git+https://github.com/status-im/react-native-i18n.git#version_0.0.8_desktop",
|
||||
"react-native-image-crop-picker": "0.18.1",
|
||||
"react-native-image-resizer": "1.0.0",
|
||||
"react-native-invertible-scroll-view": "1.1.0",
|
||||
"react-native-keychain": "git+https://github.com/status-im/react-native-keychain.git",
|
||||
"react-native-level-fs": "3.0.0",
|
||||
"react-native-os": "1.1.0",
|
||||
"react-native-qrcode": "0.2.6",
|
||||
"react-native-securerandom": "git+https://github.com/status-im/react-native-securerandom.git",
|
||||
"react-native-splash-screen": "3.0.6",
|
||||
"react-native-svg": "6.3.1",
|
||||
"react-native-tcp": "3.3.0",
|
||||
"react-native-testfairy": "2.10.0",
|
||||
"react-native-udp": "2.2.1",
|
||||
"react-native-webview-bridge": "github:status-im/react-native-webview-bridge#react-native-0.49-desktop",
|
||||
"realm": "git+https://github.com/status-im/realm-js.git",
|
||||
"rn-snoopy": "github:status-im/rn-snoopy",
|
||||
"string_decoder": "0.10.31",
|
||||
"url": "0.10.3",
|
||||
"web3": "github:status-im/web3.js#feature/shhext"
|
||||
},
|
||||
"devDependencies": {
|
||||
"patch-package": "^5.1.1"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
# Prerequisites:
|
||||
lein, node.js v.8 , cmake, Qt 5.9.1 (with QtWebEngine components installed), Qt's qmake available in PATH
|
||||
|
||||
Note: add qmake to PATH via
|
||||
`export PATH=<QT_PATH>/clang_64/bin:$PATH`
|
||||
|
||||
Caveats:
|
||||
- if npm hangs at some step, check the version. If it's 5.6.0, try downgrading to 5.5.1 via `npm install -g npm@5.5.1`
|
||||
|
||||
# To install react-native-cli with desktop commands support:
|
||||
1. git clone https://github.com/status-im/react-native-desktop.git
|
||||
2. cd react-native-desktop/react-native-cli
|
||||
3. npm update
|
||||
4. npm install -g
|
||||
|
||||
# To setup re-natal dev builds of status-react for Desktop:
|
||||
1. git clone https://github.com/status-im/status-react.git
|
||||
2. cd status-react
|
||||
3. git checkout desktop
|
||||
4. npm install
|
||||
5. lein deps
|
||||
6. ./re-natal use-figwheel
|
||||
7. ./re-natal enable-source-maps
|
||||
8. In separate terminal tab: `npm start` (note: it starts react-native packager )
|
||||
9. In separate terminal tab: node ./ubuntu-server.js
|
||||
10. In separate terminal tab: lein figwheel-repl desktop (note: wait until sources compiled)
|
||||
11. In separate terminal tab: react-native run-desktop
|
||||
|
||||
# Editor setup
|
||||
Running `lein figwheel-repl desktop` will run a REPL on port 7888 by default. Some additional steps might be needed to connect to it.
|
||||
|
||||
## emacs-cider
|
||||
In order to get REPL working, use the below elisp code:
|
||||
```
|
||||
(defun custom-cider-jack-in ()
|
||||
(interactive)
|
||||
(let ((status-desktop-params "with-profile +figwheel repl"))
|
||||
(set-variable 'cider-lein-parameters status-desktop-params)
|
||||
(message "setting 'cider-lein-parameters")
|
||||
(cider-jack-in)))
|
||||
|
||||
(defun start-figwheel-cljs-repl ()
|
||||
(interactive)
|
||||
(set-buffer "*cider-repl status-react*")
|
||||
(goto-char (point-max))
|
||||
(insert "(do (use 'figwheel-api)
|
||||
(start [:desktop])
|
||||
(start-cljs-repl))")
|
||||
(cider-repl-return))
|
||||
```
|
||||
|
||||
`custom-cider-jack-in` sets the correct profile for leiningen, and can be run as soon as emacs is open.
|
||||
run `start-figwheel-cljs-repl` once you already have a cider repl session from the jack-in
|
||||
|
||||
## vim-fireplace
|
||||
For some reason there is no `.nrepl-port` file in project root, so `vim-fireplace` will not be able to connect automatically. You can either:
|
||||
- run `:Connect` and answer a couple of interactive prompts
|
||||
- create `.nrepl-port` file manually and add a single line containing `7888` (or whatever port REPL is running on)
|
||||
|
||||
After Figwheel has connected to the app, run `:Piggieback (figwheel-sidecar.repl-api/repl-env)` inside Vim, and you should be all set.
|
|
@ -0,0 +1,136 @@
|
|||
These are some common issues you may run into while setting up React Native Qt.
|
||||
|
||||
## Initial setup issues
|
||||
|
||||
### `npm install` hangs
|
||||
Downgrade to version 5.5.1: `npm install -g npm@5.5.1`.
|
||||
|
||||
### `re-natal` missing
|
||||
Create a link:
|
||||
`ln -sf node_modules/re-natal/index.js re-natal`
|
||||
|
||||
|
||||
### `react-native run desktop` complaining about missing `qmldir`:
|
||||
```Command failed: ./build.sh -e "node_modules/react-native-i18n/desktop;node_modules/react-native-config/desktop;node_modules/react-native-fs/desktop;node_modules/react-native-http-bridge/desktop;node_modules/react-native-webview-bridge/desktop;modules/react-native-status/desktop"
|
||||
Error copying directory from "/path-to-status-react/node_modules/react-native/ReactQt/runtime/src/qmldir" to "/path-to-status-react/desktop/lib/React".
|
||||
make[2]: *** [lib/CMakeFiles/copy-qmldir] Error 1
|
||||
make[1]: *** [lib/CMakeFiles/copy-qmldir.dir/all] Error 2
|
||||
make: *** [all] Error 2
|
||||
```
|
||||
Can be solved by re-running `npm install react-native` which put the `ReactQt/runtime/src/qmldir` file back.
|
||||
|
||||
### Missing web3 package issue
|
||||
|
||||
After last upgrade of react-native-desktop to the v.0.53.3 of original react-native appeared some incompatibility between `react-native` and `web3` packages on npm install. Initially it installed usually fine, but after `react-native desktop` command execution `web3` package is get removed from `node_modules`. Manual install of web3 by `npm install web3` installs `web3` package, but removes `react-native` package. Workaround or solution?
|
||||
|
||||
### Go problem
|
||||
```
|
||||
panic: runloop has just unexpectedly stopped
|
||||
|
||||
goroutine 50 [running]:
|
||||
github.com/status-im/status-go/vendor/github.com/rjeczalik/notify.init.0.func1()
|
||||
/path-to-status-react/desktop/modules/react-native-status/desktop/StatusGo/src/github.com/status-im/status-go/vendor/github.com/rjeczalik/notify/watcher_fsevents_cgo.go:69 +0x79
|
||||
created by github.com/status-im/status-go/vendor/github.com/rjeczalik/notify.init.0
|
||||
/path-to-status-react/desktop/modules/react-native-status/desktop/StatusGo/src/github.com/status-im/status-go/vendor/github.com/rjeczalik/notify/watcher_fsevents_cgo.go:65 +0x4e
|
||||
events.js:183
|
||||
throw er; // Unhandled 'error' event
|
||||
```
|
||||
Related to https://github.com/rjeczalik/notify/issues/139. Solution: re-run.
|
||||
|
||||
## App issues
|
||||
|
||||
### Eth node crashing
|
||||
`node ./ubuntu_server.js` log:
|
||||
```
|
||||
DEBUG [status-im.utils.handlers:36] - Handling re-frame event: :signal-event {"type":"node.crashed","event":{"error":"node is already running"}}
|
||||
DEBUG [status-im.ui.screens.events:350] - :event-str {"type":"node.crashed","event":{"error":"node is already running"}}
|
||||
DEBUG [status-im.utils.instabug:8] - Signal event: {"type":"node.crashed","event":{"error":"node is already running"}}
|
||||
DEBUG [status-im.ui.screens.events:362] - Event node.crashed not handled
|
||||
```
|
||||
Solution: prevent starting Ethereum local node when there is an instance already running.
|
||||
|
||||
### Reload JS - blank screen
|
||||
Console log for `react-native run-desktop` shows error 533.
|
||||
Solution: reload again. Still, might hang at `Signing you in...` step (due to node attempted to be restarted). Re-run Figwheel and `react-native run-desktop`
|
||||
|
||||
### ReactButton.qml non-existent property "elide" error upon startup
|
||||
```
|
||||
qrc:/qml/ReactButton.qml:33: Error: Cannot assign to non-existent property "elide"
|
||||
"Component for qrc:/qml/ReactWebView.qml is not loaded"
|
||||
QQmlComponent: Component is not ready
|
||||
"Unable to construct item from component qrc:/qml/ReactWebView.qml"
|
||||
"Can't create QML item for componenet qrc:/qml/ReactWebView.qml"
|
||||
"RCTWebViewView" has no view for inspecting!
|
||||
```
|
||||
Reload JS does not help, restarting Figwheel/react-native might not as well. Restarting Metro bundler solved it for me.
|
||||
|
||||
### After login when several contacts are available: realm errors
|
||||
1. `attempting to create an object of type 'chat'...`
|
||||
2. `attempting to create an object of type 'transport'...`
|
||||
3. Error text containing only the public key.
|
||||
The realm stack trace follows.
|
||||
|
||||
### Error: spawn gnome-terminal ENOENT
|
||||
In node server log:
|
||||
```
|
||||
ignoring exception: Error: read ECONNRESET
|
||||
```
|
||||
In react-native log:
|
||||
```
|
||||
./run-app.sh: line 72: 56660 Segmentation fault: 11 /path-to-status-react/desktop/bin/StatusIm $args
|
||||
events.js:183
|
||||
throw er; // Unhandled 'error' event
|
||||
^
|
||||
|
||||
Error: spawn gnome-terminal ENOENT
|
||||
at _errnoException (util.js:992:11)
|
||||
at Process.ChildProcess._handle.onexit (internal/child_process.js:190:19)
|
||||
at onErrorNT (internal/child_process.js:372:16)
|
||||
at _combinedTickCallback (internal/process/next_tick.js:138:11)
|
||||
at process._tickCallback (internal/process/next_tick.js:180:9)
|
||||
```
|
||||
or
|
||||
```
|
||||
StatusIm(7924,0x70000c1cd000) malloc: *** error for object 0x7f8b1539bd10: incorrect checksum for freed object - object was probably modified after being freed.
|
||||
*** set a breakpoint in malloc_error_break to debug
|
||||
./run-app.sh: line 72: 7924 Abort trap: 6 /path-to-status-react/desktop/bin/StatusIm $args
|
||||
events.js:183
|
||||
throw er; // Unhandled 'error' event
|
||||
^
|
||||
|
||||
Error: spawn gnome-terminal ENOENT
|
||||
at _errnoException (util.js:992:11)
|
||||
at Process.ChildProcess._handle.onexit (internal/child_process.js:190:19)
|
||||
at onErrorNT (internal/child_process.js:372:16)
|
||||
at _combinedTickCallback (internal/process/next_tick.js:138:11)
|
||||
at process._tickCallback (internal/process/next_tick.js:180:9)
|
||||
```
|
||||
|
||||
### statusgo error during `react-native run-desktop`
|
||||
|
||||
```
|
||||
Command failed: build(.)sh -e "node_modules/react-native-i18n/desktop;node_modules/react-native-config/desktop;node_modules/react-native-fs/desktop;node_modules/react-native-http-bridge/desktop;node_modules/react-native-webview-bridge/desktop;modules/react-native-status/desktop"
|
||||
# github.com/status-im/status-go/vendor/github.com/ethereum/go-ethereum/crypto/bn256
|
||||
../vendor/github.com/ethereum/go-ethereum/crypto/bn256/bn256_fast.go:26: syntax error: unexpected = in type declaration
|
||||
../vendor/github.com/ethereum/go-ethereum/crypto/bn256/bn256_fast.go:30: syntax error: unexpected = in type declaration
|
||||
# github.com/status-im/status-go/vendor/github.com/ethereum/go-ethereum/crypto/bn256
|
||||
vendor/github.com/ethereum/go-ethereum/crypto/bn256/bn256_fast.go:26: syntax error: unexpected = in type declaration
|
||||
vendor/github.com/ethereum/go-ethereum/crypto/bn256/bn256_fast.go:30: syntax error: unexpected = in type declaration
|
||||
make[3]: *** [statusgo-library] Error 2
|
||||
make[2]: *** [modules/react-native-status/desktop/StatusGo/src/github.com/status-im/src/StatusGo_ep-stamp/StatusGo_ep-configure] Error 2
|
||||
make[1]: *** [modules/react-native-status/desktop/CMakeFiles/StatusGo_ep(.)dir/all] Error 2
|
||||
make: *** [all] Error 2
|
||||
```
|
||||
|
||||
### inotify errors
|
||||
|
||||
upon running `npm start` on linux, watchman may indicate: "The user limit on the total number of inotify watches was reached"
|
||||
|
||||
This can be fixed by running the below command. Note, changes will only be as valid as the current terminal session.
|
||||
|
||||
```
|
||||
echo 999999 | sudo tee -a /proc/sys/fs/inotify/max_user_watches && echo 999999 | sudo tee -a
|
||||
/proc/sys/fs/inotify/max_queued_events && echo 999999 | sudo tee -a /proc/sys/fs/inotify/max_user_instances &&
|
||||
watchman shutdown-server && sudo sysctl -p
|
||||
```
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
(ns env.config)
|
||||
|
||||
|
||||
(def figwheel-urls {:android "ws://192.168.10.203:3449/figwheel-ws",
|
||||
:ios "ws://localhost:3449/figwheel-ws"}
|
||||
)
|
||||
:ios "ws://localhost:3449/figwheel-ws",
|
||||
:desktop "ws://localhost:3449/figwheel-ws"})
|
||||
|
|
|
@ -18,11 +18,11 @@
|
|||
;; Do not delete, root-el is used by the figwheel-bridge.js
|
||||
(def root-el (r/as-element [reloader]))
|
||||
|
||||
(figwheel/start {:websocket-url (:ios conf/figwheel-urls)
|
||||
(figwheel/start {:websocket-url (:desktop conf/figwheel-urls)
|
||||
:heads-up-display false
|
||||
:jsload-callback #(swap! cnt inc)})
|
||||
|
||||
(utils.handlers/add-pre-event-callback rr/pre-event-callback)
|
||||
|
||||
(rr/enable-re-frisk-remote! {:host (env.utils/re-frisk-url (:ios conf/figwheel-urls))
|
||||
(rr/enable-re-frisk-remote! {:host (env.utils/re-frisk-url (:desktop conf/figwheel-urls))
|
||||
:on-init core/init})
|
||||
|
|
|
@ -4,15 +4,15 @@
|
|||
(defn system-options [builds-to-start]
|
||||
{:nrepl-port 7888
|
||||
:builds [{:id :desktop
|
||||
:source-paths ["react-native/src" "src" "env/dev"]
|
||||
:compiler {:output-to "target/ios/desktop.js"
|
||||
:source-paths ["react-native/src/cljsjs" "react-native/src/desktop" "src" "env/dev"]
|
||||
:compiler {:output-to "target/desktop/app.js"
|
||||
:main "env.desktop.main"
|
||||
:output-dir "target/desktop"
|
||||
:npm-deps false
|
||||
:optimizations :none}
|
||||
:figwheel true}
|
||||
{:id :ios
|
||||
:source-paths ["react-native/src" "src" "env/dev"]
|
||||
:source-paths ["react-native/src/cljsjs" "react-native/src/mobile" "src" "env/dev"]
|
||||
:compiler {:output-to "target/ios/app.js"
|
||||
:main "env.ios.main"
|
||||
:output-dir "target/ios"
|
||||
|
@ -20,7 +20,7 @@
|
|||
:optimizations :none}
|
||||
:figwheel true}
|
||||
{:id :android
|
||||
:source-paths ["react-native/src" "src" "env/dev"]
|
||||
:source-paths ["react-native/src/cljsjs" "react-native/src/mobile" "src" "env/dev"]
|
||||
:compiler {:output-to "target/android/app.js"
|
||||
:main "env.android.main"
|
||||
:output-dir "target/android"
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
(ns env.desktop.main
|
||||
(:require [status-im.desktop.core :as core]))
|
||||
|
||||
(core/init)
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
var CLOSURE_UNCOMPILED_DEFINES = null;
|
||||
var debugEnabled = false;
|
||||
var debugEnabled = true;
|
||||
|
||||
var config = {
|
||||
basePath: "target/",
|
||||
|
@ -47,7 +47,7 @@ function formatCompileError(msg) {
|
|||
return errorStr;
|
||||
}
|
||||
|
||||
/* This is simply demonstrating that we can receive and react to
|
||||
/* This is simply demonstrating that we can receive and react to
|
||||
* arbitrary messages from Figwheel this will enable creating a nicer
|
||||
* feedback system in the Figwheel top level React component.
|
||||
*/
|
||||
|
@ -103,27 +103,35 @@ var isChrome = function () {
|
|||
return typeof importScripts === "function"
|
||||
};
|
||||
|
||||
function asyncImportScripts(url, success, error) {
|
||||
logDebug('(asyncImportScripts) Importing: ' + url);
|
||||
asyncImportChain =
|
||||
asyncImportChain
|
||||
.then(function (v) {return fetch(url);})
|
||||
.then(function (response) {
|
||||
if(response.ok)
|
||||
return response.text();
|
||||
throw new Error("Failed to Fetch: " + url + " - Perhaps your project was cleaned and you haven't recompiled?")
|
||||
})
|
||||
.then(function (responseText) {
|
||||
evaluate(responseText);
|
||||
fireEvalListenters(url);
|
||||
success();
|
||||
return true;
|
||||
})
|
||||
.catch(function (e) {
|
||||
console.error(e);
|
||||
error();
|
||||
return true;
|
||||
});
|
||||
async function getUrlText(url) {
|
||||
const text = await fetch(url).then(response => {
|
||||
if(!response.ok) {
|
||||
throw new Error("Failed to Fetch: " + url + " - Perhaps your project was cleaned and you haven't recompiled?");
|
||||
}
|
||||
return response.text()
|
||||
});
|
||||
return text;
|
||||
}
|
||||
|
||||
var ATTEMPTS_COUNT = 3;
|
||||
async function asyncImportScripts(url, success, error) {
|
||||
|
||||
var attempt = 0;
|
||||
var text = await getUrlText(url);
|
||||
|
||||
while(attempt < ATTEMPTS_COUNT && text.length === 0)
|
||||
{
|
||||
text = await getUrlText(url);
|
||||
++attempt;
|
||||
}
|
||||
|
||||
if(!text || 0 === text.length) {
|
||||
console.log("Can't fetch file: ", url)
|
||||
return;
|
||||
}
|
||||
evaluate(text);
|
||||
fireEvalListenters(url);
|
||||
success();
|
||||
}
|
||||
|
||||
function syncImportScripts(url, success, error) {
|
||||
|
@ -147,7 +155,7 @@ function importJs(src, success, error) {
|
|||
if (isChrome()) {
|
||||
syncImportScripts(src, success, error);
|
||||
} else {
|
||||
asyncImportScripts(src, success, error);
|
||||
asyncImportChain = asyncImportChain.then(function (v) {return asyncImportScripts(src, success, error);})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,64 @@
|
|||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
find_package(Go REQUIRED)
|
||||
|
||||
set(REACT_NATIVE_DESKTOP_EXTERNAL_MODULES_TYPE_NAMES ${REACT_NATIVE_DESKTOP_EXTERNAL_MODULES_TYPE_NAMES}
|
||||
\"RCTStatus\" PARENT_SCOPE)
|
||||
|
||||
set(REACT_NATIVE_DESKTOP_EXTERNAL_MODULES_SRC ${REACT_NATIVE_DESKTOP_EXTERNAL_MODULES_SRC}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rctstatus.cpp PARENT_SCOPE)
|
||||
|
||||
include(${CMAKE_ROOT}/Modules/ExternalProject.cmake)
|
||||
|
||||
if (WIN32 AND NOT CUSTOM_STATUSGO_BUILD_DIR_PATH)
|
||||
set(CUSTOM_STATUSGO_BUILD_DIR_PATH "C:/srd-build/StatusGo")
|
||||
endif()
|
||||
if (CUSTOM_STATUSGO_BUILD_DIR_PATH)
|
||||
set(StatusGo_ROOT ${CUSTOM_STATUSGO_BUILD_DIR_PATH})
|
||||
else()
|
||||
set(StatusGo_ROOT "${CMAKE_CURRENT_BINARY_DIR}/StatusGo")
|
||||
endif()
|
||||
set(StatusGo_PREFIX "${StatusGo_ROOT}/src/github.com/status-im")
|
||||
set(StatusGo_SOURCE_DIR "${StatusGo_PREFIX}/status-go")
|
||||
set(StatusGo_INCLUDE_DIR "${StatusGo_SOURCE_DIR}/build/bin")
|
||||
set(StatusGo_STATIC_LIB
|
||||
"${StatusGo_SOURCE_DIR}/build/bin/${CMAKE_STATIC_LIBRARY_PREFIX}status${CMAKE_STATIC_LIBRARY_SUFFIX}")
|
||||
|
||||
include_directories(${StatusGo_INCLUDE_DIR})
|
||||
|
||||
if (WIN32)
|
||||
set(CONFIGURE_SCRIPT build-status-go.bat)
|
||||
else()
|
||||
set(CONFIGURE_SCRIPT build-status-go.sh)
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(StatusGo_ep
|
||||
PREFIX ${StatusGo_PREFIX}
|
||||
SOURCE_DIR ${StatusGo_SOURCE_DIR}
|
||||
GIT_REPOSITORY https://github.com/status-im/status-go.git
|
||||
GIT_TAG origin/develop
|
||||
BUILD_BYPRODUCTS ${StatusGo_STATIC_LIB}
|
||||
CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/${CONFIGURE_SCRIPT} ${GO_ROOT_PATH} ${StatusGo_ROOT} ${StatusGo_SOURCE_DIR}
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
)
|
||||
|
||||
set(REACT_NATIVE_DESKTOP_EXTERNAL_PROJECT_DEPS ${REACT_NATIVE_DESKTOP_EXTERNAL_PROJECT_DEPS} StatusGo_ep PARENT_SCOPE)
|
||||
|
||||
if (APPLE)
|
||||
set(STATUSGO_DEPS_LIBS "-framework Foundation"
|
||||
"-framework CoreServices"
|
||||
"-framework IOKit"
|
||||
"-framework Security" pthread)
|
||||
elseif (WIN32)
|
||||
set(STATUSGO_DEPS_LIBS -lWinMM -lWS2_32 -lsetupapi)
|
||||
else()
|
||||
set(STATUSGO_DEPS_LIBS pthread)
|
||||
endif()
|
||||
|
||||
set(REACT_NATIVE_DESKTOP_EXTERNAL_MODULES_LIBS ${REACT_NATIVE_DESKTOP_EXTERNAL_MODULES_LIBS}
|
||||
${StatusGo_STATIC_LIB} ${STATUSGO_DEPS_LIBS} PARENT_SCOPE)
|
||||
|
||||
set(REACT_NATIVE_DESKTOP_EXTERNAL_MODULES_INCLUDE_DIRS ${REACT_NATIVE_DESKTOP_EXTERNAL_MODULES_INCLUDE_DIRS}
|
||||
${StatusGo_INCLUDE_DIR} PARENT_SCOPE)
|
|
@ -0,0 +1,35 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# The module defines the following variables:
|
||||
# GO_FOUND - true if the Go was found
|
||||
# GO_EXECUTABLE - path to the executable
|
||||
# GO_VERSION - Go version number
|
||||
# GO_PLATFORM - i.e. linux
|
||||
# GO_ARCH - i.e. amd64
|
||||
# Example usage:
|
||||
# find_package(Go 1.2 REQUIRED)
|
||||
|
||||
|
||||
find_program(GO_EXECUTABLE go PATHS ENV GOROOT GOPATH GOBIN PATH_SUFFIXES bin)
|
||||
if (GO_EXECUTABLE)
|
||||
get_filename_component(GO_ROOT_PATH ${GO_EXECUTABLE} REALPATH)
|
||||
get_filename_component(GO_ROOT_PATH ${GO_ROOT_PATH}/../.. REALPATH)
|
||||
message(STATUS "GO_ROOT_PATH is set to: ${GO_ROOT_PATH}")
|
||||
execute_process(COMMAND ${GO_EXECUTABLE} version OUTPUT_VARIABLE GO_VERSION_OUTPUT OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(GO_VERSION_OUTPUT MATCHES "go([0-9]+\\.[0-9]+\\.?[0-9]*)[a-zA-Z0-9]* ([^/]+)/(.*)")
|
||||
set(GO_VERSION ${CMAKE_MATCH_1})
|
||||
set(GO_PLATFORM ${CMAKE_MATCH_2})
|
||||
set(GO_ARCH ${CMAKE_MATCH_3})
|
||||
elseif(GO_VERSION_OUTPUT MATCHES "go version devel .* ([^/]+)/(.*)$")
|
||||
set(GO_VERSION "99-devel")
|
||||
set(GO_PLATFORM ${CMAKE_MATCH_1})
|
||||
set(GO_ARCH ${CMAKE_MATCH_2})
|
||||
message("WARNING: Development version of Go being used, can't determine compatibility.")
|
||||
endif()
|
||||
endif()
|
||||
mark_as_advanced(GO_EXECUTABLE)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Go REQUIRED_VARS GO_EXECUTABLE GO_VERSION GO_PLATFORM GO_ARCH VERSION_VAR GO_VERSION)
|
|
@ -0,0 +1,8 @@
|
|||
set GOROOT=%1
|
||||
set GOPATH=%2
|
||||
set PATH=%GOROOT%/bin;%GOROOT%;%GOPATH%;%PATH%
|
||||
|
||||
cd %3/lib
|
||||
go get .
|
||||
cd ..
|
||||
mingw32-make statusgo-library
|
|
@ -0,0 +1,10 @@
|
|||
#!/bin/bash
|
||||
|
||||
export GOROOT=$1
|
||||
export GOPATH=$2
|
||||
export PATH=$GOROOT/bin:$GOROOT:$GOPATH:$PATH
|
||||
|
||||
cd $3/lib
|
||||
go get ./
|
||||
cd ..
|
||||
make statusgo-library
|
|
@ -0,0 +1,286 @@
|
|||
/**
|
||||
* Copyright (c) 2017-present, Status Research and Development GmbH.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "rctstatus.h"
|
||||
#include "bridge.h"
|
||||
#include "eventdispatcher.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QJsonDocument>
|
||||
#include <QByteArray>
|
||||
#include <QVariantMap>
|
||||
#include <QDir>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include "libstatus.h"
|
||||
|
||||
namespace {
|
||||
struct RegisterQMLMetaType {
|
||||
RegisterQMLMetaType() {
|
||||
qRegisterMetaType<RCTStatus*>();
|
||||
}
|
||||
} registerMetaType;
|
||||
} // namespace
|
||||
|
||||
class RCTStatusPrivate {
|
||||
public:
|
||||
static Bridge* bridge;
|
||||
static RCTStatus* rctStatus;
|
||||
};
|
||||
|
||||
Bridge* RCTStatusPrivate::bridge = nullptr;
|
||||
RCTStatus* RCTStatusPrivate::rctStatus = nullptr;
|
||||
|
||||
RCTStatus::RCTStatus(QObject* parent) : QObject(parent), d_ptr(new RCTStatusPrivate) {
|
||||
RCTStatusPrivate::rctStatus = this;
|
||||
SetSignalEventCallback((void*)&RCTStatus::jailSignalEventCallback);
|
||||
connect(this, &RCTStatus::jailSignalEvent, this, &RCTStatus::onJailSignalEvent);
|
||||
}
|
||||
|
||||
RCTStatus::~RCTStatus() {}
|
||||
|
||||
void RCTStatus::setBridge(Bridge* bridge) {
|
||||
Q_D(RCTStatus);
|
||||
d->bridge = bridge;
|
||||
}
|
||||
|
||||
QString RCTStatus::moduleName() {
|
||||
return "Status";
|
||||
}
|
||||
|
||||
QList<ModuleMethod*> RCTStatus::methodsToExport() {
|
||||
return QList<ModuleMethod*>{};
|
||||
}
|
||||
|
||||
QVariantMap RCTStatus::constantsToExport() {
|
||||
return QVariantMap();
|
||||
}
|
||||
|
||||
void RCTStatus::initJail(QString js, double callbackId) {
|
||||
Q_D(RCTStatus);
|
||||
qDebug() << "call of RCTStatus::initJail with param js:" << " and callback id: " << callbackId;
|
||||
|
||||
InitJail(js.toUtf8().data());
|
||||
|
||||
d->bridge->invokePromiseCallback(callbackId, QVariantList{ "{\"result\":\"\"}" });
|
||||
}
|
||||
|
||||
|
||||
void RCTStatus::parseJail(QString chatId, QString js, double callbackId) {
|
||||
Q_D(RCTStatus);
|
||||
qDebug() << "call of RCTStatus::parseJail with param chatId: " << chatId << " js:" << " and callback id: " << callbackId;
|
||||
|
||||
const char* result = Parse(chatId.toUtf8().data(), js.toUtf8().data());
|
||||
qDebug() << "RCTStatus::parseJail parseJail result: " << result;
|
||||
d->bridge->invokePromiseCallback(callbackId, QVariantList{result});
|
||||
}
|
||||
|
||||
|
||||
void RCTStatus::callJail(QString chatId, QString path, QString params, double callbackId) {
|
||||
Q_D(RCTStatus);
|
||||
qDebug() << "call of RCTStatus::callJail with param chatId: " << chatId << " path: " << path << " params: " << params << " and callback id: " << callbackId;
|
||||
|
||||
const char* result = Call(chatId.toUtf8().data(), path.toUtf8().data(), params.toUtf8().data());
|
||||
qDebug() << "RCTStatus::callJail callJail result: " << result;
|
||||
d->bridge->invokePromiseCallback(callbackId, QVariantList{result});
|
||||
}
|
||||
|
||||
void RCTStatus::getDeviceUUID(double callbackId) {
|
||||
Q_D(RCTStatus);
|
||||
qDebug() << "call of RCTStatus::getDeviceUUID";
|
||||
|
||||
d->bridge->invokePromiseCallback(callbackId, QVariantList{"com.status.StatusIm"});
|
||||
}
|
||||
|
||||
|
||||
void RCTStatus::startNode(QString configString) {
|
||||
Q_D(RCTStatus);
|
||||
qDebug() << "call of RCTStatus::startNode with param configString:" << configString;
|
||||
|
||||
QJsonParseError jsonError;
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(configString.toUtf8(), &jsonError);
|
||||
if (jsonError.error != QJsonParseError::NoError){
|
||||
qDebug() << jsonError.errorString();
|
||||
}
|
||||
|
||||
qDebug() << " RCTStatus::startNode configString: " << jsonDoc.toVariant().toMap();
|
||||
QVariantMap configJSON = jsonDoc.toVariant().toMap();
|
||||
|
||||
QString newKeystoreUrl = "keystore";
|
||||
|
||||
int networkId = configJSON["NetworkId"].toInt();
|
||||
QString dataDir = configJSON["DataDir"].toString();
|
||||
|
||||
QString networkDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/" + dataDir;
|
||||
QDir dir(networkDir);
|
||||
if (!dir.exists()) {
|
||||
dir.mkpath(".");
|
||||
}
|
||||
qDebug()<<"RCTStatus::startNode networkDir: "<<networkDir;
|
||||
|
||||
|
||||
char *configChars = GenerateConfig(networkDir.toUtf8().data(), networkId);
|
||||
qDebug() << "RCTStatus::startNode GenerateConfig result: " << configChars;
|
||||
|
||||
jsonDoc = QJsonDocument::fromJson(QString(configChars).toUtf8(), &jsonError);
|
||||
if (jsonError.error != QJsonParseError::NoError){
|
||||
qDebug() << jsonError.errorString();
|
||||
}
|
||||
|
||||
qDebug() << " RCTStatus::startNode GenerateConfig configString: " << jsonDoc.toVariant().toMap();
|
||||
QVariantMap generatedConfig = jsonDoc.toVariant().toMap();
|
||||
generatedConfig["KeyStoreDir"] = newKeystoreUrl;
|
||||
generatedConfig["LogEnabled"] = true;
|
||||
generatedConfig["LogFile"] = networkDir + "/geth.log";
|
||||
//generatedConfig["LogLevel"] = "DEBUG";
|
||||
|
||||
const char* result = StartNode(QString(QJsonDocument::fromVariant(generatedConfig).toJson(QJsonDocument::Compact)).toUtf8().data());
|
||||
qDebug() << "RCTStatus::startNode StartNode result: " << result;
|
||||
}
|
||||
|
||||
|
||||
void RCTStatus::shouldMoveToInternalStorage(double callbackId) {
|
||||
Q_D(RCTStatus);
|
||||
qDebug() << "call of RCTStatus::shouldMoveToInternalStorage with param callbackId: " << callbackId;
|
||||
d->bridge->invokePromiseCallback(callbackId, QVariantList{});
|
||||
}
|
||||
|
||||
|
||||
void RCTStatus::moveToInternalStorage(double callbackId) {
|
||||
Q_D(RCTStatus);
|
||||
qDebug() << "call of RCTStatus::moveToInternalStorage with param callbackId: " << callbackId;
|
||||
d->bridge->invokePromiseCallback(callbackId, QVariantList{ "{\"result\":\"\"}" });
|
||||
}
|
||||
|
||||
|
||||
void RCTStatus::stopNode() {
|
||||
qDebug() << "call of RCTStatus::stopNode";
|
||||
const char* result = StopNode();
|
||||
qDebug() << "RCTStatus::stopNode StopNode result: " << result;
|
||||
}
|
||||
|
||||
|
||||
void RCTStatus::createAccount(QString password, double callbackId) {
|
||||
Q_D(RCTStatus);
|
||||
qDebug() << "call of RCTStatus::createAccount with param callbackId: " << callbackId;
|
||||
const char* result = CreateAccount(password.toUtf8().data());
|
||||
qDebug() << "RCTStatus::createAccount CreateAccount result: " << result;
|
||||
d->bridge->invokePromiseCallback(callbackId, QVariantList{result});
|
||||
}
|
||||
|
||||
|
||||
void RCTStatus::notifyUsers(QString token, QString payloadJSON, QString tokensJSON, double callbackId) {
|
||||
Q_D(RCTStatus);
|
||||
qDebug() << "call of RCTStatus::notifyUsers with param callbackId: " << callbackId;
|
||||
const char* result = NotifyUsers(token.toUtf8().data(), payloadJSON.toUtf8().data(), tokensJSON.toUtf8().data());
|
||||
qDebug() << "RCTStatus::notifyUsers Notify result: " << result;
|
||||
d->bridge->invokePromiseCallback(callbackId, QVariantList{result});
|
||||
}
|
||||
|
||||
|
||||
void RCTStatus::addPeer(QString enode, double callbackId) {
|
||||
Q_D(RCTStatus);
|
||||
qDebug() << "call of RCTStatus::addPeer with param callbackId: " << callbackId;
|
||||
const char* result = AddPeer(enode.toUtf8().data());
|
||||
qDebug() << "RCTStatus::addPeer AddPeer result: " << result;
|
||||
d->bridge->invokePromiseCallback(callbackId, QVariantList{result});
|
||||
}
|
||||
|
||||
|
||||
void RCTStatus::recoverAccount(QString passphrase, QString password, double callbackId) {
|
||||
Q_D(RCTStatus);
|
||||
qDebug() << "call of RCTStatus::recoverAccount with param callbackId: " << callbackId;
|
||||
const char* result = RecoverAccount(password.toUtf8().data(), passphrase.toUtf8().data());
|
||||
qDebug() << "RCTStatus::recoverAccount RecoverAccount result: " << result;
|
||||
d->bridge->invokePromiseCallback(callbackId, QVariantList{result});
|
||||
}
|
||||
|
||||
|
||||
void RCTStatus::login(QString address, QString password, double callbackId) {
|
||||
Q_D(RCTStatus);
|
||||
qDebug() << "call of RCTStatus::login with param callbackId: " << callbackId;
|
||||
const char* result = Login(address.toUtf8().data(), password.toUtf8().data());
|
||||
qDebug() << "RCTStatus::login Login result: " << result;
|
||||
d->bridge->invokePromiseCallback(callbackId, QVariantList{result});
|
||||
}
|
||||
|
||||
|
||||
void RCTStatus::approveSignRequests(QString hashes, QString password, double callbackId) {
|
||||
Q_D(RCTStatus);
|
||||
qDebug() << "call of RCTStatus::approveSignRequests with param callbackId: " << callbackId;
|
||||
const char* result = ApproveSignRequests(hashes.toUtf8().data(), password.toUtf8().data());
|
||||
qDebug() << "RCTStatus::approveSignRequests CompleteTransactions result: " << result;
|
||||
d->bridge->invokePromiseCallback(callbackId, QVariantList{result});
|
||||
}
|
||||
|
||||
void RCTStatus::discardSignRequest(QString id) {
|
||||
qDebug() << "call of RCTStatus::discardSignRequest with id: " << id;
|
||||
DiscardSignRequest(id.toUtf8().data());
|
||||
}
|
||||
|
||||
void RCTStatus::setAdjustResize() {
|
||||
}
|
||||
|
||||
|
||||
void RCTStatus::setAdjustPan() {
|
||||
}
|
||||
|
||||
|
||||
void RCTStatus::setSoftInputMode(int i) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RCTStatus::clearCookies() {
|
||||
}
|
||||
|
||||
|
||||
void RCTStatus::clearStorageAPIs() {
|
||||
}
|
||||
|
||||
|
||||
void RCTStatus::sendWeb3Request(QString payload, double callbackId) {
|
||||
Q_D(RCTStatus);
|
||||
qDebug() << "call of RCTStatus::sendWeb3Request with param callbackId: " << callbackId;
|
||||
const char* result = CallRPC(payload.toUtf8().data());
|
||||
qDebug() << "RCTStatus::sendWeb3Request CallRPC result: " << result;
|
||||
d->bridge->invokePromiseCallback(callbackId, QVariantList{result});
|
||||
}
|
||||
|
||||
void RCTStatus::sendWeb3PrivateRequest(QString payload, double callbackId) {
|
||||
Q_D(RCTStatus);
|
||||
qDebug() << "call of RCTStatus::sendWeb3PrivateRequest with param callbackId: " << callbackId;
|
||||
const char* result = CallPrivateRPC(payload.toUtf8().data());
|
||||
qDebug() << "RCTStatus::sendWeb3PrivateRequest CallPrivateRPC result: " << result;
|
||||
d->bridge->invokePromiseCallback(callbackId, QVariantList{result});
|
||||
}
|
||||
|
||||
void RCTStatus::closeApplication() {
|
||||
}
|
||||
|
||||
bool RCTStatus::JSCEnabled() {
|
||||
qDebug() << "call of RCTStatus::JSCEnabled";
|
||||
return false;
|
||||
}
|
||||
|
||||
void RCTStatus::jailSignalEventCallback(const char* signal) {
|
||||
qDebug() << "call of RCTStatus::jailSignalEventCallback ... signal: " << signal;
|
||||
RCTStatusPrivate::rctStatus->emitSignalEvent(signal);
|
||||
}
|
||||
|
||||
void RCTStatus::emitSignalEvent(const char* signal) {
|
||||
qDebug() << "call of RCTStatus::emitSignalEvent ... signal: " << signal;
|
||||
Q_EMIT jailSignalEvent(signal);
|
||||
}
|
||||
|
||||
void RCTStatus::onJailSignalEvent(const char* signal) {
|
||||
qDebug() << "call of RCTStatus::onJailSignalEvent ... signal: " << signal;
|
||||
RCTStatusPrivate::bridge->eventDispatcher()->sendDeviceEvent("gethEvent", QVariantMap{{"jsonEvent", signal}});
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/**
|
||||
* Copyright (c) 2017-present, Status Research and Development GmbH.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef RCTSTATUS_H
|
||||
#define RCTSTATUS_H
|
||||
|
||||
#include "moduleinterface.h"
|
||||
|
||||
#include <QVariantMap>
|
||||
|
||||
class RCTStatusPrivate;
|
||||
class RCTStatus : public QObject, public ModuleInterface {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(ModuleInterface)
|
||||
|
||||
Q_DECLARE_PRIVATE(RCTStatus)
|
||||
|
||||
public:
|
||||
Q_INVOKABLE RCTStatus(QObject* parent = 0);
|
||||
~RCTStatus();
|
||||
|
||||
void setBridge(Bridge* bridge) override;
|
||||
|
||||
QString moduleName() override;
|
||||
QList<ModuleMethod*> methodsToExport() override;
|
||||
QVariantMap constantsToExport() override;
|
||||
|
||||
Q_INVOKABLE void initJail(QString js, double callbackId);
|
||||
Q_INVOKABLE void parseJail(QString chatId, QString js, double callbackId);
|
||||
Q_INVOKABLE void callJail(QString chatId, QString path, QString params, double callbackId);
|
||||
Q_INVOKABLE void startNode(QString configString);
|
||||
Q_INVOKABLE void shouldMoveToInternalStorage(double callbackId);
|
||||
Q_INVOKABLE void moveToInternalStorage(double callbackId);
|
||||
Q_INVOKABLE void stopNode();
|
||||
Q_INVOKABLE void createAccount(QString password, double callbackId);
|
||||
Q_INVOKABLE void notifyUsers(QString token, QString payloadJSON, QString tokensJSON, double callbackId);
|
||||
Q_INVOKABLE void addPeer(QString enode, double callbackId);
|
||||
Q_INVOKABLE void recoverAccount(QString passphrase, QString password, double callbackId);
|
||||
Q_INVOKABLE void login(QString address, QString password, double callbackId);
|
||||
Q_INVOKABLE void approveSignRequests(QString hashes, QString password, double callbackId);
|
||||
Q_INVOKABLE void discardSignRequest(QString id);
|
||||
|
||||
Q_INVOKABLE void setAdjustResize();
|
||||
Q_INVOKABLE void setAdjustPan();
|
||||
Q_INVOKABLE void setSoftInputMode(int i);
|
||||
|
||||
Q_INVOKABLE void clearCookies();
|
||||
Q_INVOKABLE void clearStorageAPIs();
|
||||
Q_INVOKABLE void sendWeb3Request(QString payload, double callbackId);
|
||||
Q_INVOKABLE void sendWeb3PrivateRequest(QString payload, double callbackId);
|
||||
Q_INVOKABLE void closeApplication();
|
||||
Q_INVOKABLE void getDeviceUUID(double callbackId);
|
||||
|
||||
Q_INVOKABLE static bool JSCEnabled();
|
||||
Q_INVOKABLE static void jailSignalEventCallback(const char* signal);
|
||||
|
||||
void emitSignalEvent(const char* signal);
|
||||
|
||||
Q_SIGNALS:
|
||||
void jailSignalEvent(const char* signal);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onJailSignalEvent(const char* signal);
|
||||
|
||||
private:
|
||||
QScopedPointer<RCTStatusPrivate> d_ptr;
|
||||
};
|
||||
|
||||
#endif // RCTSTATUS_H
|
|
@ -0,0 +1,23 @@
|
|||
patch-package
|
||||
--- a/node_modules/metro/src/JSTransformer/index.js
|
||||
+++ b/node_modules/metro/src/JSTransformer/index.js
|
||||
@@ -151,6 +151,8 @@ module.exports = class Transformer {
|
||||
/^--heap[_-]growing[_-]percent=[0-9]+$/.test(arg) ||
|
||||
/^--max[_-]old[_-]space[_-]size=[0-9]+$/.test(arg));
|
||||
|
||||
+ execArgv.push("--max-old-space-size=8192");
|
||||
+
|
||||
const env = _extends({},
|
||||
process.env, {
|
||||
// Force color to print syntax highlighted code frames.
|
||||
--- a/node_modules/metro/src/defaults.js
|
||||
+++ b/node_modules/metro/src/defaults.js
|
||||
@@ -45,7 +45,7 @@ exports.sourceExts = ['js', 'json'];
|
||||
|
||||
exports.moduleSystem = require.resolve('./lib/polyfills/require.js');
|
||||
|
||||
-exports.platforms = ['ios', 'android', 'windows', 'web'];
|
||||
+exports.platforms = ['ios', 'android', 'windows', 'web', 'desktop'];
|
||||
|
||||
exports.providesModuleNodeModules = ['react-native', 'react-native-windows'];
|
||||
|
31
project.clj
31
project.clj
|
@ -22,13 +22,17 @@
|
|||
:aliases {"prod-build" ^{:doc "Recompile code with prod profile."}
|
||||
["do" "clean"
|
||||
["with-profile" "prod" "cljsbuild" "once" "ios"]
|
||||
["with-profile" "prod" "cljsbuild" "once" "android"]]
|
||||
["with-profile" "prod" "cljsbuild" "once" "android"]
|
||||
["with-profile" "prod" "cljsbuild" "once" "desktop"]]
|
||||
"prod-build-android" ^{:doc "Recompile code for Android with prod profile."}
|
||||
["do" "clean"
|
||||
["with-profile" "prod" "cljsbuild" "once" "android"]]
|
||||
"prod-build-ios" ^{:doc "Recompile code for iOS with prod profile."}
|
||||
["do" "clean"
|
||||
["with-profile" "prod" "cljsbuild" "once" "ios"]]
|
||||
"prod-build-desktop" ^{:doc "Recompile code for desktop with prod profile."}
|
||||
["do" "clean"
|
||||
["with-profile" "prod" "cljsbuild" "once" "desktop"]]
|
||||
"figwheel-repl" ["with-profile" "+figwheel" "run" "-m" "clojure.main" "env/dev/run.clj"]
|
||||
"test-cljs" ["with-profile" "test" "doo" "node" "test" "once"]
|
||||
"test-protocol" ["with-profile" "test" "doo" "node" "protocol" "once"]
|
||||
|
@ -36,20 +40,20 @@
|
|||
:profiles {:dev {:dependencies [[com.cemerick/piggieback "0.2.2"]]
|
||||
:cljsbuild {:builds
|
||||
{:ios
|
||||
{:source-paths ["components/src" "react-native/src" "src"]
|
||||
{:source-paths ["components/src" "react-native/src/cljsjs" "react-native/src/mobile" "src"]
|
||||
:compiler {:output-to "target/ios/app.js"
|
||||
:main "env.ios.main"
|
||||
:output-dir "target/ios"
|
||||
:optimizations :none}}
|
||||
:android
|
||||
{:source-paths ["components/src" "react-native/src" "src"]
|
||||
{:source-paths ["components/src" "react-native/src/cljsjs" "react-native/src/mobile" "src"]
|
||||
:compiler {:output-to "target/android/app.js"
|
||||
:main "env.android.main"
|
||||
:output-dir "target/android"
|
||||
:optimizations :none}
|
||||
:warning-handlers [status-im.utils.build/warning-handler]}
|
||||
:desktop
|
||||
{:source-paths ["components/src" "react-native/src" "src"]
|
||||
{:source-paths ["components/src" "react-native/src/cljsjs" "react-native/src/desktop" "src"]
|
||||
:compiler {:output-to "target/desktop/app.js"
|
||||
:main "env.desktop.main"
|
||||
:output-dir "target/desktop"
|
||||
|
@ -62,7 +66,7 @@
|
|||
[re-frisk-sidecar "0.5.7"]
|
||||
[day8.re-frame/tracing "0.5.0"]
|
||||
[hawk "0.2.11"]]
|
||||
:source-paths ["src" "env/dev" "react-native/src" "components/src"]}]
|
||||
:source-paths ["src" "env/dev" "react-native/src/cljsjs" "components/src"]}]
|
||||
:test {:dependencies [[day8.re-frame/test "0.1.5"]]
|
||||
:plugins [[lein-doo "0.1.9"]]
|
||||
:cljsbuild {:builds
|
||||
|
@ -91,7 +95,7 @@
|
|||
:target :nodejs}}]}}
|
||||
:prod {:cljsbuild {:builds
|
||||
{:ios
|
||||
{:source-paths ["components/src" "react-native/src" "src" "env/prod"]
|
||||
{:source-paths ["components/src" "react-native/src/cljsjs" "react-native/src/mobile" "src" "env/prod"]
|
||||
:compiler {:output-to "index.ios.js"
|
||||
:main "env.ios.main"
|
||||
:output-dir "target/ios-prod"
|
||||
|
@ -104,7 +108,7 @@
|
|||
:language-in :ecmascript5}
|
||||
:warning-handlers [status-im.utils.build/warning-handler]}
|
||||
:android
|
||||
{:source-paths ["components/src" "react-native/src" "src" "env/prod"]
|
||||
{:source-paths ["components/src" "react-native/src/cljsjs" "react-native/src/mobile" "src" "env/prod"]
|
||||
:compiler {:output-to "index.android.js"
|
||||
:main "env.android.main"
|
||||
:output-dir "target/android-prod"
|
||||
|
@ -115,4 +119,17 @@
|
|||
:parallel-build false
|
||||
:elide-asserts true
|
||||
:language-in :ecmascript5}
|
||||
:warning-handlers [status-im.utils.build/warning-handler]}
|
||||
:desktop
|
||||
{:source-paths ["components/src" "react-native/src/cljsjs" "react-native/src/desktop" "src" "env/prod"]
|
||||
:compiler {:output-to "index.desktop.js"
|
||||
:main "env.desktop.main"
|
||||
:output-dir "target/desktop-prod"
|
||||
:static-fns true
|
||||
:optimize-constants true
|
||||
:optimizations :simple
|
||||
:closure-defines {"goog.DEBUG" false}
|
||||
:parallel-build false
|
||||
:elide-asserts true
|
||||
:language-in :ecmascript5}
|
||||
:warning-handlers [status-im.utils.build/warning-handler]}}}}})
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
(ns status-im.react-native.js-dependencies)
|
||||
|
||||
(def config (js/require "react-native-config"))
|
||||
(def fs (js/require "react-native-fs"))
|
||||
(def http-bridge (js/require "react-native-http-bridge"))
|
||||
(def keychain (js/require "react-native-keychain"))
|
||||
(def qr-code (js/require "react-native-qrcode"))
|
||||
(def react-native (js/require "react-native"))
|
||||
(def realm (js/require "realm"))
|
||||
(def webview-bridge (js/require "react-native-webview-bridge"))
|
||||
(def secure-random (.-generateSecureRandom (js/require "react-native-securerandom")))
|
||||
(def EventEmmiter (js/require "react-native/Libraries/vendor/emitter/EventEmitter"))
|
||||
(def fetch (.-default (js/require "react-native-fetch-polyfill")))
|
||||
(def i18n (js/require "react-native-i18n"))
|
||||
(def camera #js {:constants {:Aspect "Portrait"}})
|
||||
(def dialogs #js {})
|
||||
(def dismiss-keyboard #js {})
|
||||
(def image-crop-picker #js {})
|
||||
(def image-resizer #js {})
|
||||
(def instabug #js {:IBGLog ( fn [])})
|
||||
(def nfc #js {})
|
||||
(def svg #js {})
|
||||
(def react-native-fcm #js {:default #js {:getFCMToken (fn [])
|
||||
:requestPermissions (fn [])}})
|
||||
(def snoopy #js {})
|
||||
(def snoopy-filter #js {})
|
||||
(def snoopy-bars #js {})
|
||||
(def snoopy-buffer #js {})
|
||||
(def background-timer #js {:setTimeout (fn [])})
|
||||
(def testfairy #js {})
|
||||
|
|
@ -1,31 +1,29 @@
|
|||
(ns status-im.react-native.js-dependencies)
|
||||
|
||||
(def camera (js/require "react-native-camera"))
|
||||
(def config (js/require "react-native-config"))
|
||||
(def dialogs (js/require "react-native-dialogs"))
|
||||
(def dismiss-keyboard (js/require "dismissKeyboard"))
|
||||
(def fs (js/require "react-native-fs"))
|
||||
(def http-bridge (js/require "react-native-http-bridge"))
|
||||
;; i18n is now exported in default object of the module
|
||||
;; https://github.com/AlexanderZaytsev/react-native-i18n/blob/master/index.js
|
||||
(def i18n (.-default (js/require "react-native-i18n")))
|
||||
(def image-crop-picker (js/require "react-native-image-crop-picker"))
|
||||
(def image-resizer (js/require "react-native-image-resizer"))
|
||||
(def instabug (js/require "instabug-reactnative"))
|
||||
(def keychain (js/require "react-native-keychain"))
|
||||
(def nfc (js/require "nfc-react-native"))
|
||||
(def qr-code (js/require "react-native-qrcode"))
|
||||
(def react-native (js/require "react-native"))
|
||||
(def realm (js/require "realm"))
|
||||
(def webview-bridge (js/require "react-native-webview-bridge"))
|
||||
(def secure-random (.-generateSecureRandom (js/require "react-native-securerandom")))
|
||||
(def EventEmmiter (js/require "react-native/Libraries/vendor/emitter/EventEmitter"))
|
||||
(def fetch (.-default (js/require "react-native-fetch-polyfill")))
|
||||
(def i18n (.-default (js/require "react-native-i18n")))
|
||||
(def camera (js/require "react-native-camera"))
|
||||
(def dialogs (js/require "react-native-dialogs"))
|
||||
(def dismiss-keyboard (js/require "dismissKeyboard"))
|
||||
(def image-crop-picker (js/require "react-native-image-crop-picker"))
|
||||
(def image-resizer (js/require "react-native-image-resizer"))
|
||||
(def instabug (js/require "instabug-reactnative"))
|
||||
(def nfc (js/require "nfc-react-native"))
|
||||
(def svg (js/require "react-native-svg"))
|
||||
(def react-native-fcm (js/require "react-native-fcm"))
|
||||
(def secure-random (.-generateSecureRandom (js/require "react-native-securerandom")))
|
||||
(def snoopy (js/require "rn-snoopy"))
|
||||
(def snoopy-filter (js/require "rn-snoopy/stream/filter"))
|
||||
(def snoopy-bars (js/require "rn-snoopy/stream/bars"))
|
||||
(def snoopy-buffer (js/require "rn-snoopy/stream/buffer"))
|
||||
(def EventEmmiter (js/require "react-native/Libraries/vendor/emitter/EventEmitter"))
|
||||
(def background-timer (.-default (js/require "react-native-background-timer")))
|
||||
(def fetch (.-default (js/require "react-native-fetch-polyfill")))
|
||||
(def testfairy (js/require "react-native-testfairy"))
|
|
@ -0,0 +1,89 @@
|
|||
#!/bin/bash
|
||||
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"
|
||||
STATUSREACTPATH="$SCRIPTPATH/.."
|
||||
WORKFOLDER="$SCRIPTPATH/../mac_bundle"
|
||||
MACDEPLOYQT=""
|
||||
|
||||
#if no arguments passed, inform user about possible ones (one for making script interactive, one for path to macdeployqt)
|
||||
|
||||
if [ $# -eq 0 ]
|
||||
then
|
||||
echo -e "${RED}You need to specify path to macdeployqt binary as an argument${NC}"
|
||||
echo "Example: scripts/create-desktop-mac-bundle.sh /usr/bin/macdeployqt"
|
||||
exit 1
|
||||
else
|
||||
MACDEPLOYQT=$1
|
||||
fi
|
||||
|
||||
# check if gdrive installed
|
||||
command -v gdrive >/dev/null 2>&1 || { echo -e "${RED}gdrive tool need to be installed. (brew install gdrive). Aborting.${NC}" >&2; exit 1; }
|
||||
|
||||
|
||||
# inform user that define should be changed in "desktop/main.cpp"
|
||||
echo ""
|
||||
echo -e "${YELLOW}In desktop/main.cpp file please uncomment #define BULID_FOR_BUNDLE line.${NC}"
|
||||
read -p "When ready, plese press enter to continue"
|
||||
echo ""
|
||||
|
||||
|
||||
# create directory for all work related to bundling
|
||||
mkdir -p $WORKFOLDER
|
||||
echo -e "${GREEN}Work folder created: $WORKFOLDER${NC}"
|
||||
echo ""
|
||||
|
||||
# from index.desktop.js create javascript bundle and resources folder
|
||||
echo "Generating StatusIm.bundle and assets folder..."
|
||||
react-native bundle --entry-file index.desktop.js --bundle-output $WORKFOLDER/StatusIm.jsbundle --dev false --platform desktop --assets-dest $WORKFOLDER/assets
|
||||
echo -e "${GREEN}Generating done.${NC}"
|
||||
echo ""
|
||||
|
||||
# show path to javascript bundle and line that should be added to package.json
|
||||
echo -e "${YELLOW}Please add the following line to package.json:${NC}"
|
||||
echo "\"desktopJSBundlePath\": \"$WORKFOLDER/StatusIm.jsbundle\""
|
||||
echo ""
|
||||
read -p "When ready, plese press enter to continue"
|
||||
echo ""
|
||||
|
||||
|
||||
# build desktop app
|
||||
echo "Building StatusIm desktop..."
|
||||
react-native build-desktop
|
||||
echo -e "${GREEN}Building done.${NC}"
|
||||
echo ""
|
||||
|
||||
|
||||
# download prepared package with mac bundle files (it contains qt libraries, icon)
|
||||
echo "Downloading skeleton of mac bundle..."
|
||||
echo -e "${YELLOW}First time gdrive can ask you for permissions to google drive${NC}"
|
||||
gdrive download --path $WORKFOLDER 1fJbW9FzGGPvYkuJcSH5mCAcGdnyUeDSY
|
||||
echo -e "${GREEN}Downloading done.${NC}"
|
||||
echo ""
|
||||
|
||||
|
||||
# Unpacking downloaded archive
|
||||
echo "Unpacking bundle skeleton"
|
||||
unzip $WORKFOLDER/StatusIm.app.zip -d $WORKFOLDER
|
||||
chmod +x $WORKFOLDER/StatusIm.app/Contents/MacOs/ubuntu-server
|
||||
echo -e "${GREEN}Unzipping done.${NC}"
|
||||
echo ""
|
||||
|
||||
|
||||
# copy binary and resources to mac bundle
|
||||
echo "Copying resources and binary..."
|
||||
cp -r $WORKFOLDER/assets/share/assets $WORKFOLDER/StatusIm.app/Contents/MacOs
|
||||
cp $STATUSREACTPATH/desktop/bin/StatusIm $WORKFOLDER/StatusIm.app/Contents/MacOs
|
||||
echo -e "${GREEN}Copying done.${NC}"
|
||||
echo ""
|
||||
|
||||
|
||||
# invoke macdeployqt to create StatusIm.dmg
|
||||
echo "Creating bundle dmg..."
|
||||
$MACDEPLOYQT $WORKFOLDER/StatusIm.app -verbose=3 -qmldir="$STATUSREACTPATH/node_modules/react-native/ReactQt/application/src/" -qmldir="$STATUSREACTPATH/node_modules/react-native/ReactQt/runtime/src/qml/" -dmg
|
||||
echo -e "${GREEN}Bundle ready!${NC}"
|
||||
echo ""
|
|
@ -0,0 +1,8 @@
|
|||
#!/bin/bash
|
||||
|
||||
filename=$1
|
||||
#fileid="1yPTGcPe5DZd3ubzAgUBp3aAQRAOK9eKQ"
|
||||
fileid=$2
|
||||
rm -rf ./cookie
|
||||
curl -c ./cookie -s -L "https://drive.google.com/uc?export=download&id=${fileid}" > /dev/null
|
||||
curl -Lb ./cookie "https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=${fileid}" -o ${filename}
|
|
@ -0,0 +1,48 @@
|
|||
#!/bin/bash
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
PLATFORM=""
|
||||
PLATFORM_FOLDER=""
|
||||
|
||||
#if no arguments passed, inform user about possible ones
|
||||
|
||||
if [ $# -eq 0 ]
|
||||
then
|
||||
echo -e "${GREEN}This script should be invoked with platform argument: 'mobile' or 'desktop'${NC}"
|
||||
echo "When called it links"
|
||||
# echo "If invoked with 'mobile' argument it will make a copying: "
|
||||
# echo "package.json.mobile -> package.json"
|
||||
# echo "etc.."
|
||||
exit 1
|
||||
else
|
||||
PLATFORM=$1
|
||||
PLATFORM_FOLDER="${PLATFORM}_files"
|
||||
fi
|
||||
|
||||
|
||||
echo "Removing node_modules"
|
||||
rm -rf node_modules
|
||||
|
||||
echo "Creating link: package.json -> ${PLATFORM_FOLDER}/package.json "
|
||||
ln -sf ${PLATFORM_FOLDER}/package.json package.json
|
||||
|
||||
echo "Creating link: package-lock.json -> ${PLATFORM_FOLDER}/package-lock.json"
|
||||
ln -sf ${PLATFORM_FOLDER}/package-lock.json package-lock.json
|
||||
|
||||
echo "Creating link: VERSION -> ${PLATFORM_FOLDER}/VERSION"
|
||||
ln -sf ${PLATFORM_FOLDER}/VERSION VERSION
|
||||
|
||||
if [ "${PLATFORM}" == "mobile" ]
|
||||
then
|
||||
echo -e "Removing .re-natal symlink from root"
|
||||
rm -rf .re-natal
|
||||
else
|
||||
echo "Creating link: .re-natal -> ${PLATFORM_FOLDER}/.re-natal"
|
||||
ln -sf ${PLATFORM_FOLDER}/.re-natal .re-natal
|
||||
fi
|
||||
|
||||
|
||||
echo -e "${GREEN}Finished!${NC}"
|
|
@ -11,10 +11,7 @@
|
|||
|
||||
(defn app-root []
|
||||
(reagent/create-class
|
||||
{:component-will-mount
|
||||
(fn []
|
||||
(.hide react/splash-screen))
|
||||
:reagent-render views/main}))
|
||||
{:reagent-render views/main}))
|
||||
|
||||
(defn init []
|
||||
(core/init app-root))
|
||||
(core/init app-root))
|
|
@ -17,7 +17,7 @@
|
|||
;; if StatusModule is not initialized better to store
|
||||
;; calls and make them only when StatusModule is ready
|
||||
;; this flag helps to handle this
|
||||
(defonce module-initialized? (atom (or p/ios? js/goog.DEBUG)))
|
||||
(defonce module-initialized? (atom (or p/ios? js/goog.DEBUG p/desktop?)))
|
||||
|
||||
;; array of calls to StatusModule
|
||||
(defonce calls (atom []))
|
||||
|
|
|
@ -81,6 +81,7 @@
|
|||
:active-unknown "Unknown"
|
||||
:available "Available"
|
||||
:no-messages "No messages"
|
||||
:no-messages-yet "No messages yet"
|
||||
:suggestions-requests "Requests"
|
||||
:suggestions-commands "Commands"
|
||||
:faucet-success "Faucet request has been received"
|
||||
|
@ -187,6 +188,7 @@
|
|||
|
||||
;;sharing
|
||||
:sharing-copy-to-clipboard "Copy to clipboard"
|
||||
:sharing-copied-to-clipboard "Copied to clipboard"
|
||||
:sharing-share "Share..."
|
||||
:sharing-cancel "Cancel"
|
||||
|
||||
|
@ -220,6 +222,7 @@
|
|||
;;chats
|
||||
:new "New"
|
||||
:new-chat "New chat"
|
||||
:start-chat "Start chat"
|
||||
:start-new-chat "Start new chat"
|
||||
:start-group-chat "Start group chat"
|
||||
:invite-friends "Invite friends"
|
||||
|
@ -232,6 +235,7 @@
|
|||
:delete-group-chat-confirmation "Are you sure you want to delete this group chat?"
|
||||
:new-group-chat "New group chat"
|
||||
:new-public-group-chat "Join public chat"
|
||||
:selected-for-you "Selected for you"
|
||||
:public-chat "Public chat"
|
||||
:edit-chats "Edit chats"
|
||||
:search-chats "Search chats"
|
||||
|
@ -281,8 +285,10 @@
|
|||
:search-contacts "Search contacts"
|
||||
:contacts-group-new-chat "Start new chat"
|
||||
:choose-from-contacts "Choose from contacts"
|
||||
:or-choose-a-contact "Or choose a contact"
|
||||
:no-contacts "No contacts yet"
|
||||
:show-qr "Show QR code"
|
||||
:copy-qr "Copy code"
|
||||
:qr-code-public-key-hint "Share this code to \nstart chatting"
|
||||
:enter-address "Enter address"
|
||||
:enter-contact-code "Enter contact code"
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
(:require [clojure.string :as string]))
|
||||
|
||||
(def white "#ffffff")
|
||||
(def transparent "transparent")
|
||||
(def white-light-transparent "rgba(255, 255, 255, 0.1)") ;; Used as icon background color for a dark foreground
|
||||
(def white-transparent "rgba(255, 255, 255, 0.2)") ;; Used as icon color on dark background
|
||||
(def white-lighter-transparent "rgba(255, 255, 255, 0.6)") ;; Used for input placeholder color
|
||||
|
@ -28,6 +29,8 @@
|
|||
(def cyan "#7adcfb") ;; Used by wallet transaction filtering icon
|
||||
(def photo-border-color "#ccd3d6")
|
||||
(def green "#44d058") ;; icon for successful inboud transaction
|
||||
(def tooltip-green-text "#66bf50") ;; fading tooltip text color
|
||||
(def tooltip-green "#e9f6e6") ;; fading tooltip background color
|
||||
|
||||
(def chat-colors ["#fa6565"
|
||||
"#7cda00"
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
(ns status-im.ui.components.desktop.tabs
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.ui.components.icons.vector-icons :as icons]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.ui.components.colors :as colors]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.screens.main-tabs.styles :as tabs.styles])
|
||||
(:require-macros [status-im.utils.views :as views]))
|
||||
|
@ -26,7 +28,7 @@
|
|||
[react/view {:style tabs.styles/tab-container}
|
||||
(let [icon (if active? icon-active icon-inactive)]
|
||||
[react/view
|
||||
[icons/icon icon {:color (:color (tabs.styles/tab-icon active?))}]])
|
||||
[icons/icon icon {:style {:tint-color (if active? colors/blue colors/gray-icon)}}]])
|
||||
[react/view
|
||||
[react/text {:style (tabs.styles/tab-title active?)}
|
||||
title]]]))
|
||||
|
@ -36,13 +38,15 @@
|
|||
(defn tab [index content view-id active?]
|
||||
[react/touchable-highlight {:style (merge tabs.styles/tab-container {:flex 1})
|
||||
:disabled active?
|
||||
:on-press #(re-frame/dispatch [:set-in [:desktop/desktop :tab-view-id] view-id])}
|
||||
:on-press #(do
|
||||
(re-frame/dispatch [:navigate-to :home])
|
||||
(re-frame/dispatch [:set-in [:desktop/desktop :tab-view-id] view-id]))}
|
||||
[react/view
|
||||
[content active?]]])
|
||||
|
||||
(views/defview main-tabs []
|
||||
(views/letsubs [current-tab [:get :left-view-id]]
|
||||
(views/letsubs [current-tab [:get-in [:desktop/desktop :tab-view-id]]]
|
||||
[react/view
|
||||
[react/view {:style tabs.styles/tabs-container}
|
||||
(for [[index {:keys [content view-id]}] tabs-list-indexed]
|
||||
^{:key index} [tab index content view-id (= current-tab view-id)])]]))
|
||||
^{:key index} [tab index content view-id (= current-tab view-id)])]]))
|
||||
|
|
|
@ -2,121 +2,198 @@
|
|||
(:require-macros [status-im.ui.components.svg :as components.svg])
|
||||
(:require [goog.object :as object]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.utils.platform :as platform]
|
||||
[status-im.ui.components.styles :as styles]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.react-native.js-dependencies :as js-dependencies])
|
||||
(:refer-clojure :exclude [use]))
|
||||
|
||||
(defn get-property [name]
|
||||
(object/get js-dependencies/svg name))
|
||||
(when-not platform/desktop?
|
||||
(defn get-property [name]
|
||||
(object/get js-dependencies/svg name))
|
||||
|
||||
(defn adapt-class [class]
|
||||
(when class
|
||||
(reagent/adapt-react-class class)))
|
||||
(defn adapt-class [class]
|
||||
(when class
|
||||
(reagent/adapt-react-class class)))
|
||||
|
||||
(defn get-class [name]
|
||||
(adapt-class (get-property name)))
|
||||
(defn get-class [name]
|
||||
(adapt-class (get-property name)))
|
||||
|
||||
(def svg (get-class "Svg"))
|
||||
(def g (get-class "G"))
|
||||
(def rect (get-class "Rect"))
|
||||
(def path (get-class "Path"))
|
||||
(def use (get-class "Use"))
|
||||
(def defs (get-class "Defs"))
|
||||
(def circle (get-class "Circle"))
|
||||
(def svg (get-class "Svg"))
|
||||
(def g (get-class "G"))
|
||||
(def rect (get-class "Rect"))
|
||||
(def path (get-class "Path"))
|
||||
(def use (get-class "Use"))
|
||||
(def defs (get-class "Defs"))
|
||||
(def circle (get-class "Circle")))
|
||||
|
||||
(def icons {:icons/discover (components.svg/slurp-svg "./resources/icons/bottom/discover_gray.svg")
|
||||
:icons/contacts (components.svg/slurp-svg "./resources/icons/bottom/contacts_gray.svg")
|
||||
:icons/home (components.svg/slurp-svg "./resources/icons/bottom/home_gray.svg")
|
||||
:icons/home-active (components.svg/slurp-svg "./resources/icons/bottom/home_blue.svg")
|
||||
:icons/profile (components.svg/slurp-svg "./resources/icons/bottom/profile_gray.svg")
|
||||
:icons/profile-active (components.svg/slurp-svg "./resources/icons/bottom/profile_blue.svg")
|
||||
:icons/wallet (components.svg/slurp-svg "./resources/icons/bottom/wallet_gray.svg")
|
||||
:icons/wallet-active (components.svg/slurp-svg "./resources/icons/bottom/wallet_active.svg")
|
||||
:icons/speaker (components.svg/slurp-svg "./resources/icons/speaker.svg")
|
||||
:icons/speaker-off (components.svg/slurp-svg "./resources/icons/speaker_off.svg")
|
||||
:icons/transaction-history (components.svg/slurp-svg "./resources/icons/transaction_history.svg")
|
||||
:icons/add (components.svg/slurp-svg "./resources/icons/add.svg")
|
||||
:icons/add-contact (components.svg/slurp-svg "./resources/icons/add_contact.svg")
|
||||
:icons/add-wallet (components.svg/slurp-svg "./resources/icons/add_wallet.svg")
|
||||
:icons/address (components.svg/slurp-svg "./resources/icons/address.svg")
|
||||
:icons/arrow-left (components.svg/slurp-svg "./resources/icons/arrow_left.svg")
|
||||
:icons/arrow-right (components.svg/slurp-svg "./resources/icons/arrow_right.svg")
|
||||
:icons/flash-active (components.svg/slurp-svg "./resources/icons/flash_active.svg")
|
||||
:icons/flash-inactive (components.svg/slurp-svg "./resources/icons/flash_inactive.svg")
|
||||
:icons/attach (components.svg/slurp-svg "./resources/icons/attach.svg")
|
||||
:icons/browse (components.svg/slurp-svg "./resources/icons/browse.svg")
|
||||
:icons/close (components.svg/slurp-svg "./resources/icons/close.svg")
|
||||
:icons/copy-from (components.svg/slurp-svg "./resources/icons/copy_from.svg")
|
||||
:icons/delete (components.svg/slurp-svg "./resources/icons/delete.svg")
|
||||
:icons/dots-horizontal (components.svg/slurp-svg "./resources/icons/dots_horizontal.svg")
|
||||
:icons/dots-vertical (components.svg/slurp-svg "./resources/icons/dots_vertical.svg")
|
||||
:icons/exclamation-mark (components.svg/slurp-svg "./resources/icons/exclamation_mark.svg")
|
||||
:icons/filter (components.svg/slurp-svg "./resources/icons/filter.svg")
|
||||
:icons/fullscreen (components.svg/slurp-svg "./resources/icons/fullscreen.svg")
|
||||
:icons/group-big (components.svg/slurp-svg "./resources/icons/group_big.svg")
|
||||
:icons/group-chat (components.svg/slurp-svg "./resources/icons/group_chat.svg")
|
||||
:icons/chats (components.svg/slurp-svg "./resources/icons/chats.svg")
|
||||
:icons/hamburger (components.svg/slurp-svg "./resources/icons/hamburger.svg")
|
||||
:icons/hidden (components.svg/slurp-svg "./resources/icons/hidden.svg")
|
||||
:icons/in-contacts (components.svg/slurp-svg "./resources/icons/in_contacts.svg")
|
||||
:icons/lock (components.svg/slurp-svg "./resources/icons/lock.svg")
|
||||
:icons/mic (components.svg/slurp-svg "./resources/icons/mic.svg")
|
||||
:icons/ok (components.svg/slurp-svg "./resources/icons/ok.svg")
|
||||
:icons/public (components.svg/slurp-svg "./resources/icons/public.svg")
|
||||
:icons/public-chat (components.svg/slurp-svg "./resources/icons/public_chat.svg")
|
||||
:icons/qr (components.svg/slurp-svg "./resources/icons/QR.svg")
|
||||
:icons/input-commands (components.svg/slurp-svg "./resources/icons/input_commands.svg")
|
||||
:icons/input-send (components.svg/slurp-svg "./resources/icons/input_send.svg")
|
||||
:icons/back (components.svg/slurp-svg "./resources/icons/back.svg")
|
||||
:icons/forward (components.svg/slurp-svg "./resources/icons/forward.svg")
|
||||
:icons/dropdown-up (components.svg/slurp-svg "./resources/icons/dropdown_up.svg")
|
||||
:icons/up (components.svg/slurp-svg "./resources/icons/up.svg")
|
||||
:icons/down (components.svg/slurp-svg "./resources/icons/down.svg")
|
||||
:icons/grab (components.svg/slurp-svg "./resources/icons/grab.svg")
|
||||
:icons/share (components.svg/slurp-svg "./resources/icons/share.svg")
|
||||
:icons/tooltip-triangle (components.svg/slurp-svg "./resources/icons/tooltip-triangle.svg")
|
||||
:icons/open (components.svg/slurp-svg "./resources/icons/open.svg")
|
||||
:icons/network (components.svg/slurp-svg "./resources/icons/network.svg")
|
||||
:icons/wnode (components.svg/slurp-svg "./resources/icons/wnode.svg")
|
||||
:icons/refresh (components.svg/slurp-svg "./resources/icons/refresh.svg")
|
||||
:icons/newchat (components.svg/slurp-svg "./resources/icons/newchat.svg")
|
||||
:icons/logo (components.svg/slurp-svg "./resources/icons/logo.svg")
|
||||
:icons/camera (components.svg/slurp-svg "./resources/icons/camera.svg")
|
||||
:icons/check (components.svg/slurp-svg "./resources/icons/check.svg")
|
||||
:icons/dots (components.svg/slurp-svg "./resources/icons/dots.svg")
|
||||
:icons/warning (components.svg/slurp-svg "./resources/icons/warning.svg")})
|
||||
(if platform/desktop?
|
||||
(def icons {:icons/discover (js/require "./resources/icons/bottom/discover_gray.svg")
|
||||
:icons/contacts (js/require "./resources/icons/bottom/contacts_gray.svg")
|
||||
:icons/home (js/require "./resources/icons/bottom/home_gray.svg")
|
||||
:icons/home-active (js/require "./resources/icons/bottom/home_blue.svg")
|
||||
:icons/profile (js/require "./resources/icons/bottom/profile_gray.svg")
|
||||
:icons/profile-active (js/require "./resources/icons/bottom/profile_blue.svg")
|
||||
:icons/wallet (js/require "./resources/icons/bottom/wallet_gray.svg")
|
||||
:icons/wallet-active (js/require "./resources/icons/bottom/wallet_active.svg")
|
||||
:icons/speaker (js/require "./resources/icons/speaker.svg")
|
||||
:icons/speaker-off (js/require "./resources/icons/speaker_off.svg")
|
||||
:icons/transaction-history (js/require "./resources/icons/transaction_history.svg")
|
||||
:icons/add (js/require "./resources/icons/add.svg")
|
||||
:icons/add-contact (js/require "./resources/icons/add_contact.svg")
|
||||
:icons/add-wallet (js/require "./resources/icons/add_wallet.svg")
|
||||
:icons/address (js/require "./resources/icons/address.svg")
|
||||
:icons/arrow-left (js/require "./resources/icons/arrow_left.svg")
|
||||
:icons/arrow-right (js/require "./resources/icons/arrow_right.svg")
|
||||
:icons/flash-active (js/require "./resources/icons/flash_active.svg")
|
||||
:icons/flash-inactive (js/require "./resources/icons/flash_inactive.svg")
|
||||
:icons/attach (js/require "./resources/icons/attach.svg")
|
||||
:icons/browse (js/require "./resources/icons/browse.svg")
|
||||
:icons/close (js/require "./resources/icons/close.svg")
|
||||
:icons/copy-from (js/require "./resources/icons/copy_from.svg")
|
||||
:icons/delete (js/require "./resources/icons/delete.svg")
|
||||
:icons/dots-horizontal (js/require "./resources/icons/dots_horizontal.svg")
|
||||
:icons/dots-vertical (js/require "./resources/icons/dots_vertical.svg")
|
||||
:icons/exclamation-mark (js/require "./resources/icons/exclamation_mark.svg")
|
||||
:icons/filter (js/require "./resources/icons/filter.svg")
|
||||
:icons/fullscreen (js/require "./resources/icons/fullscreen.svg")
|
||||
:icons/group-big (js/require "./resources/icons/group_big.svg")
|
||||
:icons/group-chat (js/require "./resources/icons/group_chat.svg")
|
||||
:icons/chats (js/require "./resources/icons/chats.svg")
|
||||
:icons/hamburger (js/require "./resources/icons/hamburger.svg")
|
||||
:icons/hidden (js/require "./resources/icons/hidden.svg")
|
||||
:icons/in-contacts (js/require "./resources/icons/in_contacts.svg")
|
||||
:icons/lock (js/require "./resources/icons/lock.svg")
|
||||
:icons/mic (js/require "./resources/icons/mic.svg")
|
||||
:icons/ok (js/require "./resources/icons/ok.svg")
|
||||
:icons/public (js/require "./resources/icons/public.svg")
|
||||
:icons/public-chat (js/require "./resources/icons/public_chat.svg")
|
||||
:icons/qr (js/require "./resources/icons/QR.svg")
|
||||
:icons/input-commands (js/require "./resources/icons/input_commands.svg")
|
||||
:icons/input-send (js/require "./resources/icons/input_send.svg")
|
||||
:icons/back (js/require "./resources/icons/back.svg")
|
||||
:icons/forward (js/require "./resources/icons/forward.svg")
|
||||
:icons/dropdown-up (js/require "./resources/icons/dropdown_up.svg")
|
||||
:icons/up (js/require "./resources/icons/up.svg")
|
||||
:icons/down (js/require "./resources/icons/down.svg")
|
||||
:icons/grab (js/require "./resources/icons/grab.svg")
|
||||
:icons/share (js/require "./resources/icons/share.svg")
|
||||
:icons/tooltip-triangle (js/require "./resources/icons/tooltip-triangle.svg")
|
||||
:icons/open (js/require "./resources/icons/open.svg")
|
||||
:icons/network (js/require "./resources/icons/network.svg")
|
||||
:icons/wnode (js/require "./resources/icons/wnode.svg")
|
||||
:icons/refresh (js/require "./resources/icons/refresh.svg")
|
||||
:icons/newchat (js/require "./resources/icons/newchat.svg")
|
||||
:icons/logo (js/require "./resources/icons/logo.svg")
|
||||
:icons/camera (js/require "./resources/icons/camera.svg")
|
||||
:icons/check (js/require "./resources/icons/check.svg")
|
||||
:icons/dots (js/require "./resources/icons/dots.svg")
|
||||
:icons/warning (js/require "./resources/icons/warning.svg")})
|
||||
(def icons {:icons/discover (components.svg/slurp-svg "./resources/icons/bottom/discover_gray.svg")
|
||||
:icons/contacts (components.svg/slurp-svg "./resources/icons/bottom/contacts_gray.svg")
|
||||
:icons/home (components.svg/slurp-svg "./resources/icons/bottom/home_gray.svg")
|
||||
:icons/home-active (components.svg/slurp-svg "./resources/icons/bottom/home_blue.svg")
|
||||
:icons/profile (components.svg/slurp-svg "./resources/icons/bottom/profile_gray.svg")
|
||||
:icons/profile-active (components.svg/slurp-svg "./resources/icons/bottom/profile_blue.svg")
|
||||
:icons/wallet (components.svg/slurp-svg "./resources/icons/bottom/wallet_gray.svg")
|
||||
:icons/wallet-active (components.svg/slurp-svg "./resources/icons/bottom/wallet_active.svg")
|
||||
:icons/speaker (components.svg/slurp-svg "./resources/icons/speaker.svg")
|
||||
:icons/speaker-off (components.svg/slurp-svg "./resources/icons/speaker_off.svg")
|
||||
:icons/transaction-history (components.svg/slurp-svg "./resources/icons/transaction_history.svg")
|
||||
:icons/add (components.svg/slurp-svg "./resources/icons/add.svg")
|
||||
:icons/add-contact (components.svg/slurp-svg "./resources/icons/add_contact.svg")
|
||||
:icons/add-wallet (components.svg/slurp-svg "./resources/icons/add_wallet.svg")
|
||||
:icons/address (components.svg/slurp-svg "./resources/icons/address.svg")
|
||||
:icons/arrow-left (components.svg/slurp-svg "./resources/icons/arrow_left.svg")
|
||||
:icons/arrow-right (components.svg/slurp-svg "./resources/icons/arrow_right.svg")
|
||||
:icons/flash-active (components.svg/slurp-svg "./resources/icons/flash_active.svg")
|
||||
:icons/flash-inactive (components.svg/slurp-svg "./resources/icons/flash_inactive.svg")
|
||||
:icons/attach (components.svg/slurp-svg "./resources/icons/attach.svg")
|
||||
:icons/browse (components.svg/slurp-svg "./resources/icons/browse.svg")
|
||||
:icons/close (components.svg/slurp-svg "./resources/icons/close.svg")
|
||||
:icons/copy-from (components.svg/slurp-svg "./resources/icons/copy_from.svg")
|
||||
:icons/delete (components.svg/slurp-svg "./resources/icons/delete.svg")
|
||||
:icons/dots-horizontal (components.svg/slurp-svg "./resources/icons/dots_horizontal.svg")
|
||||
:icons/dots-vertical (components.svg/slurp-svg "./resources/icons/dots_vertical.svg")
|
||||
:icons/exclamation-mark (components.svg/slurp-svg "./resources/icons/exclamation_mark.svg")
|
||||
:icons/filter (components.svg/slurp-svg "./resources/icons/filter.svg")
|
||||
:icons/fullscreen (components.svg/slurp-svg "./resources/icons/fullscreen.svg")
|
||||
:icons/group-big (components.svg/slurp-svg "./resources/icons/group_big.svg")
|
||||
:icons/group-chat (components.svg/slurp-svg "./resources/icons/group_chat.svg")
|
||||
:icons/chats (components.svg/slurp-svg "./resources/icons/chats.svg")
|
||||
:icons/hamburger (components.svg/slurp-svg "./resources/icons/hamburger.svg")
|
||||
:icons/hidden (components.svg/slurp-svg "./resources/icons/hidden.svg")
|
||||
:icons/in-contacts (components.svg/slurp-svg "./resources/icons/in_contacts.svg")
|
||||
:icons/lock (components.svg/slurp-svg "./resources/icons/lock.svg")
|
||||
:icons/mic (components.svg/slurp-svg "./resources/icons/mic.svg")
|
||||
:icons/ok (components.svg/slurp-svg "./resources/icons/ok.svg")
|
||||
:icons/public (components.svg/slurp-svg "./resources/icons/public.svg")
|
||||
:icons/public-chat (components.svg/slurp-svg "./resources/icons/public_chat.svg")
|
||||
:icons/qr (components.svg/slurp-svg "./resources/icons/QR.svg")
|
||||
:icons/input-commands (components.svg/slurp-svg "./resources/icons/input_commands.svg")
|
||||
:icons/input-send (components.svg/slurp-svg "./resources/icons/input_send.svg")
|
||||
:icons/back (components.svg/slurp-svg "./resources/icons/back.svg")
|
||||
:icons/forward (components.svg/slurp-svg "./resources/icons/forward.svg")
|
||||
:icons/dropdown-up (components.svg/slurp-svg "./resources/icons/dropdown_up.svg")
|
||||
:icons/up (components.svg/slurp-svg "./resources/icons/up.svg")
|
||||
:icons/down (components.svg/slurp-svg "./resources/icons/down.svg")
|
||||
:icons/grab (components.svg/slurp-svg "./resources/icons/grab.svg")
|
||||
:icons/share (components.svg/slurp-svg "./resources/icons/share.svg")
|
||||
:icons/tooltip-triangle (components.svg/slurp-svg "./resources/icons/tooltip-triangle.svg")
|
||||
:icons/open (components.svg/slurp-svg "./resources/icons/open.svg")
|
||||
:icons/network (components.svg/slurp-svg "./resources/icons/network.svg")
|
||||
:icons/wnode (components.svg/slurp-svg "./resources/icons/wnode.svg")
|
||||
:icons/refresh (components.svg/slurp-svg "./resources/icons/refresh.svg")
|
||||
:icons/newchat (components.svg/slurp-svg "./resources/icons/newchat.svg")
|
||||
:icons/logo (components.svg/slurp-svg "./resources/icons/logo.svg")
|
||||
:icons/camera (components.svg/slurp-svg "./resources/icons/camera.svg")
|
||||
:icons/check (components.svg/slurp-svg "./resources/icons/check.svg")
|
||||
:icons/dots (components.svg/slurp-svg "./resources/icons/dots.svg")
|
||||
:icons/warning (components.svg/slurp-svg "./resources/icons/warning.svg")}))
|
||||
|
||||
(defn normalize-property-name [n]
|
||||
(if (= n :icons/options)
|
||||
(if platform/ios? :icons/dots-horizontal :icons/dots-vertical)
|
||||
n))
|
||||
|
||||
(defn icon
|
||||
([name] (icon name nil))
|
||||
([name {:keys [color container-style style accessibility-label width height]
|
||||
:or {accessibility-label :icon}}]
|
||||
^{:key name}
|
||||
[react/view {:style container-style
|
||||
:accessibility-label accessibility-label}
|
||||
(if-let [icon-fn (get icons (normalize-property-name name))]
|
||||
(let [icon-vec (icon-fn
|
||||
(cond
|
||||
(keyword? color)
|
||||
(case color
|
||||
:dark styles/icon-dark-color
|
||||
:gray styles/icon-gray-color
|
||||
:blue styles/color-light-blue
|
||||
:active styles/color-blue4
|
||||
:white styles/color-white
|
||||
:red styles/icon-red-color
|
||||
styles/icon-dark-color)
|
||||
(string? color)
|
||||
color
|
||||
:else
|
||||
styles/icon-dark-color))]
|
||||
(if width
|
||||
(update icon-vec 1 assoc :width width :height height)
|
||||
icon-vec))
|
||||
(throw (js/Error. (str "Unknown icon: " name))))]))
|
||||
(if platform/desktop?
|
||||
(do (def default-viewbox {:width 24 :height 24})
|
||||
|
||||
(defn icon
|
||||
([name] (icon name nil))
|
||||
([name {:keys [color container-style style accessibility-label width height]
|
||||
:or {accessibility-label :icon}}]
|
||||
(let [icon-style (if width
|
||||
(assoc default-viewbox :width width :height height)
|
||||
default-viewbox)]
|
||||
[react/view {:style container-style
|
||||
:accessibility-label accessibility-label}
|
||||
[react/image {:source (get icons (normalize-property-name name))
|
||||
:style (merge icon-style style)}]]))))
|
||||
(do (defn icon
|
||||
([name] (icon name nil))
|
||||
([name {:keys [color container-style style accessibility-label width height]
|
||||
:or {accessibility-label :icon}}]
|
||||
^{:key name}
|
||||
[react/view {:style container-style
|
||||
:accessibility-label accessibility-label}
|
||||
(if-let [icon-fn (get icons (normalize-property-name name))]
|
||||
(let [icon-vec (icon-fn
|
||||
(cond
|
||||
(keyword? color)
|
||||
(case color
|
||||
:dark styles/icon-dark-color
|
||||
:gray styles/icon-gray-color
|
||||
:blue styles/color-light-blue
|
||||
:active styles/color-blue4
|
||||
:white styles/color-white
|
||||
:red styles/icon-red-color
|
||||
styles/icon-dark-color)
|
||||
(string? color)
|
||||
color
|
||||
:else
|
||||
styles/icon-dark-color))]
|
||||
(if width
|
||||
(update icon-vec 1 assoc :width width :height height)
|
||||
icon-vec))
|
||||
(throw (js/Error. (str "Unknown icon: " name))))]))))
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
(ns status-im.ui.components.text-input.styles
|
||||
(:require-macros [status-im.utils.styles :refer [defstyle defnstyle]])
|
||||
(:require [status-im.ui.components.colors :as colors]))
|
||||
(:require [status-im.ui.components.colors :as colors]
|
||||
[status-im.utils.platform :as p]))
|
||||
|
||||
(def label
|
||||
{:font-size 14
|
||||
|
@ -15,11 +16,12 @@
|
|||
:border-radius 8
|
||||
:background-color colors/gray-lighter})
|
||||
|
||||
(def input
|
||||
(defstyle input
|
||||
{:font-size 15
|
||||
:letter-spacing -0.2
|
||||
:color colors/black
|
||||
:padding 0})
|
||||
:padding 0
|
||||
:desktop {:height 52}})
|
||||
|
||||
(defn error [label?]
|
||||
{:bottom-value (if label? -20 0)
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
(ns status-im.ui.screens.add-new.new-public-chat.subs
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.screens.add-new.new-public-chat.db :as db]
|
||||
[cljs.spec.alpha :as spec]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:new-topic-error-message
|
||||
:<- [:get :public-group-topic]
|
||||
(fn [topic]
|
||||
(when-not (spec/valid? ::db/topic topic)
|
||||
(i18n/label :topic-name-error))))
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
;; initial state of app-db
|
||||
(def app-db {:current-public-key nil
|
||||
:status-module-initialized? (or platform/ios? js/goog.DEBUG)
|
||||
:status-module-initialized? (or platform/ios? js/goog.DEBUG platform/desktop?)
|
||||
:keyboard-height 0
|
||||
:tab-bar-visible? true
|
||||
:navigation-stack '()
|
||||
|
@ -51,6 +51,7 @@
|
|||
:chat/cooldown-enabled? false
|
||||
:chat/last-outgoing-message-sent-at 0
|
||||
:chat/spam-messages-frequency 0
|
||||
:tooltips {}
|
||||
:desktop/desktop {:tab-view-id :home}
|
||||
:dimensions/window (dimensions/window)})
|
||||
|
||||
|
@ -128,6 +129,7 @@
|
|||
:navigation.screen-params/collectibles-list])))
|
||||
|
||||
(spec/def :desktop/desktop (spec/nilable any?))
|
||||
(spec/def ::tooltips (spec/nilable any?))
|
||||
|
||||
;;;;NETWORK
|
||||
|
||||
|
@ -216,6 +218,7 @@
|
|||
::modal
|
||||
::was-modal?
|
||||
::rpc-url
|
||||
::tooltips
|
||||
::web3
|
||||
::web3-node-version
|
||||
::webview-bridge
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
(ns status-im.ui.screens.desktop.main.add-new.styles
|
||||
(:require [status-im.ui.components.colors :as colors]))
|
||||
|
||||
(def new-contact-view
|
||||
{:flex 1
|
||||
:background-color colors/white
|
||||
:margin-left 24
|
||||
:margin-right 37})
|
||||
|
||||
(def new-contact-title
|
||||
{:height 64
|
||||
:align-items :flex-start
|
||||
:justify-content :center})
|
||||
|
||||
(def new-contact-title-text
|
||||
{:font-size 20
|
||||
:color :black
|
||||
:font-weight "600"})
|
||||
|
||||
(def new-contact-subtitle
|
||||
{:font-size 14})
|
||||
|
||||
(def new-contact-separator
|
||||
{:height 1
|
||||
:background-color colors/gray-light})
|
||||
|
||||
(def add-contact-edit-view
|
||||
{:height 45
|
||||
:margin-bottom 32
|
||||
:background-color colors/white
|
||||
:border-radius 12
|
||||
:flex-direction :row
|
||||
:margin-top 16})
|
||||
|
||||
(def add-contact-input
|
||||
{:font-size 14
|
||||
:background-color colors/gray-lighter
|
||||
:margin-right 12
|
||||
:border-radius 8})
|
||||
|
||||
(defn add-contact-button [error?]
|
||||
{:width 140
|
||||
:height 45
|
||||
:border-radius 8
|
||||
:background-color (if error? colors/gray-lighter colors/blue)
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(defn add-contact-button-text [error?]
|
||||
{:font-size 16
|
||||
:color (if error? colors/gray colors/white)})
|
||||
|
||||
(def suggested-contact-view
|
||||
{:flex-direction "row"
|
||||
:align-items :center
|
||||
:margin-bottom 16})
|
||||
|
||||
(def suggested-contacts
|
||||
{:margin-top 12})
|
||||
|
||||
(def suggested-contact-image
|
||||
{:width 46
|
||||
:height 46
|
||||
:border-radius 46
|
||||
:margin-right 16})
|
||||
|
||||
(def suggested-topic-image
|
||||
(merge suggested-contact-image
|
||||
{:background-color colors/blue
|
||||
:align-items :center
|
||||
:justify-content :center}))
|
||||
|
||||
(def suggested-topic-text
|
||||
{:font-size 25.6
|
||||
:color colors/white})
|
|
@ -1,47 +1,97 @@
|
|||
(ns status-im.ui.screens.desktop.main.add-new.views
|
||||
(:require-macros [status-im.utils.views :as views])
|
||||
(:require [status-im.ui.components.icons.vector-icons :as icons]
|
||||
[status-im.ui.screens.add-new.new-public-chat.view :as public-chat]
|
||||
[status-im.ui.components.list.views :as list]
|
||||
[clojure.string :as string]
|
||||
[status-im.i18n :as i18n]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.ui.screens.desktop.main.add-new.styles :as styles]
|
||||
[status-im.ui.screens.add-new.new-public-chat.view :refer [default-public-chats]]
|
||||
[status-im.ui.screens.add-new.new-public-chat.db :as public-chat-db]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.ui.components.react :as react]))
|
||||
|
||||
(views/defview new-contact []
|
||||
(views/letsubs [new-contact-identity [:get :contacts/new-identity]
|
||||
topic [:get :public-group-topic]]
|
||||
[react/view {:style {:flex 1 :background-color "#eef2f5"}}
|
||||
^{:key "newcontact"}
|
||||
[react/view {:style {:height 64 :align-items :center :padding-horizontal 11 :justify-content :center}}
|
||||
[react/text {:style {:font-size 16 :color :black :font-weight "600"}}
|
||||
"Add new contact"]]
|
||||
[react/view {:style {:height 1 :background-color "#e8ebec" :margin-horizontal 16}}]
|
||||
[react/view {:style {:height 90 :margin-horizontal 16 :margin-bottom 16 :background-color :white :border-radius 12}}
|
||||
;:box-shadow "0 0.5px 4.5px 0 rgba(0, 0, 0, 0.04)"}}
|
||||
[react/view {:style {:flex-direction :row :margin-horizontal 16 :margin-top 16}}
|
||||
contacts [:all-added-people-contacts]
|
||||
chat-error [:new-contact-error-message]
|
||||
topic [:get :public-group-topic]
|
||||
topic-error [:new-topic-error-message]
|
||||
account [:get-current-account]
|
||||
topic-input-ref (atom nil)]
|
||||
[react/scroll-view
|
||||
[react/view {:style styles/new-contact-view}
|
||||
^{:key "newcontact"}
|
||||
[react/view {:style styles/new-contact-title}
|
||||
[react/text {:style styles/new-contact-title-text}
|
||||
(i18n/label :new-chat)]]
|
||||
[react/text {:style styles/new-contact-subtitle} (i18n/label :contact-code)]
|
||||
[react/view {:style styles/new-contact-separator}]
|
||||
[react/view {:style styles/add-contact-edit-view}
|
||||
[react/text-input {:placeholder "0x..."
|
||||
:flex 1
|
||||
:style styles/add-contact-input
|
||||
:on-change (fn [e]
|
||||
(let [native-event (.-nativeEvent e)
|
||||
text (.-text native-event)]
|
||||
(re-frame/dispatch [:set :contacts/new-identity text])))}]
|
||||
[react/touchable-highlight {:disabled chat-error :on-press #(when-not chat-error (re-frame/dispatch [:add-contact-handler new-contact-identity]))}
|
||||
[react/view
|
||||
{:style (styles/add-contact-button chat-error)}
|
||||
[react/text
|
||||
{:style (styles/add-contact-button-text chat-error)}
|
||||
(i18n/label :start-chat)]]]]
|
||||
^{:key "choosecontact"}
|
||||
[react/view
|
||||
(when (seq contacts) [react/text {:style styles/new-contact-subtitle} (i18n/label :or-choose-a-contact)])
|
||||
[react/view {:style styles/suggested-contacts}
|
||||
(doall
|
||||
(for [c contacts]
|
||||
^{:key (:whisper-identity c)}
|
||||
[react/touchable-highlight {:on-press #(do
|
||||
(re-frame/dispatch [:set :contacts/new-identity (:whisper-identity c)])
|
||||
(re-frame/dispatch [:add-contact-handler (:whisper-identity c)]))}
|
||||
[react/view {:style styles/suggested-contact-view}
|
||||
[react/image {:style styles/suggested-contact-image
|
||||
:source {:uri (:photo-path c)}}]
|
||||
[react/text {:style styles/new-contact-subtitle} (:name c)]]]))]]
|
||||
^{:key "publicchat"}
|
||||
[react/view {:style styles/new-contact-title}
|
||||
[react/text {:style styles/new-contact-title-text}
|
||||
(i18n/label :new-public-group-chat)]]
|
||||
[react/text {:style styles/new-contact-subtitle} (i18n/label :public-group-topic)]
|
||||
[react/view {:style styles/new-contact-separator}]
|
||||
[react/view {:style styles/add-contact-edit-view}
|
||||
[react/view {:style {:flex 1}}
|
||||
[react/text-input {:placeholder "Contact key"
|
||||
[react/text-input {:flex 1
|
||||
:ref #(when (and (nil? @topic-input-ref) %)
|
||||
(.setNativeProps % (js-obj "text" "#"))
|
||||
(reset! topic-input-ref %))
|
||||
:style styles/add-contact-input
|
||||
:on-change (fn [e]
|
||||
(let [native-event (.-nativeEvent e)
|
||||
text (.-text native-event)]
|
||||
(re-frame/dispatch [:set :contacts/new-identity text])))}]]
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:add-contact-handler new-contact-identity])}
|
||||
[react/view {:style {:margin-left 16 :width 30 :height 30 :border-radius 15 :background-color "#eef2f5" :align-items :center
|
||||
:justify-content :center}}
|
||||
[icons/icon :icons/ok]]]]]
|
||||
^{:key "publicchat"}
|
||||
[react/view {:style {:height 64 :align-items :center :padding-horizontal 11 :justify-content :center}}
|
||||
[react/text {:style {:font-size 16 :color :black :font-weight "600"}}
|
||||
"Join to public chat"]]
|
||||
[react/view {:style {:height 1 :background-color "#e8ebec" :margin-horizontal 16}}]
|
||||
[react/view {:style {:height 90 :margin-horizontal 16 :margin-bottom 16 :background-color :white :border-radius 12}}
|
||||
;:box-shadow "0 0.5px 4.5px 0 rgba(0, 0, 0, 0.04)"}}
|
||||
[react/view {:style {:flex-direction :row :margin-horizontal 16 :margin-top 16}}
|
||||
[react/text "#"]
|
||||
[react/view {:style {:flex 1}}
|
||||
[react/text-input {:placeholder "topic"
|
||||
:on-change (fn [e]
|
||||
(let [native-event (.-nativeEvent e)
|
||||
text (.-text native-event)]
|
||||
(re-frame/dispatch [:set :public-group-topic text])))}]]
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:create-new-public-chat topic])}
|
||||
[react/view {:style {:margin-left 16 :width 30 :height 30 :border-radius 15 :background-color "#eef2f5" :align-items :center
|
||||
:justify-content :center}}
|
||||
[icons/icon :icons/ok]]]]]]))
|
||||
text (.-text native-event)
|
||||
[_ before after] (first (re-seq #"(.*)\#(.*)" text))]
|
||||
(.setNativeProps @topic-input-ref (js-obj "text" (str "#" before after)))
|
||||
(re-frame/dispatch [:set :public-group-topic (subs text 1)])))}]]
|
||||
[react/touchable-highlight {:disabled topic-error
|
||||
:on-press #(when-not topic-error
|
||||
(do
|
||||
(re-frame/dispatch [:set :public-group-topic nil])
|
||||
(re-frame/dispatch [:create-new-public-chat topic])))}
|
||||
[react/view {:style (styles/add-contact-button topic-error)}
|
||||
[react/text {:style (styles/add-contact-button-text topic-error)}
|
||||
(i18n/label :new-public-group-chat)]]]]
|
||||
[react/text {:style styles/new-contact-subtitle} (i18n/label :selected-for-you)]
|
||||
[react/view {:style styles/suggested-contacts}
|
||||
(doall
|
||||
(for [topic public-chat/default-public-chats]
|
||||
^{:key topic}
|
||||
[react/touchable-highlight {:on-press #(do
|
||||
(re-frame/dispatch [:set :public-group-topic nil])
|
||||
(re-frame/dispatch [:create-new-public-chat topic]))}
|
||||
[react/view {:style styles/suggested-contact-view}
|
||||
[react/view {:style styles/suggested-topic-image}
|
||||
[react/text {:style styles/suggested-topic-text} (string/capitalize (first topic))]]
|
||||
[react/text {:style styles/new-contact-subtitle} topic]]]))]]]))
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
(ns status-im.ui.screens.desktop.main.chat.styles
|
||||
(:require [status-im.ui.components.colors :as colors]))
|
||||
|
||||
(defn message-box [{:keys [outgoing] :as message}]
|
||||
(let [align (if outgoing :flex-end :flex-start)
|
||||
color (if outgoing colors/hawkes-blue colors/white)]
|
||||
{:align-self align
|
||||
:background-color color
|
||||
:border-radius 8
|
||||
:padding-left 12
|
||||
:padding-right 12
|
||||
:padding-top 10
|
||||
:padding-bottom 10
|
||||
:max-width 340}))
|
||||
|
||||
(defn message-row [{:keys [outgoing first-in-group?] :as message}]
|
||||
(let [padding-horizontal (if outgoing :padding-right :padding-left)
|
||||
padding-top-value (if first-in-group? 16 8)]
|
||||
{padding-horizontal 24
|
||||
:padding-top padding-top-value}))
|
||||
|
||||
(def message-row-column
|
||||
{:flex-direction :column})
|
||||
|
||||
(defn message-timestamp-placeholder []
|
||||
{:color colors/transparent
|
||||
:font-size 10
|
||||
:align-self :flex-end
|
||||
:opacity 0.5
|
||||
:text-align :right
|
||||
:text-align-vertical :center
|
||||
:width 60})
|
||||
|
||||
(defn message-timestamp []
|
||||
(merge (message-timestamp-placeholder)
|
||||
{:color colors/gray
|
||||
:position :absolute
|
||||
:bottom 0
|
||||
:right -5}))
|
||||
|
||||
(def author
|
||||
{:color colors/gray
|
||||
:font-size 12
|
||||
:margin-left 48
|
||||
:margin-bottom 4})
|
||||
|
||||
(def chat-box
|
||||
{:height 68
|
||||
:background-color :white
|
||||
:border-radius 12
|
||||
:margin-horizontal 24
|
||||
:padding-vertical 15})
|
||||
|
||||
(def chat-box-inner
|
||||
{:flex-direction :row
|
||||
:flex 1})
|
||||
|
||||
(def chat-text-input
|
||||
{:flex 1})
|
||||
|
||||
(def messages-view
|
||||
{:flex 1
|
||||
:background-color colors/gray-lighter})
|
||||
|
||||
(def messages-scrollview-inner
|
||||
{:padding-vertical 46})
|
||||
|
||||
(def photo-style
|
||||
{:borderRadius 20
|
||||
:width 40
|
||||
:height 40
|
||||
:margin-right 8})
|
||||
|
||||
(def toolbar-chat-view
|
||||
{:align-items :center
|
||||
:padding 11
|
||||
:justify-content :center})
|
||||
|
||||
(def toolbar-chat-name
|
||||
{:font-size 16
|
||||
:color :black
|
||||
:font-weight "600"})
|
||||
|
||||
(def add-contact
|
||||
{:background-color :white
|
||||
:border-radius 6
|
||||
:margin-top 3
|
||||
:padding 4})
|
||||
|
||||
(def add-contact-text
|
||||
{:font-size 14
|
||||
:color colors/gray})
|
||||
|
||||
(def message-text
|
||||
{:font-size 14})
|
||||
|
||||
(def message-wrapper
|
||||
{:flex-direction :row
|
||||
:flex-wrap :wrap})
|
||||
|
||||
(def not-first-in-group-wrapper
|
||||
{:flex-direction :row})
|
||||
|
||||
(def send-icon
|
||||
{:margin-left 16
|
||||
:width 30
|
||||
:height 30
|
||||
:border-radius 15
|
||||
:background-color colors/gray-lighter
|
||||
:align-items :center
|
||||
:justify-content :center
|
||||
:transform [{:rotate "90deg"}]})
|
||||
|
||||
(def chat-view
|
||||
{:flex 1
|
||||
:background-color :white})
|
|
@ -5,12 +5,16 @@
|
|||
[clojure.string :as string]
|
||||
[status-im.chat.styles.message.message :as message.style]
|
||||
[status-im.utils.gfycat.core :as gfycat.core]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.utils.gfycat.core :as gfycat]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.utils.identicon :as identicon]
|
||||
[status-im.utils.datetime :as time]
|
||||
[status-im.ui.components.styles :as styles]
|
||||
[status-im.ui.components.react :as react]))
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.colors :as colors]
|
||||
[status-im.chat.views.message.datemark :as message.datemark]
|
||||
[status-im.ui.screens.desktop.main.chat.styles :as styles]
|
||||
[status-im.i18n :as i18n]))
|
||||
|
||||
(views/defview toolbar-chat-view []
|
||||
(views/letsubs [{:keys [chat-id name public-key public? group-chat]} [:get-current-chat]
|
||||
|
@ -20,43 +24,33 @@
|
|||
(if (string/blank? name)
|
||||
(gfycat.core/generate-gfy public-key)
|
||||
(or name
|
||||
"Chat name")))]
|
||||
[react/view {:style {:align-items :center :padding 11 :justify-content :center}}
|
||||
(i18n/label :t/chat-name))))]
|
||||
[react/view {:style styles/toolbar-chat-view}
|
||||
[react/view {:style {:flex-direction :row}}
|
||||
(when public?
|
||||
[icons/icon :icons/public-chat])
|
||||
(when (and group-chat (not public?))
|
||||
[icons/icon :icons/group-chat])
|
||||
[react/text {:style {:font-size 16 :color :black :font-weight "600"}}
|
||||
[react/text {:style styles/toolbar-chat-name}
|
||||
chat-name]]
|
||||
(when pending?
|
||||
[react/touchable-highlight
|
||||
{:on-press #(re-frame/dispatch [:add-pending-contact chat-id])}
|
||||
[react/view {:style {:background-color :white :border-radius 6 :margin-top 3 :padding 4}} ;style/add-contact
|
||||
[react/text {:style {:font-size 14 :color "#939ba1"}}
|
||||
"Add to contacts"]]])])))
|
||||
[react/view {:style styles/add-contact} ;style/add-contact
|
||||
[react/text {:style styles/add-contact-text}
|
||||
(i18n/label :t/add-to-contacts)]]])])))
|
||||
|
||||
(views/defview message-author-name [{:keys [outgoing from] :as message}]
|
||||
(views/letsubs [current-account [:get-current-account]
|
||||
incoming-name [:get-contact-name-by-identity from]]
|
||||
(if outgoing
|
||||
[react/text {:style message.style/author} (:name current-account)]
|
||||
(let [name (or incoming-name (gfycat/generate-gfy from))]
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:show-contact-dialog from name (boolean incoming-name)])}
|
||||
[react/text {:style message.style/author} name]]))))
|
||||
|
||||
(def photo-style
|
||||
{:borderRadius 15
|
||||
:width 30
|
||||
:height 30})
|
||||
(let [name (or incoming-name (gfycat/generate-gfy from))]
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:show-contact-dialog from name (boolean incoming-name)])}
|
||||
[react/text {:style styles/author} name]])))
|
||||
|
||||
(views/defview member-photo [from]
|
||||
(views/letsubs [photo-path nil];[:photo-path from]]
|
||||
[react/view
|
||||
[react/image {:source {:uri (if (string/blank? photo-path)
|
||||
(identicon/identicon from)
|
||||
photo-path)}
|
||||
:style photo-style}]]))
|
||||
[react/view
|
||||
[react/image {:source {:uri (identicon/identicon from)}
|
||||
:style styles/photo-style}]])
|
||||
|
||||
(views/defview my-photo [from]
|
||||
(views/letsubs [account [:get-current-account]]
|
||||
|
@ -65,16 +59,42 @@
|
|||
[react/image {:source {:uri (if (string/blank? photo-path)
|
||||
(identicon/identicon from)
|
||||
photo-path)}
|
||||
:style photo-style}]])))
|
||||
:style styles/photo-style}]])))
|
||||
|
||||
(defn message [text me? {:keys [outgoing message-id chat-id message-status user-statuses timestamp
|
||||
from current-public-key content-type group-chat type value] :as message}]
|
||||
(views/defview message-with-timestamp [text {:keys [timestamp] :as message} style]
|
||||
[react/view {:style style}
|
||||
[react/view {:style styles/message-wrapper}
|
||||
[react/text {:style styles/message-text
|
||||
:selectable true}
|
||||
text]
|
||||
[react/text {:style (styles/message-timestamp-placeholder)}
|
||||
(time/timestamp->time timestamp)]
|
||||
[react/text {:style (styles/message-timestamp)}
|
||||
(time/timestamp->time timestamp)]]])
|
||||
|
||||
(views/defview text-only-message [text message]
|
||||
[react/view {:style (styles/message-row message)}
|
||||
[message-with-timestamp text message (styles/message-box message)]])
|
||||
|
||||
(views/defview photo-placeholder []
|
||||
[react/view {:style styles/photo-style}])
|
||||
|
||||
(views/defview message-with-name-and-avatar [text {:keys [from first-in-group? last-in-group?] :as message}]
|
||||
[react/view {:style (styles/message-row message)}
|
||||
[react/view {:style styles/message-row-column}
|
||||
(when first-in-group?
|
||||
[message-author-name message])
|
||||
[react/view {:style styles/not-first-in-group-wrapper}
|
||||
(if last-in-group?
|
||||
[member-photo from]
|
||||
[photo-placeholder])
|
||||
[message-with-timestamp text message (styles/message-box message)]]]])
|
||||
|
||||
(defn message [text me? {:keys [message-id chat-id message-status user-statuses from
|
||||
current-public-key content-type group-chat outgoing type value] :as message}]
|
||||
(if (= type :datemark)
|
||||
^{:key (str "datemark" message-id)}
|
||||
[react/view {:style {:margin-vertical 20}}
|
||||
[react/text
|
||||
(string/capitalize (last (string/split value #"-")))]
|
||||
[react/view {:style {:height 1 :background-color "#e8ebec"}}]]
|
||||
[message.datemark/chat-datemark value]
|
||||
(when (= content-type constants/text-content-type)
|
||||
(reagent.core/create-class
|
||||
{:component-did-mount
|
||||
|
@ -89,19 +109,9 @@
|
|||
:reagent-render
|
||||
(fn []
|
||||
^{:key (str "message" message-id)}
|
||||
[react/view {:style {:flex-direction :row :flex 1 :margin-vertical 12}}
|
||||
(if outgoing
|
||||
[my-photo from]
|
||||
[member-photo from])
|
||||
[react/view {:style {:padding-horizontal 12 :background-color :white :border-radius 8 :flex 1}}
|
||||
[react/view {:style {:flex-direction :row}}
|
||||
[message-author-name message]
|
||||
[react/view {:style {:flex 1}}]
|
||||
[react/text {:style {:color styles/color-gray4 :font-size 12}} (time/timestamp->time timestamp)]]
|
||||
;;TODO use https://github.com/status-im/status-react/pull/3299
|
||||
;;[rn-hl/hyperlink {:linkStyle {:color "#2980b9"} :on-press #(re-frame/dispatch [:show-link-dialog %1])}
|
||||
[react/text
|
||||
text]]])}))))
|
||||
(if (and group-chat (not outgoing))
|
||||
[message-with-name-and-avatar text message]
|
||||
[text-only-message text message]))}))))
|
||||
|
||||
(views/defview messages-view [{:keys [chat-id group-chat]}]
|
||||
(views/letsubs [chat-id* (atom nil)
|
||||
|
@ -113,7 +123,7 @@
|
|||
(js/setTimeout #(when scroll-ref (.scrollToEnd @scroll-ref)) 400))
|
||||
messages (re-frame/subscribe [:get-current-chat-messages-stream])
|
||||
current-public-key (re-frame/subscribe [:get-current-public-key])]
|
||||
[react/view {:style {:flex 1 :background-color :white :margin-horizontal 16}}
|
||||
[react/view {:style styles/messages-view}
|
||||
[react/scroll-view {:scrollEventThrottle 16
|
||||
:on-scroll (fn [e]
|
||||
(let [ne (.-nativeEvent e)
|
||||
|
@ -122,52 +132,48 @@
|
|||
(when @scroll-timer (js/clearTimeout @scroll-timer))
|
||||
(reset! scroll-timer (js/setTimeout #(re-frame/dispatch [:load-more-messages]) 300)))
|
||||
(reset! scroll-height (+ y (.-height (.-layoutMeasurement ne))))))
|
||||
:on-content-size-change #(when (or (not @scroll-height) (< (- %2 @scroll-height) 500))
|
||||
(.scrollToEnd @scroll-ref))
|
||||
:on-content-size-change #(.scrollToEnd @scroll-ref)
|
||||
:ref #(reset! scroll-ref %)}
|
||||
[react/view {:style {:padding-vertical 60}}
|
||||
[react/view {:style styles/messages-scrollview-inner}
|
||||
(doall
|
||||
(for [[index {:keys [from content message-id] :as message-obj}] (map-indexed vector (reverse @messages))]
|
||||
^{:key (str message index)}
|
||||
(for [[index {:keys [from content message-id type value] :as message-obj}] (map-indexed vector (reverse @messages))]
|
||||
^{:key (or message-id (str type value))}
|
||||
[message content (= from @current-public-key) (assoc message-obj :group-chat group-chat)]))]]])))
|
||||
|
||||
(views/defview chat-text-input []
|
||||
(views/letsubs [{:keys [input-text]} [:get-current-chat]
|
||||
inp-ref (atom nil)]
|
||||
[react/view {:style {:height 90 :margin-horizontal 16 :background-color :white :border-radius 12}}
|
||||
[react/view {:style {:flex-direction :row :margin-horizontal 16 :margin-top 16 :flex 1 :margin-bottom 16}}
|
||||
(views/letsubs [inp-ref (atom nil)]
|
||||
[react/view {:style styles/chat-box}
|
||||
[react/view {:style styles/chat-box-inner}
|
||||
[react/view {:style {:flex 1}}
|
||||
[react/text-input {:default-value (or input-text "")
|
||||
:placeholder "Type a message..."
|
||||
[react/text-input {:placeholder (i18n/label :t/type-a-message)
|
||||
:auto-focus true
|
||||
:multiline true
|
||||
:blur-on-submit true
|
||||
:style {:flex 1}
|
||||
:style styles/chat-text-input
|
||||
:ref #(reset! inp-ref %)
|
||||
:on-key-press (fn [e]
|
||||
(let [native-event (.-nativeEvent e)
|
||||
key (.-key native-event)]
|
||||
(when (= key "Enter")
|
||||
(js/setTimeout #(do
|
||||
(.clear @inp-ref)
|
||||
(.focus @inp-ref)) 200)
|
||||
key (.-key native-event)
|
||||
modifiers (js->clj (.-modifiers native-event))
|
||||
should-send (and (= key "Enter") (not (contains? (set modifiers) "shift")))]
|
||||
(when should-send
|
||||
(.clear @inp-ref)
|
||||
(.focus @inp-ref)
|
||||
(re-frame/dispatch [:send-current-message]))))
|
||||
:on-change (fn [e]
|
||||
(let [native-event (.-nativeEvent e)
|
||||
text (.-text native-event)]
|
||||
(re-frame/dispatch [:set-chat-input-text text])))}]]
|
||||
[react/touchable-highlight {:on-press (fn []
|
||||
(js/setTimeout #(do (.clear @inp-ref) (.focus @inp-ref)) 200)
|
||||
(.clear @inp-ref)
|
||||
(.focus @inp-ref)
|
||||
(re-frame/dispatch [:send-current-message]))}
|
||||
[react/view {:style {:margin-left 16 :width 30 :height 30 :border-radius 15 :background-color "#eef2f5" :align-items :center
|
||||
:justify-content :center :transform [{:rotate "90deg"}]}}
|
||||
[react/view {:style styles/send-icon}
|
||||
[icons/icon :icons/arrow-left]]]]]))
|
||||
|
||||
(views/defview chat-view []
|
||||
(views/letsubs [current-chat [:get-current-chat]]
|
||||
[react/view {:style {:flex 1 :background-color :white}}
|
||||
[react/view {:style styles/chat-view}
|
||||
[toolbar-chat-view]
|
||||
[react/view {:style {:height 1 :background-color "#e8ebec" :margin-horizontal 16}}]
|
||||
[messages-view current-chat]
|
||||
[react/view {:style {:height 1 :background-color "#e8ebec" :margin-horizontal 16}}]
|
||||
[chat-text-input]]))
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
(ns status-im.ui.screens.desktop.main.styles
|
||||
(:require [status-im.ui.components.colors :as colors]))
|
||||
|
||||
(def main-views
|
||||
{:flex 1
|
||||
:flex-direction :row})
|
||||
|
||||
(def left-sidebar
|
||||
{:width 340
|
||||
:background-color colors/white})
|
||||
|
||||
(def pane-separator
|
||||
{:width 1
|
||||
:background-color colors/gray-light})
|
|
@ -0,0 +1,87 @@
|
|||
(ns status-im.ui.screens.desktop.main.tabs.home.styles
|
||||
(:require [status-im.ui.components.colors :as colors]))
|
||||
|
||||
(def chat-list-view
|
||||
{:flex 1
|
||||
:background-color colors/white})
|
||||
|
||||
(defn chat-list-item [current?]
|
||||
{:padding-horizontal 16
|
||||
:flex-direction :row
|
||||
:flex 1
|
||||
:justify-content :space-between
|
||||
:background-color (if current? colors/gray-lighter colors/white)
|
||||
:align-items :center})
|
||||
|
||||
(def chat-list-header
|
||||
{:flex-direction :row
|
||||
:align-items :center
|
||||
:padding 11})
|
||||
|
||||
(def img-container
|
||||
{:height 78
|
||||
:justify-content :center})
|
||||
|
||||
(def chat-icon
|
||||
{:width 46
|
||||
:height 46
|
||||
:border-radius 46
|
||||
:margin-right 16})
|
||||
|
||||
(def unread-messages-icon
|
||||
{:position :absolute
|
||||
:width 22
|
||||
:height 22
|
||||
:border-radius 22
|
||||
:left 28
|
||||
:top 10
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:background-color colors/blue})
|
||||
|
||||
(defn unread-messages-text [large?]
|
||||
{:color colors/white
|
||||
:font-size (if large? 10 12)})
|
||||
|
||||
(def chat-list-separator
|
||||
{:height 1
|
||||
:background-color colors/gray-light})
|
||||
|
||||
(def chat-name-box
|
||||
{:flex-direction :row
|
||||
:align-items :center})
|
||||
|
||||
(def chat-name-last-msg-box
|
||||
{:flex 1
|
||||
:padding-vertical 16})
|
||||
|
||||
(defn chat-name [current?]
|
||||
{:font-size 14
|
||||
:font-weight (if current? "600" :normal)})
|
||||
|
||||
(def chat-last-message
|
||||
{:color colors/gray
|
||||
:font-size 14})
|
||||
|
||||
(def timestamp
|
||||
{:justify-content :flex-start
|
||||
:align-items :flex-end
|
||||
:padding-vertical 16})
|
||||
|
||||
(def add-new
|
||||
{:background-color colors/blue
|
||||
:width 34
|
||||
:height 34
|
||||
:border-radius 34
|
||||
:justify-content :center
|
||||
:align-items :center})
|
||||
|
||||
(defn topic-image [color]
|
||||
(merge chat-icon
|
||||
{:background-color color
|
||||
:align-items :center
|
||||
:justify-content :center}))
|
||||
|
||||
(def topic-text
|
||||
{:font-size 25.6
|
||||
:color colors/white})
|
|
@ -2,6 +2,12 @@
|
|||
(:require-macros [status-im.utils.views :as views])
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.utils.gfycat.core :as gfycat]
|
||||
[status-im.i18n :as i18n]
|
||||
|
||||
[status-im.ui.screens.desktop.main.tabs.home.styles :as styles]
|
||||
[clojure.string :as string]
|
||||
[status-im.ui.screens.home.views.inner-item :as chat-item]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.ui.components.icons.vector-icons :as icons]
|
||||
[status-im.ui.components.react :as react]))
|
||||
|
||||
|
@ -12,36 +18,60 @@
|
|||
[react/text {:font :medium}
|
||||
@unviewed-messages-count]])))
|
||||
|
||||
(views/defview chat-list-item-inner-view [{:keys [chat-id name group-chat public? public-key]}]
|
||||
(let [name (str
|
||||
(if public? "#" "")
|
||||
(or name
|
||||
(gfycat/generate-gfy public-key)))]
|
||||
[react/view {:style {:padding 12 :background-color :white :flex-direction :row :align-items :center}}
|
||||
(when public?
|
||||
[icons/icon :icons/public-chat])
|
||||
(when (and group-chat (not public?))
|
||||
[icons/icon :icons/group-chat])
|
||||
[react/text
|
||||
name]
|
||||
[react/view {:style {:flex 1}}]
|
||||
[unviewed-indicator chat-id]]))
|
||||
(views/defview chat-list-item-inner-view [{:keys [chat-id name group-chat color public? public-key] :as chat-item}]
|
||||
(letsubs [photo-path [:get-chat-photo chat-id]
|
||||
unviewed-messages-count [:unviewed-messages-count chat-id]
|
||||
chat-name [:get-chat-name chat-id]
|
||||
current-chat-id [:get-current-chat-id]
|
||||
last-message [:get-last-message chat-id]]
|
||||
(let [name (or chat-name
|
||||
(gfycat/generate-gfy public-key))
|
||||
[unviewed-messages-label large?] (if (< 99 unviewed-messages-count)
|
||||
["99+" true]
|
||||
[unviewed-messages-count false])]
|
||||
[react/view {:style (styles/chat-list-item (= current-chat-id chat-id))}
|
||||
[react/view {:style styles/img-container}
|
||||
(if public?
|
||||
[react/view {:style (styles/topic-image color)}
|
||||
[react/text {:style styles/topic-text}
|
||||
(string/capitalize (second name))]]
|
||||
[react/image {:style styles/chat-icon
|
||||
:source {:uri photo-path}}])
|
||||
(when (pos? unviewed-messages-count)
|
||||
[react/view {:style styles/unread-messages-icon}
|
||||
[react/text {:style (styles/unread-messages-text large?)} unviewed-messages-label]])]
|
||||
[react/view {:style styles/chat-name-last-msg-box}
|
||||
[react/view {:style styles/chat-name-box}
|
||||
(when (and group-chat (not public?))
|
||||
[icons/icon :icons/group-chat])
|
||||
(when public?
|
||||
[icons/icon :icons/public-chat])
|
||||
[react/text {:ellipsize-mode :tail
|
||||
:number-of-lines 1
|
||||
:style (styles/chat-name (= current-chat-id chat-id))}
|
||||
name]]
|
||||
[react/text {:ellipsize-mode :tail
|
||||
:number-of-lines 1
|
||||
:style styles/chat-last-message}
|
||||
(or (:content last-message) (i18n/label :no-messages-yet))]]
|
||||
[react/view {:style styles/timestamp}
|
||||
[chat-item/message-timestamp (:timestamp last-message)]]])))
|
||||
|
||||
(defn chat-list-item [[chat-id chat]]
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:navigate-to-chat chat-id])}
|
||||
[react/view
|
||||
[chat-list-item-inner-view (assoc chat :chat-id chat-id)]]])
|
||||
[chat-list-item-inner-view (assoc chat :chat-id chat-id)]])
|
||||
|
||||
(views/defview chat-list-view []
|
||||
(views/letsubs [home-items [:home-items]]
|
||||
[react/view {:style {:flex 1 :background-color :white}}
|
||||
[react/view {:style {:align-items :center :flex-direction :row :padding 11}}
|
||||
[react/view {:style styles/chat-list-view}
|
||||
[react/view {:style styles/chat-list-header}
|
||||
[react/view {:style {:flex 1}}]
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:navigate-to :new-contact])}
|
||||
[icons/icon :icons/add]]]
|
||||
[react/view {:style {:height 1 :background-color "#e8ebec" :margin-horizontal 16}}]
|
||||
[react/view {:style styles/add-new}
|
||||
[icons/icon :icons/add {:style {:tint-color :white}}]]]]
|
||||
[react/view {:style styles/chat-list-separator}]
|
||||
[react/scroll-view
|
||||
[react/view
|
||||
(for [[index chat] (map-indexed vector home-items)]
|
||||
^{:key (str chat index)}
|
||||
[chat-list-item chat])]]]))
|
||||
^{:key (first chat)}
|
||||
[chat-list-item chat])]]]))
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
(ns status-im.ui.screens.desktop.main.tabs.profile.styles
|
||||
(:require [status-im.ui.components.colors :as colors]))
|
||||
|
||||
(def profile-view
|
||||
{:align-items :center})
|
||||
|
||||
(def profile-badge
|
||||
{:margin-top 34
|
||||
:align-items :center
|
||||
:margin-bottom 16})
|
||||
|
||||
(def logout-row
|
||||
{:justify-content :space-between
|
||||
:flex-direction :row
|
||||
:margin-horizontal 24
|
||||
:align-self :stretch
|
||||
:margin-top 60})
|
||||
|
||||
(defn logout-row-text [color]
|
||||
{:color color
|
||||
:font-size 16})
|
||||
|
||||
(def profile-photo
|
||||
{:border-radius 100
|
||||
:width 100
|
||||
:height 100})
|
||||
|
||||
(def profile-user-name
|
||||
{:font-weight :bold
|
||||
:font-size 18})
|
||||
|
||||
(def share-contact-code
|
||||
{:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:align-items :center
|
||||
:height 45
|
||||
:width 240
|
||||
:margin-horizontal 50
|
||||
:border-radius 8
|
||||
:background-color (colors/alpha colors/blue 0.1)})
|
||||
|
||||
(def share-contact-code-text-container
|
||||
{:margin-left 32
|
||||
:justify-content :center
|
||||
:align-items :center})
|
||||
|
||||
(def share-contact-code-text
|
||||
{:color colors/blue
|
||||
:font-size 14})
|
||||
|
||||
(def share-contact-icon-container
|
||||
{:margin-right 12
|
||||
:width 22
|
||||
:height 22
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(def qr-code-container
|
||||
{:align-items :center
|
||||
:padding-top 16
|
||||
:padding-bottom 46
|
||||
:padding-left 58
|
||||
:padding-right 58})
|
||||
|
||||
(def close-icon-container
|
||||
{:flex 1
|
||||
:margin-top 22
|
||||
:margin-right 22
|
||||
:margin-bottom 16
|
||||
:flex-direction :row
|
||||
:justify-content :flex-end})
|
||||
|
||||
(def close-icon
|
||||
{:height 24
|
||||
:width 24
|
||||
:tint-color colors/gray-icon})
|
||||
|
||||
(def check-icon
|
||||
{:height 16
|
||||
:width 16
|
||||
:margin-right 8
|
||||
:tint-color colors/tooltip-green-text})
|
||||
|
||||
(def qr-code-title
|
||||
{:font-size 20
|
||||
:font-weight "600"
|
||||
:margin-bottom 32})
|
||||
|
||||
(def qr-code
|
||||
{:width 130
|
||||
:height 130
|
||||
:margin-bottom 16})
|
||||
|
||||
(def qr-code-text
|
||||
{:font-size 16
|
||||
:text-align :center
|
||||
:margin-bottom 16})
|
||||
|
||||
(def qr-code-copy
|
||||
{:width 185
|
||||
:height 45
|
||||
:border-radius 8
|
||||
:background-color colors/blue
|
||||
:justify-content :center
|
||||
:align-items :center})
|
||||
|
||||
(def qr-code-copy-text
|
||||
{:font-size 16
|
||||
:color colors/white})
|
||||
|
||||
(defn tooltip-container [opacity]
|
||||
{:position :absolute
|
||||
:align-items :center
|
||||
:opacity opacity
|
||||
:top -34})
|
||||
|
||||
(def tooltip-icon-text
|
||||
{:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:align-items :center
|
||||
:height 24
|
||||
:border-radius 8
|
||||
:padding-left 10
|
||||
:padding-right 10
|
||||
:background-color colors/tooltip-green})
|
||||
|
||||
(def tooltip-triangle
|
||||
{:width 0
|
||||
:height 0
|
||||
:border-top-width 9.1
|
||||
:border-left-width 9.1
|
||||
:border-right-width 9.1
|
||||
:border-left-color :transparent
|
||||
:border-right-color :transparent
|
||||
:border-top-color colors/tooltip-green})
|
|
@ -2,40 +2,73 @@
|
|||
(:require-macros [status-im.utils.views :as views])
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.screens.profile.user.views :as profile]
|
||||
[status-im.utils.build :as build]
|
||||
[status-im.utils.utils :as utils]
|
||||
[status-im.ui.components.colors :as colors]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.components.icons.vector-icons :as vector-icons]
|
||||
[taoensso.timbre :as log]
|
||||
[clojure.string :as string]
|
||||
[status-im.ui.components.qr-code-viewer.views :as qr-code-viewer]
|
||||
[status-im.ui.screens.desktop.main.tabs.profile.styles :as styles]
|
||||
[status-im.ui.screens.profile.user.views :as profile]))
|
||||
|
||||
(defn profile-badge [{:keys [name]}]
|
||||
[react/view {:margin-vertical 10}
|
||||
[react/text {:style {:font-weight :bold}
|
||||
(defn profile-badge [{:keys [name photo-path]}]
|
||||
[react/view styles/profile-badge
|
||||
[react/image {:source {:uri photo-path}
|
||||
:style styles/profile-photo}]
|
||||
[react/text {:style styles/profile-user-name
|
||||
:number-of-lines 1}
|
||||
name]])
|
||||
|
||||
(defn profile-info-item [{:keys [label value]}]
|
||||
[react/view
|
||||
[react/view
|
||||
[react/text
|
||||
label]
|
||||
[react/view {:height 10}]
|
||||
[react/text {:number-of-lines 1
|
||||
:ellipsizeMode :middle}
|
||||
value]]])
|
||||
(views/defview copied-tooltip [opacity]
|
||||
(views/letsubs []
|
||||
[react/view {:style (styles/tooltip-container opacity)}
|
||||
[react/view {:style styles/tooltip-icon-text}
|
||||
[vector-icons/icon :icons/check
|
||||
{:style styles/check-icon}]
|
||||
[react/text {:style {:font-size 14 :color colors/tooltip-green-text}}
|
||||
(i18n/label :sharing-copied-to-clipboard)]]
|
||||
[react/view {:style styles/tooltip-triangle}]]))
|
||||
|
||||
(defn my-profile-info [{:keys [public-key]}]
|
||||
[react/view
|
||||
[profile-info-item
|
||||
{:label "Contact Key"
|
||||
:value public-key}]])
|
||||
(views/defview qr-code []
|
||||
(views/letsubs [{:keys [public-key]} [:get-current-account]
|
||||
tooltip-opacity [:get-in [:tooltips :qr-copied]]]
|
||||
[react/view
|
||||
[react/view {:style styles/qr-code-container}
|
||||
[react/text {:style styles/qr-code-title}
|
||||
(string/replace (i18n/label :qr-code-public-key-hint) "\n" "")]
|
||||
[react/view {:style styles/qr-code}
|
||||
[qr-code-viewer/qr-code {:value public-key :size 130}]]
|
||||
[react/view {:style {:align-items :center}}
|
||||
[react/text {:style styles/qr-code-text}
|
||||
public-key]
|
||||
(when tooltip-opacity
|
||||
[copied-tooltip tooltip-opacity])]
|
||||
[react/touchable-highlight {:on-press #(do
|
||||
(re-frame/dispatch [:copy-to-clipboard public-key])
|
||||
(re-frame/dispatch [:show-tooltip :qr-copied]))}
|
||||
[react/view {:style styles/qr-code-copy}
|
||||
[react/text {:style styles/qr-code-copy-text}
|
||||
(i18n/label :copy-qr)]]]]]))
|
||||
|
||||
(defn share-contact-code []
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:navigate-to :qr-code])}
|
||||
[react/view {:style styles/share-contact-code}
|
||||
[react/view {:style styles/share-contact-code-text-container}
|
||||
[react/text {:style styles/share-contact-code-text}
|
||||
(i18n/label :share-contact-code)]]
|
||||
[react/view {:style styles/share-contact-icon-container
|
||||
:accessibility-label :share-my-contact-code-button}
|
||||
[vector-icons/icon :icons/qr {:style {:tint-color colors/blue}}]]]])
|
||||
|
||||
(views/defview profile []
|
||||
(views/letsubs [current-account [:get-current-account]]
|
||||
[react/view {:margin-top 40 :margin-horizontal 10}
|
||||
[react/view
|
||||
[profile-badge current-account]]
|
||||
[react/view {:style {:height 1 :background-color "#e8ebec" :margin-horizontal 16}}]
|
||||
[react/view
|
||||
[my-profile-info current-account]]
|
||||
[react/view {:style {:height 1 :background-color "#e8ebec" :margin-horizontal 16}}]
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:logout])
|
||||
:style {:margin-top 60}}
|
||||
[react/view
|
||||
[react/text {:style {:color :red}} "Log out"]]]]))
|
||||
[react/view styles/profile-view
|
||||
[profile-badge current-account]
|
||||
[share-contact-code]
|
||||
[react/view {:style styles/logout-row}
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:logout])}
|
||||
[react/text {:style (styles/logout-row-text colors/red)} (i18n/label :t/logout)]]
|
||||
[react/view [react/text {:style (styles/logout-row-text colors/gray)} "V" build/version]]]]))
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
(:require-macros [status-im.utils.views :as views])
|
||||
(:require [status-im.ui.screens.desktop.main.tabs.profile.views :as profile.views]
|
||||
[status-im.ui.screens.desktop.main.tabs.home.views :as home.views]
|
||||
[status-im.ui.screens.desktop.main.styles :as styles]
|
||||
[status-im.ui.screens.desktop.main.chat.views :as chat.views]
|
||||
[status-im.ui.screens.desktop.main.add-new.views :as add-new.views]
|
||||
[status-im.ui.components.desktop.tabs :as tabs]
|
||||
|
@ -24,17 +25,18 @@
|
|||
(views/defview main-view []
|
||||
(views/letsubs [view-id [:get :view-id]]
|
||||
(let [component (case view-id
|
||||
:chat chat.views/chat-view
|
||||
:chat chat.views/chat-view
|
||||
:new-contact add-new.views/new-contact
|
||||
:qr-code profile.views/qr-code
|
||||
status-view)]
|
||||
[react/view {:style {:flex 1}}
|
||||
[component]])))
|
||||
|
||||
(views/defview main-views []
|
||||
[react/view {:style {:flex 1 :flex-direction :row}}
|
||||
[react/view {:style {:width 280 :background-color :white}}
|
||||
[react/view {:style styles/main-views}
|
||||
[react/view {:style styles/left-sidebar}
|
||||
[react/view {:style {:flex 1}}
|
||||
[tab-views]]
|
||||
[tabs/main-tabs]]
|
||||
[react/view {:style {:width 1 :background-color "#e8ebec"}}]
|
||||
[main-view]])
|
||||
[react/view {:style styles/pane-separator}]
|
||||
[main-view]])
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
[status-im.ui.screens.accounts.recover.views :as recover.views]
|
||||
[status-im.ui.screens.accounts.views :as accounts.views]))
|
||||
|
||||
(enable-console-print!)
|
||||
|
||||
(views/defview main []
|
||||
(views/letsubs [view-id [:get :view-id]]
|
||||
(let [component (case view-id
|
||||
|
@ -15,7 +17,7 @@
|
|||
:accounts accounts.views/accounts
|
||||
:recover recover.views/recover
|
||||
:create-account create.views/create-account
|
||||
(:new-contact :chat :home) main.views/main-views
|
||||
(:new-contact :chat :home :qr-code) main.views/main-views
|
||||
:login login.views/login
|
||||
react/view)]
|
||||
[react/view {:style {:flex 1}}
|
||||
|
|
|
@ -345,8 +345,8 @@
|
|||
[:process-pending-messages]
|
||||
[:update-wallet]
|
||||
[:update-transactions]
|
||||
(when platform/mobile? [:get-fcm-token])
|
||||
[:sync-wallet-transactions]
|
||||
[:get-fcm-token]
|
||||
[:update-sign-in-time]]
|
||||
(seq events-after) (into events-after))}))
|
||||
|
||||
|
|
|
@ -107,6 +107,7 @@
|
|||
(defstyle datetime-text
|
||||
{:color component.styles/text4-color
|
||||
:android {:font-size 14}
|
||||
:desktop {:font-size 14}
|
||||
:ios {:font-size 15}})
|
||||
|
||||
(def new-messages-container
|
||||
|
|
|
@ -3,7 +3,12 @@
|
|||
[status-im.utils.platform :as platform])
|
||||
(:require-macros [status-im.utils.styles :refer [defnstyle]]))
|
||||
|
||||
(def tabs-height (if platform/ios? 52 56))
|
||||
(def tabs-height
|
||||
(cond
|
||||
platform/android? 56
|
||||
platform/ios? 52
|
||||
platform/desktop? 68))
|
||||
|
||||
(def tab-height (dec tabs-height))
|
||||
|
||||
(def tabs-container
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
(ns status-im.ui.screens.profile.events
|
||||
(:require [clojure.spec.alpha :as spec]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.ui.components.react :refer [show-image-picker]]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.chat.constants :as chat-const]
|
||||
[status-im.ui.screens.profile.navigation]
|
||||
[status-im.ui.screens.accounts.utils :as accounts.utils]
|
||||
[status-im.chat.events :as chat-events]
|
||||
|
@ -15,7 +16,7 @@
|
|||
:open-image-picker
|
||||
;; the image picker is only used here for now, this effect can be use in other scenarios as well
|
||||
(fn [callback-event]
|
||||
(show-image-picker
|
||||
(react/show-image-picker
|
||||
(fn [image]
|
||||
(let [path (get (js->clj image) "path")
|
||||
_ (log/debug path)
|
||||
|
@ -114,3 +115,40 @@
|
|||
(handlers-macro/merge-fx cofx
|
||||
{:db (update db :my-profile/seed assoc :step :finish :error nil :word nil)}
|
||||
(accounts.utils/clean-seed-phrase))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:copy-to-clipboard
|
||||
(fn [value]
|
||||
(react/copy-to-clipboard value)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:copy-to-clipboard
|
||||
(fn [_ [_ value]]
|
||||
{:copy-to-clipboard value}))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:show-tooltip
|
||||
(let [tooltips (atom {})]
|
||||
(fn [tooltip-id]
|
||||
(when-let [{:keys [interval-id]} (@tooltips tooltip-id)]
|
||||
(js/clearInterval interval-id))
|
||||
(let [interval-id (js/setInterval
|
||||
#(let [{:keys [opacity interval-id cnt]} (@tooltips tooltip-id)]
|
||||
(when opacity
|
||||
(swap! tooltips assoc-in [tooltip-id :cnt] (inc cnt))
|
||||
(if (and opacity (>= 0.0 opacity))
|
||||
(do
|
||||
(log/debug "remove interval:" interval-id)
|
||||
(js/clearInterval interval-id)
|
||||
(re-frame/dispatch [:set-in [:tooltips tooltip-id] nil])
|
||||
(swap! tooltips dissoc interval-id))
|
||||
(do (re-frame/dispatch [:set-in [:tooltips tooltip-id] opacity])
|
||||
(when (< 10 cnt)
|
||||
(swap! tooltips assoc-in [tooltip-id :opacity] (- opacity 0.05)))))))
|
||||
100)]
|
||||
(swap! tooltips assoc tooltip-id {:opacity 1.0 :interval-id interval-id :cnt 0})))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:show-tooltip
|
||||
(fn [_ [_ tooltip-id]]
|
||||
{:show-tooltip tooltip-id}))
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
(ns status-im.ui.screens.profile.subs
|
||||
(:require [re-frame.core :refer [reg-sub]]
|
||||
[clojure.string :as string]
|
||||
[status-im.utils.build :as build]))
|
||||
[status-im.utils.build :as build]
|
||||
[status-im.utils.platform :as platform]))
|
||||
|
||||
(reg-sub
|
||||
:get-profile-unread-messages-number
|
||||
|
@ -12,7 +13,8 @@
|
|||
(reg-sub
|
||||
:get-app-version
|
||||
(fn [{:keys [web3-node-version]}]
|
||||
(str build/version " (" build/build-no ")\nnode " (or web3-node-version "N/A") "")))
|
||||
(let [version (if platform/desktop? build/version build/build-no)]
|
||||
(str build/version " (" version ")\nnode " (or web3-node-version "N/A") ""))))
|
||||
|
||||
(reg-sub :get-device-UUID
|
||||
(fn [db]
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
status-im.ui.screens.currency-settings.subs
|
||||
status-im.ui.screens.browser.subs
|
||||
status-im.ui.screens.add-new.new-chat.subs
|
||||
status-im.ui.screens.add-new.new-public-chat.subs
|
||||
status-im.ui.screens.profile.subs))
|
||||
|
||||
(reg-sub :get
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
(ns status-im.utils.keychain.core
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.react-native.js-dependencies :as rn]))
|
||||
[status-im.react-native.js-dependencies :as rn]
|
||||
[status-im.utils.platform :as platform]))
|
||||
|
||||
(def key-bytes 64)
|
||||
(def username "status-im.encryptionkey")
|
||||
|
@ -73,3 +74,6 @@
|
|||
(defn reset []
|
||||
(log/debug "resetting key...")
|
||||
(.resetGenericPassword rn/keychain))
|
||||
|
||||
(defn set-username []
|
||||
(when platform/desktop? (.setUsername rn/keychain username)))
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
(ns status-im.utils.keychain.events
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.utils.keychain.core :as keychain]))
|
||||
[status-im.utils.keychain.core :as keychain]
|
||||
[status-im.utils.platform :as platform]))
|
||||
|
||||
(defn handle-key-error [event {:keys [error key]}]
|
||||
(if (= :weak-key error)
|
||||
|
@ -13,6 +14,7 @@
|
|||
(re-frame/reg-fx
|
||||
:get-encryption-key
|
||||
(fn [event]
|
||||
(when platform/desktop? (keychain/set-username))
|
||||
(.. (keychain/get-encryption-key)
|
||||
(then #(re-frame/dispatch (conj event %)))
|
||||
(catch (partial handle-key-error event)))))
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
[status-im.utils.config :as config]
|
||||
[status-im.utils.utils :as utils]
|
||||
[status-im.ui.components.react :refer [copy-to-clipboard]]
|
||||
[taoensso.timbre :as log]))
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.utils.platform :as platform]))
|
||||
|
||||
;; Work in progress namespace responsible for push notifications and interacting
|
||||
;; with Firebase Cloud Messaging.
|
||||
|
@ -28,14 +29,16 @@
|
|||
|
||||
;; NOTE: Only need to explicitly request permissions on iOS.
|
||||
(defn request-permissions []
|
||||
(-> (.requestPermissions (.-default rn/react-native-fcm))
|
||||
(.then
|
||||
(fn [_]
|
||||
(log/debug "notifications-granted")
|
||||
(dispatch [:request-notifications-granted {}]))
|
||||
(fn [_]
|
||||
(log/debug "notifications-denied")
|
||||
(dispatch [:request-notifications-denied {}])))))
|
||||
(if platform/desktop?
|
||||
(dispatch [:request-notifications-granted {}])
|
||||
(-> (.requestPermissions (.-default rn/react-native-fcm))
|
||||
(.then
|
||||
(fn [_]
|
||||
(log/debug "notifications-granted")
|
||||
(dispatch [:request-notifications-granted {}]))
|
||||
(fn [_]
|
||||
(log/debug "notifications-denied")
|
||||
(dispatch [:request-notifications-denied {}]))))))
|
||||
|
||||
(defn get-fcm-token []
|
||||
(-> (.getFCMToken (object/get rn/react-native-fcm "default"))
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
(def android? (= os "android"))
|
||||
(def ios? (= os "ios"))
|
||||
(def desktop? (= os "desktop"))
|
||||
(def mobile? (not= os "desktop"))
|
||||
(def iphone-x? (and ios? (ios/iphone-x-dimensions?)))
|
||||
|
||||
(def platform-specific
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
(defn body [style]
|
||||
`(let [style# ~style
|
||||
common# (dissoc style# :android :ios)
|
||||
common# (dissoc style# :android :ios :desktop)
|
||||
platform# (keyword status-im.utils.platform/os)
|
||||
platform-specific# (get style# platform#)]
|
||||
(if platform-specific#
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Copyright (C) 2016, Canonical Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
*/
|
||||
|
||||
console.debug = console.log;
|
||||
|
||||
|
||||
var net = require('net');
|
||||
var repl = require('repl');
|
||||
var vm = require('vm');
|
||||
var util = require('util');
|
||||
var Buffer = require('buffer').Buffer;
|
||||
var realmConstructor = require("./node_modules/realm/lib/index.js");
|
||||
console.log("Loaded realmConstructor: " + realmConstructor);
|
||||
|
||||
var DEBUG = 1;
|
||||
|
||||
function rnUbuntuServer(readable, writable) {
|
||||
console.reportErrorsAsExceptions = false; // XXX:
|
||||
var sandbox = { console: console, util: util, outerRealmConstructor: realmConstructor };
|
||||
vm.createContext(sandbox);
|
||||
|
||||
var state = 'start';
|
||||
var length = 0;
|
||||
var buffer = new Buffer(0);
|
||||
|
||||
var internalEval = function(code) {
|
||||
DEBUG > 3 && console.error("-- internalEval: executing script(length=" + code.length + "): " + code.slice(0, 80) + " ... " + code.slice(-80));
|
||||
DEBUG > 3 && console.error("-- before sandbox=" + util.inspect(sandbox, { colors: true, depth: null }));
|
||||
var result = vm.runInContext(code, sandbox);
|
||||
DEBUG > 3 && console.error("-- internalEval: result = " + result);
|
||||
DEBUG > 3 && console.error("-- after sandbox=" + util.inspect(sandbox, { colors: true, depth: null }));
|
||||
return result;
|
||||
};
|
||||
|
||||
var sendResponse = function(result) {
|
||||
function sendResponsePacket(response) {
|
||||
const sizeBuf = new Buffer(4);
|
||||
const dataBuf = new Buffer(response);
|
||||
sizeBuf.writeUInt32LE(dataBuf.length, 0);
|
||||
writable.write(sizeBuf);
|
||||
writable.write(dataBuf);
|
||||
}
|
||||
|
||||
var stringifiedResult = JSON.stringify(result);
|
||||
DEBUG > 3 && console.error("-- sending result=" + stringifiedResult);
|
||||
if (stringifiedResult === undefined) {
|
||||
sendResponsePacket('undefined');
|
||||
return;
|
||||
}
|
||||
sendResponsePacket(stringifiedResult);
|
||||
}
|
||||
|
||||
readable.on('error', function (exc) {
|
||||
console.warn("ignoring exception: " + exc);
|
||||
});
|
||||
|
||||
readable.on('data', function(chunk) {
|
||||
DEBUG > 2 && console.error("-- Data received from RN Client: state = " + state)
|
||||
DEBUG > 2 && console.error("-- chunk length: " + chunk.length)
|
||||
DEBUG > 2 && console.error("-- buffer length(original): " + buffer.length)
|
||||
|
||||
if (chunk == null || state === 'eof')
|
||||
return;
|
||||
|
||||
buffer = Buffer.concat([buffer, chunk]);
|
||||
DEBUG > 2 && console.error("-- buffer length(concat): " + buffer.length)
|
||||
|
||||
while(true) {
|
||||
if (state === 'start') {
|
||||
if (buffer.length < 4)
|
||||
return;
|
||||
length = buffer.readUInt32LE(0);
|
||||
DEBUG > 2 && console.error("-- New Packet: length=" + length);
|
||||
|
||||
if (buffer.length >= length + 4) {
|
||||
var result = internalEval(buffer.toString('utf8', 4, length + 4));
|
||||
var tmpBuffer = new Buffer(buffer.length - 4 - length);
|
||||
buffer.copy(tmpBuffer, 0, length + 4, buffer.length);
|
||||
buffer = tmpBuffer;
|
||||
sendResponse(result);
|
||||
} else {
|
||||
state = 'script';
|
||||
}
|
||||
}
|
||||
|
||||
if (state === 'script') {
|
||||
DEBUG > 2 && console.error("-- Packet length: " + length);
|
||||
if (buffer.length >= length + 4) {
|
||||
var result = internalEval(buffer.toString('utf8', 4, length + 4));
|
||||
var tmpBuffer = new Buffer(buffer.length - 4 - length);
|
||||
buffer.copy(tmpBuffer, 0, length + 4, buffer.length);
|
||||
buffer = tmpBuffer;
|
||||
state = 'start';
|
||||
sendResponse(result);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
readable.on('end', function() {
|
||||
state = 'eof';
|
||||
DEBUG && console.error("-- Session ended");
|
||||
});
|
||||
}
|
||||
|
||||
if (process.argv.indexOf('--pipe') != -1) {
|
||||
console.log = console.error
|
||||
rnUbuntuServer(process.stdin, process.stdout);
|
||||
} else {
|
||||
var server = net.createServer((sock) => {
|
||||
DEBUG && console.error("-- Connection from RN client");
|
||||
rnUbuntuServer(sock, sock);
|
||||
}).listen(5000, function() { console.error("-- Server starting") });
|
||||
}
|
Loading…
Reference in New Issue