Browse Source

Desktop branch merged into develop (#5266)

* Desktop branch merged into develop
* Fixed review notes by yenda
tags/build-2601
Volodymyr Kozieiev 1 year ago
parent
commit
457f2a157a
No account linked to committer's email address
88 changed files with 17296 additions and 2561 deletions
  1. 1
    0
      .gitattributes
  2. 5
    0
      .gitignore
  3. 2
    1
      Jenkinsfile
  4. 197
    0
      Jenkinsfile.desktopbuild
  5. 1
    0
      Jenkinsfile.nightly
  6. 1
    0
      Jenkinsfile.nightly_fastlane
  7. 1
    0
      Jenkinsfile.parameters
  8. 1
    0
      Jenkinsfile.release
  9. 1
    0
      Jenkinsfile.upload_release_android
  10. 1
    0
      Jenkinsfile.upload_release_ios
  11. 2
    0
      Makefile
  12. 4
    4
      build.clj
  13. 1
    1
      components/src/status_im/ui/components/react.cljs
  14. 19
    0
      deployment/linux/.env
  15. 0
    0
      deployment/linux/usr/bin/.keep
  16. 0
    0
      deployment/linux/usr/lib/.keep
  17. 7
    0
      deployment/linux/usr/share/applications/StatusIm.desktop
  18. BIN
      deployment/linux/usr/share/icons/hicolor/1024x1024/apps/StatusIm.png
  19. 1
    1
      deps.edn
  20. 39
    0
      desktop/CMakeLists.txt
  21. 34
    0
      desktop/build.bat
  22. 32
    0
      desktop/build.sh
  23. 284
    0
      desktop/main.cpp
  24. 11
    0
      desktop/run-app.bat.in
  25. 73
    0
      desktop/run-app.sh.in
  26. 70
    0
      desktop_files/.re-natal
  27. 1
    0
      desktop_files/VERSION
  28. 12602
    0
      desktop_files/package-lock.json
  29. 83
    0
      desktop_files/package.json
  30. 60
    0
      doc/desktop/DevEnvSetup.md
  31. 136
    0
      doc/desktop/Troubleshooting.md
  32. 3
    2
      env/dev/env/config.cljs
  33. 2
    2
      env/dev/env/desktop/main.cljs
  34. 4
    4
      env/dev/figwheel.clj
  35. 4
    0
      env/prod/env/desktop/main.cljs
  36. 32
    24
      figwheel-bridge.js
  37. 0
    0
      mobile_files/VERSION
  38. 1736
    2207
      mobile_files/package-lock.json
  39. 0
    0
      mobile_files/package.json
  40. 64
    0
      modules/react-native-status/desktop/CMakeLists.txt
  41. 35
    0
      modules/react-native-status/desktop/FindGo.cmake
  42. 8
    0
      modules/react-native-status/desktop/build-status-go.bat
  43. 10
    0
      modules/react-native-status/desktop/build-status-go.sh
  44. 286
    0
      modules/react-native-status/desktop/rctstatus.cpp
  45. 76
    0
      modules/react-native-status/desktop/rctstatus.h
  46. 23
    0
      patches/metro+0.30.2.patch
  47. 24
    7
      project.clj
  48. 0
    0
      react-native/src/cljsjs/cljsjs/create_react_class.cljs
  49. 0
    0
      react-native/src/cljsjs/cljsjs/react.cljs
  50. 0
    0
      react-native/src/cljsjs/cljsjs/react/dom.cljs
  51. 0
    0
      react-native/src/cljsjs/cljsjs/react/dom/server.cljs
  52. 31
    0
      react-native/src/desktop/status_im/react_native/js_dependencies.cljs
  53. 11
    13
      react-native/src/mobile/status_im/react_native/js_dependencies.cljs
  54. 89
    0
      scripts/create-desktop-mac-bundle.sh
  55. 8
    0
      scripts/download-package-files.sh
  56. 48
    0
      scripts/prepare-for-platform.sh
  57. 2
    5
      src/status_im/desktop/core.cljs
  58. 1
    1
      src/status_im/native_module/impl/module.cljs
  59. 6
    0
      src/status_im/translations/en.cljs
  60. 3
    0
      src/status_im/ui/components/colors.cljs
  61. 8
    4
      src/status_im/ui/components/desktop/tabs.cljs
  62. 180
    103
      src/status_im/ui/components/icons/vector_icons.cljs
  63. 5
    3
      src/status_im/ui/components/text_input/styles.cljs
  64. 12
    0
      src/status_im/ui/screens/add_new/new_public_chat/subs.cljs
  65. 4
    1
      src/status_im/ui/screens/db.cljs
  66. 75
    0
      src/status_im/ui/screens/desktop/main/add_new/styles.cljs
  67. 86
    36
      src/status_im/ui/screens/desktop/main/add_new/views.cljs
  68. 116
    0
      src/status_im/ui/screens/desktop/main/chat/styles.cljs
  69. 74
    68
      src/status_im/ui/screens/desktop/main/chat/views.cljs
  70. 14
    0
      src/status_im/ui/screens/desktop/main/styles.cljs
  71. 87
    0
      src/status_im/ui/screens/desktop/main/tabs/home/styles.cljs
  72. 52
    22
      src/status_im/ui/screens/desktop/main/tabs/home/views.cljs
  73. 135
    0
      src/status_im/ui/screens/desktop/main/tabs/profile/styles.cljs
  74. 61
    28
      src/status_im/ui/screens/desktop/main/tabs/profile/views.cljs
  75. 7
    5
      src/status_im/ui/screens/desktop/main/views.cljs
  76. 3
    1
      src/status_im/ui/screens/desktop/views.cljs
  77. 1
    1
      src/status_im/ui/screens/events.cljs
  78. 1
    0
      src/status_im/ui/screens/home/styles.cljs
  79. 6
    1
      src/status_im/ui/screens/main_tabs/styles.cljs
  80. 40
    2
      src/status_im/ui/screens/profile/events.cljs
  81. 4
    2
      src/status_im/ui/screens/profile/subs.cljs
  82. 1
    0
      src/status_im/ui/screens/subs.cljs
  83. 5
    1
      src/status_im/utils/keychain/core.cljs
  84. 3
    1
      src/status_im/utils/keychain/events.cljs
  85. 12
    9
      src/status_im/utils/notifications.cljs
  86. 2
    0
      src/status_im/utils/platform.cljs
  87. 1
    1
      src/status_im/utils/styles.clj
  88. 125
    0
      ubuntu-server.js

+ 1
- 0
.gitattributes View File

@@ -1 +1,2 @@
*.pbxproj -text
*.patch eol=lf

+ 5
- 0
.gitignore View File

@@ -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

+ 2
- 1
Jenkinsfile View File

@@ -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)
}
}

+ 197
- 0
Jenkinsfile.desktopbuild View File

@@ -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
}
}
}
}
)

+ 1
- 0
Jenkinsfile.nightly View File

@@ -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

+ 1
- 0
Jenkinsfile.nightly_fastlane View File

@@ -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

+ 1
- 0
Jenkinsfile.parameters View File

@@ -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

+ 1
- 0
Jenkinsfile.release View File

@@ -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

+ 1
- 0
Jenkinsfile.upload_release_android View File

@@ -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

+ 1
- 0
Jenkinsfile.upload_release_ios View File

@@ -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
- 0
Makefile View File

@@ -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 ..

+ 4
- 4
build.clj View File

@@ -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

+ 1
- 1
components/src/status_im/ui/components/react.cljs View File

@@ -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"))

+ 19
- 0
deployment/linux/.env View File

@@ -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
deployment/linux/usr/bin/.keep View File


+ 0
- 0
deployment/linux/usr/lib/.keep View File


+ 7
- 0
deployment/linux/usr/share/applications/StatusIm.desktop View File

@@ -0,0 +1,7 @@
[Desktop Entry]
Type=Application
Name=StatusIm
Comment=StatusIm Desktop
Exec=StatusIm
Icon=StatusIm
Categories=Network;

BIN
deployment/linux/usr/share/icons/hicolor/1024x1024/apps/StatusIm.png View File


+ 1
- 1
deps.edn View File

@@ -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"}

+ 39
- 0
desktop/CMakeLists.txt View File

@@ -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
)


+ 34
- 0
desktop/build.bat View File

@@ -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 .

+ 32
- 0
desktop/build.sh View File

@@ -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

+ 284
- 0
desktop/main.cpp View File

@@ -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"

+ 11
- 0
desktop/run-app.bat.in View File

@@ -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@


+ 73
- 0
desktop/run-app.sh.in View File

@@ -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


+ 70
- 0
desktop_files/.re-natal View File

@@ -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"
}
}

+ 1
- 0
desktop_files/VERSION View File

@@ -0,0 +1 @@
0.0.1

+ 12602
- 0
desktop_files/package-lock.json
File diff suppressed because it is too large
View File


+ 83
- 0
desktop_files/package.json View File

@@ -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"
}
}

+ 60
- 0
doc/desktop/DevEnvSetup.md View File

@@ -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.

+ 136
- 0
doc/desktop/Troubleshooting.md View File

@@ -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
```


+ 3
- 2
env/dev/env/config.cljs View File

@@ -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"})

+ 2
- 2
env/dev/env/desktop/main.cljs View File

@@ -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
- 4
env/dev/figwheel.clj View File

@@ -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"

+ 4
- 0
env/prod/env/desktop/main.cljs View File

@@ -0,0 +1,4 @@
(ns env.desktop.main
(:require [status-im.desktop.core :as core]))

(core/init)

+ 32
- 24
figwheel-bridge.js View File

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


VERSION → mobile_files/VERSION View File


mobile_files/package-lock.json
File diff suppressed because it is too large
View File


package.json → mobile_files/package.json View File


+ 64
- 0
modules/react-native-status/desktop/CMakeLists.txt View File

@@ -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)

+ 35
- 0
modules/react-native-status/desktop/FindGo.cmake View File

@@ -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)

+ 8
- 0
modules/react-native-status/desktop/build-status-go.bat View File

@@ -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

+ 10
- 0
modules/react-native-status/desktop/build-status-go.sh View File

@@ -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

+ 286
- 0
modules/react-native-status/desktop/rctstatus.cpp View File

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

+ 76
- 0
modules/react-native-status/desktop/rctstatus.h View File

@@ -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

+ 23
- 0
patches/metro+0.30.2.patch View File

@@ -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'];

+ 24
- 7
project.clj View File

@@ -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]}}}}})

react-native/src/cljsjs/create_react_class.cljs → react-native/src/cljsjs/cljsjs/create_react_class.cljs View File


react-native/src/cljsjs/react.cljs → react-native/src/cljsjs/cljsjs/react.cljs View File


react-native/src/cljsjs/react/dom.cljs → react-native/src/cljsjs/cljsjs/react/dom.cljs View File


react-native/src/cljsjs/react/dom/server.cljs → react-native/src/cljsjs/cljsjs/react/dom/server.cljs View File


+ 31
- 0
react-native/src/desktop/status_im/react_native/js_dependencies.cljs View File

@@ -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 {})