Compare commits

..
Author SHA1 Message Date
Ibrahem Khalil 9d886a18e5 Merge branch 'develop' into 14620 2023-01-08 12:23:37 +02:00
Ibrahem Khalil 48cb50b8d5 Merge branch 'develop' into 14620 2022-12-30 20:39:58 +02:00
Ibrahem Khalil 70ca925144 Merge branch 'develop' into 14620 2022-12-28 19:13:29 +02:00
ibrkhalil 11961c37ad Clean 2022-12-28 19:12:46 +02:00
Ibrahem Khalil 98da40d28d Merge branch 'develop' into 14620 2022-12-26 18:21:53 +02:00
ibrahem 7abd425f91 Add spacing for cross button on Android 2022-12-26 12:43:50 +02:00
4418 changed files with 120054 additions and 170408 deletions
+169 -118
View File
@@ -1,55 +1,62 @@
legacy.status-im.utils.build/warning-handler status-im.utils.build/warning-handler
legacy.status-im.utils.build/get-current-sha status-im.utils.build/get-current-sha
status-im.constants/spacing-char status-im.chat.constants/spacing-char
status-im.constants/arg-wrapping-char status-im.chat.constants/arg-wrapping-char
legacy.status-im.ios.core/init status-im.ios.core/init
legacy.status-im.ui.components.camera/aspects status-im.ui.components.camera/aspects
legacy.status-im.ui.components.camera/capture-targets status-im.ui.components.camera/capture-targets
legacy.status-im.ui.components.camera/set-torch status-im.ui.components.camera/set-torch
legacy.status-im.ui.components.camera/request-access-ios status-im.ui.components.camera/request-access-ios
legacy.status-im.chat.models.message-content/stylings status-im.chat.models.message-content/stylings
legacy.status-im.chat.models.message-content/actions status-im.chat.models.message-content/actions
legacy.status-im.chat.models.message-content/blank-string status-im.chat.models.message-content/blank-string
legacy.status-im.chat.models.message-content/sorted-ranges status-im.chat.models.message-content/sorted-ranges
legacy.status-im.ethereum.mnemonic/words->passphrase status-im.ethereum.mnemonic/words->passphrase
native-module.core/listener status-im.native-module.core/listener
native-module.core/multiaccount-reset status-im.native-module.core/multiaccount-reset
native-module.core/extract-group-membership-signatures status-im.native-module.core/extract-group-membership-signatures
native-module.core/sign-group-membership status-im.native-module.core/sign-group-membership
native-module.core/update-mailservers status-im.native-module.core/update-mailservers
legacy.status-im.ethereum.abi-spec/bytes-to-hex status-im.ethereum.abi-spec/bytes-to-hex
legacy.status-im.android.core/init status-im.android.core/init
legacy.status-im.chat.models.message/transport-keys status-im.chat.models.message/transport-keys
legacy.status-im.utils.datetime/week status-im.utils.datetime/week
legacy.status-im.utils.datetime/time-ago status-im.utils.datetime/time-ago
legacy.status-im.utils.datetime/format-date status-im.utils.datetime/format-date
legacy.status-im.utils.datetime/get-ordinal-date status-im.utils.datetime/get-ordinal-date
reagent.dom/render reagent.dom/render
reagent.dom/unmount-component-at-node reagent.dom/unmount-component-at-node
reagent.dom/dom-node reagent.dom/dom-node
reagent.dom/force-update-all reagent.dom/force-update-all
legacy.status-im.multiaccounts.create.core/get-new-key-code status-im.multiaccounts.create.core/get-new-key-code
legacy.status-im.ethereum.decode/string status-im.ethereum.decode/string
legacy.status-im.ui.screens.network.views/mainnet? status-im.ui.screens.network.views/mainnet?
legacy.status-im.data-store.chats/event->string status-im.data-store.chats/event->string
legacy.status-im.mailserver.constants/seven-days status-im.mailserver.constants/seven-days
legacy.status-im.mailserver.constants/connection-timeout status-im.mailserver.constants/connection-timeout
legacy.status-im.hardwallet.card/install-applet status-im.hardwallet.card/install-applet
legacy.status-im.hardwallet.card/install-cash-applet status-im.hardwallet.card/install-cash-applet
legacy.status-im.multiaccount.login.data-test/all-contacts status-im.multiaccount.login.data-test/all-contacts
legacy.status-im.multiaccount.login.data-test/multiaccounts status-im.multiaccount.login.data-test/multiaccounts
legacy.status-im.multiaccount.login.data-test/get-chats status-im.multiaccount.login.data-test/get-chats
legacy.status-im.multiaccount.login.data-test/transport status-im.multiaccount.login.data-test/transport
legacy.status-im.multiaccount.login.data-test/topics status-im.multiaccount.login.data-test/topics
legacy.status-im.utils.utils/clear-timeout status-im.utils.utils/clear-timeout
legacy.status-im.utils.handlers/logged-in status-im.utils.handlers/logged-in
legacy.status-im.multiaccounts.model/credentials status-im.multiaccounts.model/credentials
legacy.status-im.multiaccounts.login.core/contract-fleet? status-im.multiaccounts.login.core/contract-fleet?
legacy.status-im.multiaccounts.login.core/fetch-nodes status-im.multiaccounts.login.core/fetch-nodes
status-im.config/rpc-networks-only? status-im.utils.config/rpc-networks-only?
status-im.config/waku-enabled? status-im.utils.config/waku-enabled?
legacy.status-im.utils.pairing/has-paired-installations? status-im.utils.pairing/has-paired-installations?
legacy.status-im.tribute-to-talk.core-test/user-cofx status-im.tribute-to-talk.core-test/user-cofx
quo.gesture-handler/tap-gesture-handler
quo.gesture-handler/pan-gesture-handler
quo.gesture-handler/long-press-gesture-handler
quo.gesture-handler/pure-native-button
quo.gesture-handler/createNativeWrapper
quo.gesture-handler/animated-raw-button
quo.gesture-handler/states
mocks.js-dependencies/action-button mocks.js-dependencies/action-button
mocks.js-dependencies/camera mocks.js-dependencies/camera
mocks.js-dependencies/dismiss-keyboard mocks.js-dependencies/dismiss-keyboard
@@ -78,36 +85,75 @@ mocks.js-dependencies/react-navigation-bottom-tabs
mocks.js-dependencies/react-native-haptic-feedback mocks.js-dependencies/react-native-haptic-feedback
mocks.js-dependencies/mock mocks.js-dependencies/mock
quo.previews.main/init quo.previews.main/init
legacy.status-im.chat.models.message-list-test/descending-range status-im.chat.models.message-list-test/descending-range
legacy.status-im.chat.models.message-list-test/random-range status-im.chat.models.message-list-test/random-range
legacy.status-im.ethereum.eip165/supports? status-im.ethereum.eip165/supports?
legacy.status-im.utils.hex/valid-hex? status-im.utils.hex/valid-hex?
legacy.status-im.multiaccounts.core/chat-send? status-im.multiaccounts.core/chat-send?
legacy.status-im.hardwallet.simulated-keycard/install-cash-applet status-im.hardwallet.simulated-keycard/install-cash-applet
legacy.status-im.hardwallet.simulated-keycard/sign-typed-data status-im.hardwallet.simulated-keycard/sign-typed-data
legacy.status-im.utils.core/safe-read-message-content status-im.utils.core/safe-read-message-content
legacy.status-im.ui.components.react/native-modules status-im.ui.components.react/native-modules
legacy.status-im.ui.components.react/progress-bar status-im.ui.components.react/progress-bar
react-native.fs/move-file status-im.utils.fs/move-file
react-native.fs/read-dir status-im.utils.fs/read-dir
react-native.fs/mkdir status-im.utils.fs/mkdir
react-native.fs/unlink status-im.utils.fs/unlink
react-native.fs/file-exists? status-im.utils.fs/file-exists?
legacy.status-im.ui.components.colors/white quo.animated/code
legacy.status-im.ui.components.colors/black quo.animated/eq
legacy.status-im.ui.components.core/animated-header quo.animated/neq
legacy.status-im.ui.components.core/safe-area-provider quo.animated/greater-or-eq
legacy.status-im.ui.components.core/safe-area-consumer quo.animated/not*
legacy.status-im.ui.components.core/safe-area-view quo.animated/or*
legacy.status-im.utils.universal-links.core/open! quo.animated/and*
legacy.status-im.transport.filters.core-test/member-2 quo.animated/add
legacy.status-im.ui.screens.chat.ttt/one-to-one-chat-description-container quo.animated/sub
legacy.status-im.ethereum.ens/ttl quo.animated/multiply
legacy.status-im.ethereum.ens/addr-hash quo.animated/abs
legacy.status-im.ethereum.ens/name-hash quo.animated/min*
legacy.status-im.ethereum.ens/ABI-hash quo.animated/max*
legacy.status-im.ethereum.ens/pubkey-hash quo.animated/set
legacy.status-im.network.core/get-network quo.animated/start-clock
quo.animated/stop-clock
quo.animated/bezier
quo.animated/linear
quo.animated/set-value
quo.animated/clock
quo.animated/debug
quo.animated/log
quo.animated/event
quo.animated/on-change
quo.animated/cond*
quo.animated/block
quo.animated/call*
quo.animated/timing
quo.animated/spring
quo.animated/clamp
quo.animated/with-spring
quo.animated/with-timing
quo.animated/re-timing
quo.design-system.colors/white
quo.design-system.colors/black
status-im.transport.core-test/messages
status-im.ethereum.core/sidechain?
status-im.ethereum.core/network-with-upstream-rpc?
status-im.ethereum.core/current-address
status-im.ethereum.core/network->network-name
status-im.ethereum.core/estimate-gas
quo.core/animated-header
quo.core/safe-area-provider
quo.core/safe-area-consumer
quo.core/safe-area-view
status-im.utils.universal-links.core/open!
status-im.transport.filters.core-test/member-2
status-im.ui.screens.chat.ttt/one-to-one-chat-description-container
status-im.ethereum.ens/ttl
status-im.ethereum.ens/addr-hash
status-im.ethereum.ens/name-hash
status-im.ethereum.ens/ABI-hash
status-im.ethereum.ens/pubkey-hash
status-im.network.core/get-network
status-im.constants/desktop-content-types status-im.constants/desktop-content-types
status-im.constants/blocks-per-hour status-im.constants/blocks-per-hour
status-im.constants/one-earth-day status-im.constants/one-earth-day
@@ -142,44 +188,49 @@ status-im.constants/debug-metrics
status-im.constants/scan-qr-code status-im.constants/scan-qr-code
status-im.constants/ipfs-proto-code status-im.constants/ipfs-proto-code
status-im.constants/swarm-proto-code status-im.constants/swarm-proto-code
legacy.status-im.multiaccounts.update.publisher/publish-update! status-im.multiaccounts.update.publisher/publish-update!
legacy.status-im.utils.async/task-queue status-im.utils.async/task-queue
legacy.status-im.utils.async/async-periodic-run! status-im.utils.async/async-periodic-run!
legacy.status-im.desktop.core/app-root status-im.desktop.core/app-root
legacy.status-im.desktop.core/init status-im.desktop.core/init
legacy.status-im.chat.models-test/test-db status-im.chat.models-test/test-db
legacy.status-im.ui.components.spacing/padding-vertical quo.design-system.spacing/padding-vertical
legacy.status-im.utils.money/percent-change status-im.utils.money/percent-change
status-im.utils.platform/isMacOs?
status-im.utils.platform/isNix?
status-im.utils.platform/isWin?
status-im.utils.platform/android-version>=
utils.debounce/clear-all utils.debounce/clear-all
legacy.status-im.transport.db/create-chat status-im.transport.db/create-chat
legacy.status-im.utils.priority-map/priority-map status-im.utils.priority-map/priority-map
legacy.status-im.utils.priority-map/priority-map-by status-im.utils.priority-map/priority-map-by
legacy.status-im.utils.priority-map/priority-map-keyfn status-im.utils.priority-map/priority-map-keyfn
legacy.status-im.utils.priority-map/empty-message-map status-im.utils.priority-map/empty-message-map
legacy.status-im.wallet.choose-recipient.core/use-default-eth-gas status-im.wallet.choose-recipient.core/use-default-eth-gas
legacy.status-im.ui.components.animation/decay status-im.ui.components.animation/decay
legacy.status-im.ui.components.animation/remove-all-listeners status-im.ui.components.animation/remove-all-listeners
legacy.status-im.ui.components.animation/stop-animation status-im.ui.components.animation/stop-animation
legacy.status-im.ui.components.animation/animated status-im.ui.components.animation/animated
legacy.status-im.ui.components.animation/add status-im.ui.components.animation/add
legacy.status-im.ui.components.animation/subtract status-im.ui.components.animation/subtract
legacy.status-im.ui.components.animation/get-layout status-im.ui.components.animation/get-layout
legacy.status-im.wallet.transactions-test/uri-query-data status-im.wallet.transactions-test/uri-query-data
legacy.status-im.utils.name/shortened-name quo.react-native/touchable-highlight
legacy.status-im.ui.components.button.haptic/trigger status-im.utils.name/shortened-name
legacy.status-im.contact.db/filter-dapps status-im.ui.components.button.haptic/trigger
legacy.status-im.contact.db/filter-group-contacts status-im.contact.db/filter-dapps
legacy.status-im.contact.db/legacy-pending? status-im.contact.db/filter-group-contacts
legacy.status-im.utils.transducers-test/preview-call-1 status-im.contact.db/legacy-pending?
legacy.status-im.utils.transducers-test/preview-call-2 status-im.utils.transducers-test/preview-call-1
legacy.status-im.utils.types/to-string status-im.utils.transducers-test/preview-call-2
legacy.status-im.chat.db/datemark? status-im.utils.types/to-string
legacy.status-im.chat.db/gap? status-im.chat.db/datemark?
legacy.status-im.chat.db/map->sorted-seq status-im.chat.db/gap?
legacy.status-im.utils.snoopy/status-module-filter status-im.chat.db/map->sorted-seq
legacy.status-im.utils.snoopy/websocket-filter status-im.utils.snoopy/status-module-filter
legacy.status-im.utils.snoopy/touches-filter status-im.utils.snoopy/websocket-filter
legacy.status-im.utils.snoopy/native-animation-filter status-im.utils.snoopy/touches-filter
legacy.status-im.utils.snoopy/keyboard-observer-filter status-im.utils.snoopy/native-animation-filter
legacy.status-im.utils.multihash/hex status-im.utils.snoopy/keyboard-observer-filter
legacy.status-im.utils.multihash/decode-array status-im.utils.multihash/hex
status-im.utils.multihash/decode-array
-1
View File
@@ -1 +0,0 @@
{:lint-as {babashka.fs/with-temp-dir clojure.core/let}}
-1
View File
@@ -1 +0,0 @@
{:hooks {:macroexpand {sci.core/copy-ns sci.core/copy-ns}}}
-9
View File
@@ -1,9 +0,0 @@
(ns sci.core)
(defmacro copy-ns
([ns-sym sci-ns]
`(copy-ns ~ns-sym ~sci-ns nil))
([ns-sym sci-ns opts]
`[(quote ~ns-sym)
~sci-ns
(quote ~opts)]))
+20 -73
View File
@@ -1,76 +1,23 @@
{:config-paths ["status-im"] {:lint-as {status-im.utils.views/defview clojure.core/defn
:lint-as {legacy.status-im.utils.views/defview clojure.core/defn status-im.utils.views/letsubs clojure.core/let
legacy.status-im.utils.views/letsubs clojure.core/let reagent.core/with-let clojure.core/let
reagent.core/with-let clojure.core/let status-im.utils.fx/defn clj-kondo.lint-as/def-catch-all
legacy.status-im.utils.fx/defn clj-kondo.lint-as/def-catch-all utils.re-frame/defn clj-kondo.lint-as/def-catch-all
utils.re-frame/defn clj-kondo.lint-as/def-catch-all quo.react/with-deps-check clojure.core/fn
quo.react/with-deps-check clojure.core/fn quo.previews.preview/list-comp clojure.core/for
quo.previews.preview/list-comp clojure.core/for status-im.utils.styles/def clojure.core/def
legacy.status-im.utils.styles/def clojure.core/def status-im.utils.styles/defn clojure.core/defn
legacy.status-im.utils.styles/defn clojure.core/defn test-helpers.unit/deftest-sub clojure.core/defn
test-helpers.unit/deftest-sub clojure.core/defn taoensso.tufte/defnp clojure.core/defn}
taoensso.tufte/defnp clojure.core/defn} :linters {:consistent-alias {:level :error
:linters {:case-duplicate-test {:level :error} :aliases {clojure.string string
:case-quoted-test {:level :error} clojure.set set
:case-symbol-test {:level :error} clojure.walk walk
:clj-kondo-config {:level :error} taoensso.timbre log}}
:cond-else {:level :error} :invalid-arity {:skip-args [status-im.utils.fx/defn utils.re-frame/defn]}
:consistent-alias {:level :error
:aliases {clojure.set set
clojure.string string
clojure.walk walk
malli.core malli
malli.dev.pretty malli.pretty
malli.dev.virhe malli.virhe
malli.error malli.error
malli.generator malli.generator
malli.transform malli.transform
malli.util malli.util
schema.core schema
taoensso.timbre log}}
:deprecated-namespace {:level :warning}
:docstring-blank {:level :error}
:equals-true {:level :error}
:inline-def {:level :error}
:invalid-arity {:skip-args [legacy.status-im.utils.fx/defn
utils.re-frame/defn]}
:loop-without-recur {:level :error}
:minus-one {:level :error}
:misplaced-docstring {:level :error}
:missing-body-in-when {:level :error}
:missing-clause-in-try {:level :error}
:missing-else-branch {:level :error}
:not-empty? {:level :error}
:plus-one {:level :error}
:redundant-do {:level :error}
:redundant-let {:level :error}
:refer-all {:level :error}
:shadowed-var {:level :error
;; We temporarily use :include to define an
;; allowlist of core Clojure vars. In the
;; future, as we progressively fix shadowed
;; vars, we should be able to delete this
;; option and lint all vars.
:exclude [type name]}
:single-operand-comparison {:level :error}
:syntax {:level :error}
:unbound-destructuring-default {:level :error}
:uninitialized-var {:level :error}
:unknown-require-option {:level :error}
:unreachable-code {:level :error}
:unresolved-namespace {:level :error}
;; TODO remove number when this is fixed ;; TODO remove number when this is fixed
;; https://github.com/borkdude/clj-kondo/issues/867 ;; https://github.com/borkdude/clj-kondo/issues/867
:unresolved-symbol {:exclude [PersistentPriorityMap.EMPTY :unresolved-symbol {:exclude [PersistentPriorityMap.EMPTY
number number
legacy.status-im.test-helpers/restore-app-db]} status-im.test-helpers/restore-app-db]}}
:unresolved-var {:level :error}
:unsorted-required-namespaces {:level :error}
:unused-alias {:level :warning}
:unused-binding {:level :error}
:unused-import {:level :error}
:unused-namespace {:level :error}
:unused-private-var {:level :error}
:unused-referred-var {:level :error}
:use {:level :error}}
:config-in-ns {mocks.js-dependencies {:linters {:clojure-lsp/unused-public-var {:level :off}}}}} :config-in-ns {mocks.js-dependencies {:linters {:clojure-lsp/unused-public-var {:level :off}}}}}
-2
View File
@@ -1,2 +0,0 @@
{:lint-as {malli.experimental/defn schema.core/defn}
:linters {:unresolved-symbol {:exclude [(malli.core/=>)]}}}
@@ -1,4 +0,0 @@
{:linters
{:unresolved-symbol
{:exclude [(cljs.test/is [match? thrown-match?])
(clojure.test/is [match? thrown-match?])]}}}
@@ -1,5 +0,0 @@
{:lint-as
{rewrite-clj.zip/subedit-> clojure.core/->
rewrite-clj.zip/subedit->> clojure.core/->>
rewrite-clj.zip/edit-> clojure.core/->
rewrite-clj.zip/edit->> clojure.core/->>}}
-8
View File
@@ -1,8 +0,0 @@
{:hooks
{:analyze-call
{utils.i18n/label utils.i18n/label
test-helpers.component/get-all-by-translation-text utils.i18n/label
test-helpers.component/get-by-translation-text utils.i18n/label
test-helpers.component/query-all-by-translation-text utils.i18n/label
test-helpers.component/query-by-translation-text utils.i18n/label}}
:linters {:status-im.linter/invalid-translation-keyword {:level :error}}}
-26
View File
@@ -1,26 +0,0 @@
(ns utils.i18n
(:require [clj-kondo.hooks-api :as hooks]))
(defn label
"Verify call to `utils.i18n/label` pass the translation keyword qualified with `t`."
[{:keys [node]}]
(let [[_ translation-key-node & _] (:children node)]
(when (and (hooks/keyword-node? translation-key-node)
(not= "t" (-> translation-key-node hooks/sexpr namespace)))
(hooks/reg-finding! (assoc (meta translation-key-node)
:message "Translation keyword should be qualified with \"t\""
:type :status-im.linter/invalid-translation-keyword)))))
(comment
;; Valid
(label {:node (hooks/parse-string "(i18n/label :t/foo {:var \"hello\"})")
:cljc false
:lang :cljs
:filename ""
:config {}
:ns ""
:context nil})
;; Invalid
(label {:node (hooks/parse-string "(i18n/label :foo)")})
)
-1
View File
@@ -1 +0,0 @@
{:hooks {:analyze-call {taoensso.encore/defalias taoensso.encore/defalias}}}
@@ -1,16 +0,0 @@
(ns taoensso.encore
(:require
[clj-kondo.hooks-api :as hooks]))
(defn defalias [{:keys [node]}]
(let [[sym-raw src-raw] (rest (:children node))
src (if src-raw src-raw sym-raw)
sym (if src-raw
sym-raw
(symbol (name (hooks/sexpr src))))]
{:node (with-meta
(hooks/list-node
[(hooks/token-node 'def)
(hooks/token-node (hooks/sexpr sym))
(hooks/token-node (hooks/sexpr src))])
(meta src))}))
+37
View File
@@ -0,0 +1,37 @@
module.exports = {
"testRunner": "jest",
"testRegex": "\\.visual\\.js$",
"runner-config": "visual-test/config.json",
"devices": {
"simulator": {
"type": "ios.simulator",
"device": {
"type": "iPhone 11 Pro"
}
}
},
"apps": {
"ios.release": {
"name": "StatusIm",
"type": "ios.app",
"binaryPath": "ios/build/Build/Products/Release-iphonesimulator/StatusIm.app",
"build": "make release-ios"
},
"ios.debug": {
"name": "StatusIm",
"type": "ios.app",
"binaryPath": process.env.TEST_BINARY_PATH,
"build": "make run-ios SIMULATOR='iPhone 11 Pro'"
}
},
"configurations": {
"ios.sim.release": {
"device": "simulator",
"app": "ios.release"
},
"ios.sim.debug": {
"device": "simulator",
"app": "ios.debug"
}
}
}
+1 -2
View File
@@ -22,6 +22,7 @@ KEYCARD_TEST_MENU=0
QR_READ_TEST_MENU=1 QR_READ_TEST_MENU=1
ENABLE_ROOT_ALERT=1 ENABLE_ROOT_ALERT=1
ENABLE_QUO_PREVIEW=1 ENABLE_QUO_PREVIEW=1
MAX_IMAGES_BATCH=5
APN_TOPIC=im.status.ethereum.pr APN_TOPIC=im.status.ethereum.pr
COMMUNITIES_ENABLED=1 COMMUNITIES_ENABLED=1
DATABASE_MANAGEMENT_ENABLED=1 DATABASE_MANAGEMENT_ENABLED=1
@@ -32,5 +33,3 @@ TWO_MINUTES_SYNCING=1
SWAP_ENABLED=1 SWAP_ENABLED=1
STICKERS_TEST_ENABLED=1 STICKERS_TEST_ENABLED=1
LOCAL_PAIRING_ENABLED=1 LOCAL_PAIRING_ENABLED=1
TEST_STATEOFUS=1
FAST_CREATE_COMMUNITY_ENABLED=1
+1 -1
View File
@@ -21,6 +21,7 @@ COMMANDS_ENABLED=1
KEYCARD_TEST_MENU=1 KEYCARD_TEST_MENU=1
QR_READ_TEST_MENU=1 QR_READ_TEST_MENU=1
ENABLE_ROOT_ALERT=0 ENABLE_ROOT_ALERT=0
MAX_IMAGES_BATCH=5
APN_TOPIC=im.status.ethereum.pr APN_TOPIC=im.status.ethereum.pr
VERIFY_TRANSACTION_CHAIN_ID=5 VERIFY_TRANSACTION_CHAIN_ID=5
VERIFY_ENS_CHAIN_ID=5 VERIFY_ENS_CHAIN_ID=5
@@ -32,4 +33,3 @@ DELETE_MESSAGE_ENABLED=1
TWO_MINUTES_SYNCING=1 TWO_MINUTES_SYNCING=1
STICKERS_TEST_ENABLED=1 STICKERS_TEST_ENABLED=1
LOCAL_PAIRING_ENABLED=1 LOCAL_PAIRING_ENABLED=1
FAST_CREATE_COMMUNITY_ENABLED=1
+1 -1
View File
@@ -26,6 +26,7 @@ VERIFY_TRANSACTION_CHAIN_ID=5
VERIFY_ENS_CHAIN_ID=5 VERIFY_ENS_CHAIN_ID=5
TEST_STATEOFUS=1 TEST_STATEOFUS=1
BLANK_PREVIEW=0 BLANK_PREVIEW=0
MAX_IMAGES_BATCH=5
DATABASE_MANAGEMENT_ENABLED=1 DATABASE_MANAGEMENT_ENABLED=1
COMMUNITIES_ENABLED=1 COMMUNITIES_ENABLED=1
COMMUNITIES_MANAGEMENT_ENABLED=1 COMMUNITIES_MANAGEMENT_ENABLED=1
@@ -34,4 +35,3 @@ TWO_MINUTES_SYNCING=1
ENABLE_QUO_PREVIEW=1 ENABLE_QUO_PREVIEW=1
STICKERS_TEST_ENABLED=1 STICKERS_TEST_ENABLED=1
LOCAL_PAIRING_ENABLED=1 LOCAL_PAIRING_ENABLED=1
FAST_CREATE_COMMUNITY_ENABLED=1
+1 -1
View File
@@ -17,8 +17,8 @@ RPC_NETWORKS_ONLY=0
PARTITIONED_TOPIC=0 PARTITIONED_TOPIC=0
CONTRACT_NODES=1 CONTRACT_NODES=1
ENABLE_ROOT_ALERT=1 ENABLE_ROOT_ALERT=1
MAX_IMAGES_BATCH=5
BLANK_PREVIEW=0 BLANK_PREVIEW=0
COMMUNITIES_ENABLED=1 COMMUNITIES_ENABLED=1
DATABASE_MANAGEMENT_ENABLED=1 DATABASE_MANAGEMENT_ENABLED=1
DELETE_MESSAGE_ENABLED=1 DELETE_MESSAGE_ENABLED=1
FAST_CREATE_COMMUNITY_ENABLED=0
-1
View File
@@ -19,4 +19,3 @@ ENABLE_ROOT_ALERT=1
MAX_IMAGES_BATCH=1 MAX_IMAGES_BATCH=1
DELETE_MESSAGE_ENABLED=1 DELETE_MESSAGE_ENABLED=1
COLLECTIBLES_ENABLED=1 COLLECTIBLES_ENABLED=1
FAST_CREATE_COMMUNITY_ENABLED=0
+3 -3
View File
@@ -1,4 +1,4 @@
module.exports = { module.exports = {
root: true, root: true,
extends: '@react-native', extends: '@react-native-community',
}; };
+1 -1
View File
@@ -43,4 +43,4 @@ As a <user|developer|...>, I want to <task> so that <goal>.
[comment]: # (if on Android please replicate bug whilst running adb logcat) [comment]: # (if on Android please replicate bug whilst running adb logcat)
``` ```
... ...
``` ```
+5 -4
View File
@@ -1,8 +1,8 @@
--- ---
name: MVPBug Report name: Bug Report
about: MVPBug Report about: Bug Report
title: '' title: ''
labels: 'E:Mobile Bug MVP' labels: bug
assignees: '' assignees: ''
--- ---
@@ -22,7 +22,8 @@ assignees: ''
### Reproduction ### Reproduction
1. 1) Open Status
2)
### Additional Information ### Additional Information
-30
View File
@@ -1,30 +0,0 @@
---
name: Wont fix Report
about: to facilitate future handling, identify and address non-urgent issues that won't be prioritized in the near future
title: ''
labels: likely_wont_fix
assignees: ''
---
## Problem
#### Expected behavior
#### Actual behavior
### Reproduction
1.
### Additional Information
- Status version: release
- Operating System: Android, iOS
[comment]: # (Please, add logs/notes if necessary)
-6
View File
@@ -63,10 +63,4 @@ Documentation change PR (review please): https://github.com/status-im/status.im/
<!-- (PRs will only be accepted if squashed into single commit.) --> <!-- (PRs will only be accepted if squashed into single commit.) -->
### Before and after screenshots comparison
| Figma (if available) | iOS (if available) | Android (if available)
| --- | --- | --- |
| Please embed Image/Video here of the before and after. | Please embed Image/Video here of the before and after. | Please embed Image/Video here of the before and after. |
status: ready <!-- Can be ready or wip --> status: ready <!-- Can be ready or wip -->
+1
View File
@@ -5,6 +5,7 @@ project-board:
min-reviewers: 1 min-reviewers: 1
tested-pr-label-name: 'Tested - Issues' tested-pr-label-name: 'Tested - Issues'
contributor-column-name: 'CONTRIBUTOR' contributor-column-name: 'CONTRIBUTOR'
to-rebase-column-name: 'TO REBASE'
review-column-name: 'REVIEW' review-column-name: 'REVIEW'
test-column-name: 'E2E Tests' test-column-name: 'E2E Tests'
+3 -13
View File
@@ -7,7 +7,6 @@
# Xcode # Xcode
# #
/ios/.xcode.env.local
/component-spec /component-spec
result/ result/
build/ build/
@@ -36,10 +35,6 @@ project.xcworkspace
**/android/.project **/android/.project
**/android/.settings/org.eclipse.buildship.core.prefs **/android/.settings/org.eclipse.buildship.core.prefs
local.properties local.properties
*.hprof
.cxx/
*.keystore
!debug.keystore
# Atom # Atom
.tags* .tags*
@@ -105,8 +100,9 @@ Statusgo.xcframework
#ios #ios
/ios/Pods/ /ios/Pods/
/ios/logs/
/ios/StatusIm.xcworkspace /ios/StatusIm.xcworkspace
/ios/react-native-xcode.log
/ios/set_xcode_version.log
.ruby-version .ruby-version
status-e2e/ status-e2e/
@@ -187,10 +183,4 @@ test/appium/tests/users.py
/.calva/ /.calva/
## component-tests ## component-tests
*.log *.log
## local xcode env introduced in react-native 0.69
.xcode.env.local
## git hooks
lefthook.yml
-1
View File
@@ -1 +0,0 @@
{:clean {:ns-inner-blocks-indentation :keep}}
+4 -4
View File
@@ -1,10 +1,10 @@
{ {
"include": [ "include": [
"target/test/legacy/status_im/**" "target/test/status_im/**"
], ],
"exclude": [ "exclude": [
"target/test/legacy/status_im/test/**", "target/test/status_im/test/**",
"target/test/legacy/status_im/ui/**" "target/test/status_im/ui/**"
], ],
"report-dir": "./coverage-report", "report-dir": "./coverage-report",
"all": true, "all": true,
@@ -14,4 +14,4 @@
"exclude-after-remap": false, "exclude-after-remap": false,
"extension": [".js"], "extension": [".js"],
"reporter": ["lcovonly"] "reporter": ["lcovonly"]
} }
-10
View File
@@ -1,10 +0,0 @@
*
!*.js
!*/
*.clj-kondo
*.shadow-cljs
modules
result
target
component-spec
/app
+5 -7
View File
@@ -1,9 +1,7 @@
module.exports = { module.exports = {
arrowParens: 'always', bracketSpacing: false,
printWidth: 120, bracketSameLine: true,
semi: true, singleQuote: true,
singleQuote: true, trailingComma: 'all',
tabWidth: 2, tabWidth: 4,
trailingComma: 'all',
useTabs: false,
}; };
-12
View File
@@ -1,12 +0,0 @@
{
"editor.formatOnSave": true,
"clojure.format.enable": false,
"[clojure]": {
"editor.defaultFormatter": "rflagreca.vscode-clj-zprint"
},
"vscode-clj-zprint.IgnoreExternalFiles": false,
"vscode-clj-zprint.CommunityFormatting": false,
"vscode-clj-zprint.OptionsMap": "",
"vscode-clj-zprint.width": "",
"vscode-clj-zprint.Styles.UseOnlyTheseStyles": false
}
+15 -27
View File
@@ -1,47 +1,35 @@
;; -*- mode: clojure -*- ;; -*- mode: clojure -*-
;; vi: ft=clojure ;; vi: ft=clojure
{:width 105 {:width 105
:remove {:fn-force-nl #{:noarg1-body}} :style [;; community style
;; https://github.com/kkinnear/zprint/blob/main/doc/reference.md#community
:community
:style ;; no comma in map
[;; community style https://github.com/kkinnear/zprint/blob/main/doc/reference.md#community :no-comma
:community
;; no comma in map :custom-justify
:no-comma
:custom-justify ;; respect all newlines
;; https://github.com/kkinnear/zprint/blob/main/doc/reference.md#respect-nl
;; respect all newlines https://github.com/kkinnear/zprint/blob/main/doc/reference.md#respect-nl :respect-nl
:respect-nl
;; respect blank line https://github.com/kkinnear/zprint/blob/main/doc/reference.md#respect-bl
:respect-bl
;; hang multiline left-hand-thing https://github.com/kkinnear/zprint/issues/273
:multi-lhs-hang]
;; respect blank line
;; https://github.com/kkinnear/zprint/blob/main/doc/reference.md#respect-bl
:respect-bl]
:fn-map :fn-map
{"reg-sub" :arg1-pair {"reg-sub" :arg1-pair
"h/describe" :arg1-body "h/describe" :arg1-body
"h/describe-skip" :arg1-body
"h/describe-only" :arg1-body
"h/test" :arg1-body "h/test" :arg1-body
"h/test-skip" :arg1-body
"h/test-only" :arg1-body
"global.describe" :arg1-body "global.describe" :arg1-body
"global.test" :arg1-body "global.test" :arg1-body
"list-comp" :binding "list-comp" :binding
"defview" :arg1-body "defview" :arg1-body
"letsubs" :binding "letsubs" :binding
"with-let" "let"
"reg-event-fx" :arg1-pair
"reg-fx" :arg1-pair
"testing" :arg1-body "testing" :arg1-body
"deftest-sub" :arg1-body "deftest-sub" :arg1-body
"wait-for" :arg1-body "wait-for" :arg1-body
"with-deps-check" :arg1-body "with-deps-check" :arg1-body
"schema/=>" :arg1-body
"->" [:noarg1-body "->" [:noarg1-body
{:list {:constant-pair? false :force-nl? false} {:list {:constant-pair? false :force-nl? false}
:next-inner-restore [[:list :constant-pair?]]}] :next-inner-restore [[:list :constant-pair?]]}]
@@ -50,9 +38,9 @@
"assoc-some" "assoc" "assoc-some" "assoc"
"conj-when" "conj" "conj-when" "conj"
"conj-some" "conj"} "conj-some" "conj"}
:remove {:fn-force-nl #{:noarg1-body}}
:style-map :style-map
{:no-comma {:map {:comma? false}} {:no-comma {:map {:comma? false}}
:custom-justify :custom-justify
{:doc "Justify everything using pre-1.1.2 approach" {:doc "Justify everything using pre-1.1.2 approach"
:binding {:justify? true :justify {:max-variance 1000}} :binding {:justify? true :justify {:max-variance 1000}}
+73 -130
View File
@@ -1,4 +1,4 @@
.PHONY: nix-add-gcroots clean nix-clean run-metro test release _list _fix-node-perms _tmpdir-rm .PHONY: nix-add-gcroots clean nix-clean run-metro test release _list _fix-node-perms _tmpdir-mk _tmpdir-rm _install-hooks
help: SHELL := /bin/sh help: SHELL := /bin/sh
help: ##@other Show this help help: ##@other Show this help
@@ -14,17 +14,17 @@ WHITE := $(shell tput -Txterm setaf 7)
YELLOW := $(shell tput -Txterm setaf 3) YELLOW := $(shell tput -Txterm setaf 3)
RESET := $(shell tput -Txterm sgr0) RESET := $(shell tput -Txterm sgr0)
HELP_FUN = \ HELP_FUN = \
%help; \ %help; \
while(<>) { push @{$$help{$$2 // 'options'}}, [$$1, $$3] if /^([a-zA-Z\-]+)\s*:.*\#\#(?:@([a-zA-Z\-]+))?\s(.*)$$/ }; \ while(<>) { push @{$$help{$$2 // 'options'}}, [$$1, $$3] if /^([a-zA-Z\-]+)\s*:.*\#\#(?:@([a-zA-Z\-]+))?\s(.*)$$/ }; \
print "Usage: make [target]\n\nSee STARTING_GUIDE.md for more info.\n\n"; \ print "Usage: make [target]\n\nSee STARTING_GUIDE.md for more info.\n\n"; \
for (sort keys %help) { \ for (sort keys %help) { \
print "${WHITE}$$_:${RESET}\n"; \ print "${WHITE}$$_:${RESET}\n"; \
for (@{$$help{$$_}}) { \ for (@{$$help{$$_}}) { \
$$sep = " " x (32 - length $$_->[0]); \ $$sep = " " x (32 - length $$_->[0]); \
print " ${YELLOW}$$_->[0]${RESET}$$sep${GREEN}$$_->[1]${RESET}\n"; \ print " ${YELLOW}$$_->[0]${RESET}$$sep${GREEN}$$_->[1]${RESET}\n"; \
}; \ }; \
print "\n"; \ print "\n"; \
} }
HOST_OS := $(shell uname | tr '[:upper:]' '[:lower:]') HOST_OS := $(shell uname | tr '[:upper:]' '[:lower:]')
# This can come from Jenkins # This can come from Jenkins
@@ -42,14 +42,11 @@ export NODE_OPTIONS += --openssl-legacy-provider
export KEYSTORE_PATH ?= $(HOME)/.gradle/status-im.keystore export KEYSTORE_PATH ?= $(HOME)/.gradle/status-im.keystore
# Our custom config is located in nix/nix.conf # Our custom config is located in nix/nix.conf
export NIX_USER_CONF_FILES = $(PWD)/nix/nix.conf export NIX_CONF_DIR = $(PWD)/nix
# Location of symlinks to derivations that should not be garbage collected # Location of symlinks to derivations that should not be garbage collected
export _NIX_GCROOTS = /nix/var/nix/gcroots/per-user/$(USER)/status-mobile export _NIX_GCROOTS = /nix/var/nix/gcroots/per-user/$(USER)/status-mobile
# Defines which variables will be kept for Nix pure shell, use semicolon as divider # Defines which variables will be kept for Nix pure shell, use semicolon as divider
export _NIX_KEEP ?= TMPDIR,BUILD_ENV,\ export _NIX_KEEP ?= TMPDIR,BUILD_ENV,STATUS_GO_SRC_OVERRIDE
BUILD_TYPE,BUILD_NUMBER,COMMIT_HASH,\
ANDROID_GRADLE_OPTS,ANDROID_ABI_SPLIT,ANDROID_ABI_INCLUDE,\
STATUS_GO_SRC_OVERRIDE,STATUS_GO_IPFS_GATEWAY_URL
# Useful for Android release builds # Useful for Android release builds
TMP_BUILD_NUMBER := $(shell ./scripts/version/gen_build_no.sh | cut -c1-10) TMP_BUILD_NUMBER := $(shell ./scripts/version/gen_build_no.sh | cut -c1-10)
@@ -84,10 +81,6 @@ nix-gc-protected:
@echo -e "$(YELLOW)The following paths are protected:$(RESET)" && \ @echo -e "$(YELLOW)The following paths are protected:$(RESET)" && \
ls -1 $(_NIX_GCROOTS) | sed 's/^/ - /' ls -1 $(_NIX_GCROOTS) | sed 's/^/ - /'
nix-upgrade: SHELL := /bin/sh
nix-upgrade: ##@nix Upgrade Nix interpreter to current version.
nix/scripts/upgrade.sh
nix-gc: export TARGET := nix nix-gc: export TARGET := nix
nix-gc: nix-gc-protected ##@nix Garbage collect all packages older than 20 days from /nix/store nix-gc: nix-gc-protected ##@nix Garbage collect all packages older than 20 days from /nix/store
nix-store --gc nix-store --gc
@@ -108,7 +101,7 @@ nix-update-clojure: export TARGET := clojure
nix-update-clojure: ##@nix Update maven Nix expressions based on current clojure setup nix-update-clojure: ##@nix Update maven Nix expressions based on current clojure setup
nix/deps/clojure/generate.sh nix/deps/clojure/generate.sh
nix-update-gems: export TARGET := fastlane nix-update-gems: export TARGET := default
nix-update-gems: ##@nix Update Ruby gems in fastlane/Gemfile.lock and fastlane/gemset.nix nix-update-gems: ##@nix Update Ruby gems in fastlane/Gemfile.lock and fastlane/gemset.nix
fastlane/update.sh fastlane/update.sh
@@ -125,11 +118,10 @@ _fix-node-perms: ##@prepare Fix permissions so that directory can be cleaned
$(shell test -d node_modules && chmod -R 744 node_modules) $(shell test -d node_modules && chmod -R 744 node_modules)
$(shell test -d node_modules.tmp && chmod -R 744 node_modules.tmp) $(shell test -d node_modules.tmp && chmod -R 744 node_modules.tmp)
$(TMPDIR): SHELL := /bin/sh _tmpdir-mk: SHELL := /bin/sh
$(TMPDIR): ##@prepare Create a TMPDIR for temporary files _tmpdir-mk: ##@prepare Create a TMPDIR for temporary files
@mkdir -p "$(TMPDIR)" @mkdir -p "$(TMPDIR)"
# Make sure TMPDIR exists every time make is called # Make sure TMPDIR exists every time make is called
_tmpdir-mk: $(TMPDIR)
-include _tmpdir-mk -include _tmpdir-mk
_tmpdir-rm: SHELL := /bin/sh _tmpdir-rm: SHELL := /bin/sh
@@ -162,7 +154,7 @@ pod-install: ##@prepare Run 'pod install' to install podfiles and update Podfile
update-fleets: ##@prepare Download up-to-date JSON file with current fleets state update-fleets: ##@prepare Download up-to-date JSON file with current fleets state
curl -s https://fleets.status.im/ \ curl -s https://fleets.status.im/ \
| sed 's/"warning": "/"warning": "DO NOT EDIT! /' \ | jq --indent 4 --sort-keys . \
> resources/config/fleets.json > resources/config/fleets.json
$(KEYSTORE_PATH): export TARGET := keytool $(KEYSTORE_PATH): export TARGET := keytool
@@ -224,20 +216,24 @@ release-android: keystore build-android ##@build Build signed Android APK
@scripts/sign-android.sh result/app-release-unsigned.apk @scripts/sign-android.sh result/app-release-unsigned.apk
release-ios: export TARGET := ios release-ios: export TARGET := ios
release-ios: export IOS_STATUS_GO_TARGETS := ios/arm64
release-ios: export BUILD_ENV ?= prod release-ios: export BUILD_ENV ?= prod
release-ios: watchman-clean ios-clean jsbundle ##@build Build release for iOS release release-ios: watchman-clean ##@build Build release for iOS release
xcodebuild \ @git clean -dxf -f target/ios && \
-scheme StatusIm \ $(MAKE) jsbundle-ios && \
-configuration Release \ xcodebuild -workspace ios/StatusIm.xcworkspace -scheme StatusIm -configuration Release -destination 'generic/platform=iOS' -UseModernBuildSystem=N clean archive
-workspace ios/StatusIm.xcworkspace \
-destination 'generic/platform=iOS' \
-UseModernBuildSystem=N clean archive
jsbundle: SHELL := /bin/sh jsbundle-android: SHELL := /bin/sh
jsbundle: export BUILD_ENV ?= prod jsbundle-android: export TARGET := android
jsbundle: ##@build Build JavaScript and Clojurescript bundle for iOS and Android jsbundle-android: export BUILD_ENV ?= prod
nix/scripts/build.sh targets.mobile.jsbundle jsbundle-android: ##@jsbundle Compile JavaScript and Clojurescript into app directory
# Call nix-build to build the 'targets.mobile.android.jsbundle' attribute and copy the.js files to the project root
nix/scripts/build.sh targets.mobile.android.jsbundle && \
mv result/*.js ./
jsbundle-ios: export TARGET := ios
jsbundle-ios: export BUILD_ENV ?= prod
jsbundle-ios: ##@jsbundle Compile JavaScript and Clojure into index.ios.js
yarn shadow-cljs release mobile
#-------------- #--------------
# status-go lib # status-go lib
@@ -273,134 +269,85 @@ run-re-frisk: ##@run Start re-frisk server
# TODO: Migrate this to a Nix recipe, much the same way as nix/mobile/android/targets/release-android.nix # TODO: Migrate this to a Nix recipe, much the same way as nix/mobile/android/targets/release-android.nix
run-android: export TARGET := android run-android: export TARGET := android
# INFO: If it's empty (no devices attached, parsing issues, script error) - for Nix it's the same as not set.
run-android: export ANDROID_ABI_INCLUDE ?= $(shell ./scripts/adb_devices_abis.sh)
run-android: ##@run Build Android APK and start it on the device run-android: ##@run Build Android APK and start it on the device
npx react-native run-android --appIdSuffix debug npx react-native run-android --appIdSuffix debug
SIMULATOR=iPhone 13 SIMULATOR=iPhone 13
# TODO: fix IOS_STATUS_GO_TARGETS to be either amd64 or arm64 when RN is upgraded
run-ios: export TARGET := ios run-ios: export TARGET := ios
run-ios: export IOS_STATUS_GO_TARGETS := ios/arm64;iossimulator/amd64
run-ios: ##@run Build iOS app and start it in a simulator/device run-ios: ##@run Build iOS app and start it in a simulator/device
ifneq ("$(SIMULATOR)", "") ifneq ("$(SIMULATOR)", "")
npx react-native run-ios --simulator="$(SIMULATOR)" | xcbeautify npx react-native run-ios --simulator="$(SIMULATOR)"
else else
npx react-native run-ios | xcbeautify npx react-native run-ios
endif endif
show-ios-devices: ##@other shows connected ios device and its name
xcrun xctrace list devices
# TODO: fix IOS_STATUS_GO_TARGETS to be either amd64 or arm64 when RN is upgraded
run-ios-device: export TARGET := ios
run-ios-device: export IOS_STATUS_GO_TARGETS := ios/arm64;iossimulator/amd64
run-ios-device: ##@run iOS app and start it on a connected device by its name
ifndef DEVICE_NAME
$(error Usage: make run-ios-device DEVICE_NAME=your-device-name)
endif
react-native run-ios --device "$(DEVICE_NAME)"
#-------------- #--------------
# Tests # Tests
#-------------- #--------------
# Get all clojure files, including untracked, excluding removed lint: export TARGET := default
define find_all_clojure_files
$$(comm -23 <(sort <(git ls-files --cached --others --exclude-standard)) <(sort <(git ls-files --deleted)) | grep -E '((\.clj-kondo\/status-im)|(src).*\.clj[sc]?$$)|((\.clj-kondo\/(status-im|config))|(src).*\.edn$$)|shadow-cljs\.edn')
endef
lint: export TARGET := clojure
lint: export CLJ_LINTER_PRINT_WARNINGS ?= false
lint: ##@test Run code style checks lint: ##@test Run code style checks
@sh scripts/lint/re-frame-in-quo-components.sh && \ sh scripts/lint-re-frame-in-quo-components.sh && \
sh scripts/lint/direct-require-component-outside-quo.sh && \ clj-kondo --config .clj-kondo/config.edn --cache false --lint src && \
sh scripts/lint/require-i18n-resource-first.sh && \ ALL_CLOJURE_FILE=$$(git ls-files | grep -e \.clj$$ -e \.cljs$$ -e \.cljc$$ -e \.edn$$) && \
clj-kondo --config .clj-kondo/config.edn --cache false --fail-level error --lint src $(if $(filter $(CLJ_LINTER_PRINT_WARNINGS),true),,| grep -v ': warning: ') && \ zprint '{:search-config? true}' -sfc $$ALL_CLOJURE_FILE
ALL_CLOJURE_FILES=$(call find_all_clojure_files) && \
scripts/lint/translations.clj && \
zprint '{:search-config? true}' -sfc $$ALL_CLOJURE_FILES && \
sh scripts/lint/trailing-newline.sh && \
node_modules/.bin/prettier --write .
# NOTE: We run the linter twice because of https://github.com/kkinnear/zprint/issues/271 lint-fix: export TARGET := default
lint-fix: export TARGET := clojure
lint-fix: ##@test Run code style checks and fix issues lint-fix: ##@test Run code style checks and fix issues
ALL_CLOJURE_FILES=$(call find_all_clojure_files) && \ ALL_CLOJURE_FILE=$$(git ls-files | grep -e \.clj$$ -e \.cljs$$ -e \.cljc$$ -e \.edn$$) && \
zprint '{:search-config? true}' -sw $$ALL_CLOJURE_FILES && \ zprint '{:search-config? true}' -sw $$ALL_CLOJURE_FILE && \
zprint '{:search-config? true}' -sw $$ALL_CLOJURE_FILES && \ zprint '{:search-config? true}' -sw $$ALL_CLOJURE_FILE
clojure-lsp --ns-exclude-regex ".*/\.clj-kondo/.*|.*/src/status_im/core\.cljs|.*/src/test_helpers/component_tests_preload\.cljs$$" clean-ns && \
sh scripts/lint/trailing-newline.sh --fix && \
node_modules/.bin/prettier --write .
shadow-server: export TARGET := clojure shadow-server: export TARGET := clojure
shadow-server:##@ Start shadow-cljs in server mode for watching shadow-server:##@ Start shadow-cljs in server mode for watching
yarn shadow-cljs server yarn shadow-cljs server
_test-clojure: export TARGET := clojure test-watch: export TARGET := clojure
_test-clojure: export WATCH ?= false test-watch: ##@ Watch tests and re-run no changes to cljs files
_test-clojure: yarn install
ifeq ($(WATCH), true) nodemon --exec 'yarn shadow-cljs compile mocks && yarn shadow-cljs compile test && node --require ./test-resources/override.js target/test/test.js' -e cljs
yarn install && \
yarn shadow-cljs compile mocks && \
nodemon --exec "yarn shadow-cljs compile test && node --require ./test-resources/override.js $$SHADOW_OUTPUT_TO" -e cljs
else
yarn install && \
yarn shadow-cljs compile mocks && \
yarn shadow-cljs compile test && \
node --require ./test-resources/override.js "$$SHADOW_OUTPUT_TO"
endif
test: export SHADOW_OUTPUT_TO := target/test/test.js test-watch-for-repl: export TARGET := clojure
test: export SHADOW_NS_REGEXP := .*-test$$ test-watch-for-repl: ##@ Watch tests and support REPL connections
test: ##@test Run all Clojure tests
test: _test-clojure
test-watch-for-repl: export SHADOW_OUTPUT_TO := target/test/test.js
test-watch-for-repl: export SHADOW_NS_REGEXP := .*-test$$
test-watch-for-repl: ##@test Watch all Clojure tests and support REPL connections
yarn install yarn install
rm -f target/test/test.js rm -f target/test/test.js
yarn shadow-cljs compile mocks && \
concurrently --kill-others --prefix-colors 'auto' --names 'build,repl' \ concurrently --kill-others --prefix-colors 'auto' --names 'build,repl' \
'yarn shadow-cljs watch test --verbose' \ 'yarn shadow-cljs compile mocks && yarn shadow-cljs watch test --verbose' \
"until [ -f $$SHADOW_OUTPUT_TO ] ; do sleep 1 ; done ; node --require ./test-resources/override.js $$SHADOW_OUTPUT_TO --repl" 'until [ -f ./target/test/test.js ] ; do sleep 1 ; done ; node --require ./test-resources/override.js ./target/test/test.js --repl'
test-unit: export SHADOW_OUTPUT_TO := target/unit_test/test.js test: export TARGET := clojure
test-unit: export SHADOW_NS_REGEXP := ^(?!status-im\.integration-test).*-test$$ test: ##@test Run tests once in NodeJS
test-unit: ##@test Run unit tests # Here we create the gyp bindings for nodejs
test-unit: _test-clojure yarn install
yarn shadow-cljs compile mocks && \
yarn shadow-cljs compile test && \
node --require ./test-resources/override.js target/test/test.js
test-integration: export SHADOW_OUTPUT_TO := target/integration_test/test.js
test-integration: export SHADOW_NS_REGEXP := ^status-im\.integration-test.*$$
test-integration: ##@test Run integration tests
test-integration: _test-clojure
android-test: jsbundle run-visual-test-ios: export TARGET := clojure
android-test: export TARGET := android run-visual-test-ios: XCODE_DERIVED_DATA := $(HOME)/Library/Developer/Xcode/DerivedData
android-test: run-visual-test-ios: APPLICATION_NAME := StatusIm-brfnruzfrkkycpbndmdoeyrigthc
cd android && ./gradlew test run-visual-test-ios: export TEST_BINARY_PATH := $(XCODE_DERIVED_DATA)/$(APPLICATION_NAME)/Build/Products/Debug-iphonesimulator/StatusIm.app
run-visual-test-ios: ##@test Run tests once in NodeJS
detox test --configuration ios.sim.debug
component-test-watch: export TARGET := clojure component-test-watch: export TARGET := clojure
component-test-watch: export COMPONENT_TEST := true component-test-watch: export COMPONENT_TEST := true
component-test-watch: export BABEL_ENV := test component-test-watch: export BABEL_ENV := test
component-test-watch: export JEST_USE_SILENT_REPORTER := false
component-test-watch: ##@ Watch tests and re-run no changes to cljs files component-test-watch: ##@ Watch tests and re-run no changes to cljs files
@scripts/check-metro-shadow-process.sh yarn install
rm -rf ./component-spec nodemon --exec 'yarn shadow-cljs compile component-test && jest --config=test/jest/jest.config.js' -e cljs
nodemon --exec 'yarn shadow-cljs compile component-test && jest --config=test/jest/jest.config.js --testEnvironment node ' -e cljs
component-test: export TARGET := clojure component-test: export TARGET := clojure
component-test: export COMPONENT_TEST := true component-test: export COMPONENT_TEST := true
component-test: export BABEL_ENV := test component-test: export BABEL_ENV := test
component-test: export JEST_USE_SILENT_REPORTER := false component-test: ##@test Run tests once in NodeJS
component-test: ##@test Run component tests once in NodeJS # Here we create the gyp bindings for nodejs
@scripts/check-metro-shadow-process.sh yarn install
rm -rf ./component-spec
yarn shadow-cljs compile component-test && \ yarn shadow-cljs compile component-test && \
jest --clearCache && jest --config=test/jest/jest.config.js --testEnvironment node jest --config=test/jest/jest.config.js
#--------------
# Other # Other
#-------------- #--------------
@@ -409,10 +356,6 @@ geth-connect: ##@other Connect to Geth on the device
adb forward tcp:8545 tcp:8545 && \ adb forward tcp:8545 tcp:8545 && \
build/bin/geth attach http://localhost:8545 build/bin/geth attach http://localhost:8545
ios-clean: SHELL := /bin/sh
ios-clean: ##@prepare Clean iOS build artifacts
git clean -dxf -f target/ios
android-clean: export TARGET := gradle android-clean: export TARGET := gradle
android-clean: ##@prepare Clean Gradle state android-clean: ##@prepare Clean Gradle state
git clean -dxf -f ./android/app/build; \ git clean -dxf -f ./android/app/build; \
+23 -18
View File
@@ -2,11 +2,9 @@
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en-play-badge.png" alt="Get it on Google Play" height="80"/>](https://play.google.com/store/apps/details?id=im.status.ethereum) [<img src="https://play.google.com/intl/en_us/badges/images/generic/en-play-badge.png" alt="Get it on Google Play" height="80"/>](https://play.google.com/store/apps/details?id=im.status.ethereum)
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" alt="Get it on F-Droid" height="80"/>](https://f-droid.org/packages/im.status.ethereum/) [<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" alt="Get it on F-Droid" height="80"/>](https://f-droid.org/packages/im.status.ethereum/)
[<img src="doc/github_badge.png" alt="Get it on Github" height="80"/>](https://github.com/status-im/status-mobile/releases)
Join us in creating a browser, messenger, and gateway to a decentralized world. Status is a free (libre) open source mobile client targeting Android & iOS built entirely on [Ethereum](https://ethereum.org/) technologies. That's right, no middle men and `go-ethereum` running directly on your device.
[Get it on Github](https://github.com/status-im/status-mobile/releases)
Join us in creating a browser, messenger, and gateway to a decentralized world. Status is a free (libre) open source mobile client targeting Android & iOS built entirely on [Ethereum](https://ethereum.org/) technologies. That's right, no middlemen and `go-ethereum` running directly on your device.
[![Getting started with Status](https://i.imgur.com/C0aZZEL.jpg)](https://www.youtube.com/watch?v=oDCSEmS9c3o "Getting started with Status") [![Getting started with Status](https://i.imgur.com/C0aZZEL.jpg)](https://www.youtube.com/watch?v=oDCSEmS9c3o "Getting started with Status")
@@ -14,49 +12,52 @@ Join us in creating a browser, messenger, and gateway to a decentralized world.
We believe in a medium of pure free trade, economies with fair, permission-less access and a world without intermediaries. We want to create policies that can exist between friends or scale globally, we want to communicate securely and be uninhibited by legacy systems. We believe in a medium of pure free trade, economies with fair, permission-less access and a world without intermediaries. We want to create policies that can exist between friends or scale globally, we want to communicate securely and be uninhibited by legacy systems.
We want to take responsibility for our data, and the way we conduct ourselves privately and promote this way of life to a mass audience. We want to take responsibility for our data, the way we conduct ourselves privately and promote this way of life to a mass audience.
We want deep insights into our own economies so we can make informed, data-driven decisions on how to make our lives better. The Ethereum blockchain, Smart Contracts, Swarm and Whisper provide us with a path forward. We want deep insights into our own economies so we can make informed, data-driven decisions on how to make our lives better. The Ethereum blockchain, Smart Contracts, Swarm and Whisper provides us a path forward.
If this interests you, **help us make Status a reality** - anyone can contribute and we need everyone at any skill level to participate. If this interests you, **help us make Status a reality** - anyone can contribute and we need everyone at any skill level to participate.
## How to Contribute? ## How to Contribute?
Go straight to the [docs](doc/) and choose what interests you: Go straight to the [docs](https://status.im/docs) or [join our chat](https://join.status.im/chat/public/status) and choose what interests you:
- **Developer** Developers are the heart of software and to keep Status beating - **Developer** Developers are the heart of software and to keep Status beating
we need all the help we can get! If you're looking to code in ClojureScript or we need all the help we can get! If you're looking to code in ClojureScript or
Golang then Status is the project for you! We use React Native and there is even Golang then Status is the project for you! We use React Native and there is even
some Java/Objective-C too! Want to learn more about it? Start by reading our some Java/Objective-C too! Want to learn more about it? Start by reading our
[Developer Introduction](doc/starting-guide.md) which guides you [Developer Introduction](https://status.im/developer_tools/) which guides you
through the technology stack and start browsing [beginner through the technology stack and start browsing [beginner
issues](https://github.com/status-im/status-mobile/issues?utf8=%E2%9C%93&q=is%3Aopen%20is%3Aissue%20label%3A%22good%20first%20issue%22%20). issues](https://github.com/status-im/status-mobile/issues?utf8=%E2%9C%93&q=is%3Aopen%20is%3Aissue%20label%3A%22good%20first%20issue%22%20).
Then you can read how to [Build Then you can read how to [Build
Status](doc/starting-guide.md), which talks about managing Status](https://status.im/technical/build_status/), which talks about managing
project dependencies, coding guidelines and testing procedures. project dependencies, coding guidelines and testing procedures. The [doc/](doc/)
Check out our [coding guidelines](doc/new-guidelines.md). directory also has valuable information for contributors.
- **Community Management** - **Community Management**
Metcalfe's law states that the value of a network is proportional to the square of the number of connected users of the system - without community Status is meaningless. We're looking to create a positive, fun environment to explore new ideas, experiment and grow the Status community. Building a community takes a lot of work but the people you'll meet and the long-lasting relationships you form will be well worth it, check out our [Mission and Community Principles](https://status.im/about) Metcalfe's law states that the value of a network is proportional to the square of the number of connected users of the system - without community Status is meaningless. We're looking to create a positive, fun environment to explore new ideas, experiment and grow the Status community. Building a community takes a lot of work but the people you'll meet and long lasting relationships you form will be well worth it, check out our [Mission and Community Principles](https://status.im/about)
- **Specification / Documentation** - **Specification / Documentation**
John Dewey once said, "Education is not preparation for life; education is life *itself* ". Developers and Designers need guidance and it all starts from documentation and specifications. Our software is only as good as its documentation, check out our [docs](doc/) and see how you can improve what we have. John Dewey once said "Education is not preparation for life; education is life *itself* ". Developers & Designers need guidance and it all starts from documentation and specifications. Our software is only as good as its documentation, head over to our [docs](https://status.im/docs) and see how you can improve what we have.
- **Blog Writing** - **Blog Writing**
Content is King, keeping our blog up to date and informing the community of news helps keep everyone on the same page. Content is King, keeping our blog up to date and informing the community of news helps keep everyone on the same page. [Jump into our chat](https://join.status.im/chat/public/status) and discuss with the team how you can contribute!
- **Testers** - **Testers**
It's bug-hunting season! Status is currently under active development and there is sure to be a bunch of learning, [build status from scratch](doc/starting-guide.md) or if an android user checks out our [nightly builds](https://status.im/nightly). You can shake your phone to submit bug reports, or start browsing our [Github Issues](https://github.com/status-im/status-mobile/issues). Every bug you find brings Status closer to stable, usable software for everyone to enjoy! It's bug hunting season! Status is currently under active development and there is sure to be a bunch of learning, [build status from scratch](https://status.im/technical/build_status/) or if an android user check out our [nightly builds](https://status.im/nightly). You can shake your phone to submit bug reports, or start browsing our [Github Issues](https://github.com/status-im/status-mobile/issues). Every bug you find brings Status closer to stable, usable software for everyone to enjoy!
- **Security** - **Security**
Status is a visual interface to make permanent changes on the Blockchain, it handles crypto-tokens that have real value and allows 3rd party code execution. Security is paramount to its success. You are given permission to break Status as hard as you can, as long as you share your findings with the community! Status is a visual interface to make permanent changes on the Blockchain, it handles crypto-tokens that have real value and allows 3rd party code execution. Security is paramount to its success. You are given permission to break Status as hard as you can, as long as you share your findings with the community!
- **Evangelism** - **Evangelism**
Help us spread the word! Tell a friend *right now*, in fact, tell **everyone** - yell from a mountain if you have to, every person counts! If you've got a great story to tell or have some interesting way you've spread the word about Status let us know about it in our [chat](https://join.status.im/chat/public/status) Help us spread the word! Tell a friend *right now*, in fact tell **everyone** - yell from a mountain if you have to, every person counts! If you've got a great story to tell or have some interesting way you've spread the word about Status let us know about it in our [chat](https://join.status.im/chat/public/status)
## Status API
View our [API Docs](https://status.im/developer_tools/status_web_api.html) and learn how to integrate your DApp into Status. You can read more about how to add your DApp to Status [here](https://status.im/developer_tools/add_your_dapp.html).
## Give me Binaries! ## Give me Binaries!
You can get our Beta builds for both Android and iOS on our [website](https://status.im), through our [nightly builds](https://status.im/nightly/), or by [building it yourself](https://status.im/technical/build_status/). You can get our Beta builds for both Android and iOS on our [website](https://status.im), through our [nightly builds](https://status.im/nightly/) or by [building it yourself](https://status.im/technical/build_status/).
## Core Contributors ## Core Contributors
@@ -67,8 +68,12 @@ Without the dedication of these outstanding individuals, Status would not exist.
## Contact us ## Contact us
Feel free to email us at [support@status.im](mailto:support@status.im). Feel free to email us at [support@status.im](mailto:support@status.im) or better yet, [join our chat](https://join.status.im/chat/public/status).
## License ## License
Licensed under the [Mozilla Public License v2.0](https://github.com/status-im/status-mobile/blob/develop/LICENSE.md) Licensed under the [Mozilla Public License v2.0](https://github.com/status-im/status-mobile/blob/develop/LICENSE.md)
## Testing Supported by
[![BrowserStack Status](https://www.browserstack.com/automate/badge.svg?badge_key=SFBWQ3k5R2tnT2t6UGsxU1h1U0g3VFlCNnoxVTRHYWNoTDhsb1laaTJZWT0tLUZMUm5sSVFBSU9qSWM1RUJvK1I3Z3c9PQ==--ad15ae7992b432b33743749d40318952415bd98f)](https://www.browserstack.com/automate/public-build/SFBWQ3k5R2tnT2t6UGsxU1h1U0g3VFlCNnoxVTRHYWNoTDhsb1laaTJZWT0tLUZMUm5sSVFBSU9qSWM1RUJvK1I3Z3c9PQ==--ad15ae7992b432b33743749d40318952415bd98f)
+1 -1
View File
@@ -25,7 +25,7 @@
### Redesign ### Redesign
* quo, Switcher Navigation by @Parveshdhull in https://github.com/status-im/status-mobile/pull/13167 * Quo2, Switcher Navigation by @Parveshdhull in https://github.com/status-im/status-mobile/pull/13167
* Switcher and Bottom Tabs Animations and UI Performance Improvements by @Parveshdhull in https://github.com/status-im/status-mobile/pull/13470 * Switcher and Bottom Tabs Animations and UI Performance Improvements by @Parveshdhull in https://github.com/status-im/status-mobile/pull/13470
* feat: add token tag component (#13599) by @J-Son89 in https://github.com/status-im/status-mobile/pull/13644 * feat: add token tag component (#13599) by @J-Son89 in https://github.com/status-im/status-mobile/pull/13644
* [13565] icon-avatar component by @ibrkhalil in https://github.com/status-im/status-mobile/pull/13692 * [13565] icon-avatar component by @ibrkhalil in https://github.com/status-im/status-mobile/pull/13692
+1 -1
View File
@@ -1 +1 @@
1.25.0 1.20.2
+135 -75
View File
@@ -1,75 +1,124 @@
apply plugin: "com.android.application" apply plugin: "com.android.application"
apply plugin: "org.jetbrains.kotlin.android"
apply plugin: "com.facebook.react"
apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle" apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle"
import com.android.build.OutputFile import com.android.build.OutputFile
import com.sun.org.apache.xalan.internal.xsltc.compiler.Copy import com.sun.org.apache.xalan.internal.xsltc.compiler.Copy
/* /**
* This is the configuration block to customize your React Native Android app. * The react.gradle file registers a task for each build variant:
* By default you don't need to apply any configuration, just uncomment the lines you need. * - bundlePrJsAndAssets
* - bundleDebugJsAndAssets
* - bundleReleaseJsAndAssets
* These basically call `react-native bundle` with the correct arguments during the Android build
* cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
* bundle directly from the development server. Below you can see all the possible configurations
* and their defaults. If you decide to add a configuration block, make sure to add it before the
* `apply from: "../../node_modules/react-native/react.gradle"` line.
*
* project.ext.react = [
* // the name of the generated asset file containing your JS bundle
* bundleAssetName: "index.android.bundle",
*
* // the entry file for bundle generation
* entryFile: "index.js",
*
* // whether to bundle JS and assets in debug mode
* bundleInDebug: false,
*
* // whether to bundle JS and assets in release mode
* bundleInRelease: true,
*
* // whether to bundle JS and assets in another build variant (if configured).
* // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
* // The configuration property can be in the following formats
* // 'bundleIn${productFlavor}${buildType}'
* // 'bundleIn${buildType}'
* // bundleInFreeDebug: true,
* // bundleInPaidRelease: true,
* // bundleInBeta: true,
*
* // whether to disable dev mode in custom build variants (by default only disabled in release)
* // for example: to disable dev mode in the staging build type (if configured)
* devDisabledInStaging: true,
* // The configuration property can be in the following formats
* // 'devDisabledIn${productFlavor}${buildType}'
* // 'devDisabledIn${buildType}'
*
* // the root of your project, i.e. where "package.json" lives
* root: "../../",
*
* // where to put the JS bundle asset in debug mode
* jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
*
* // where to put the JS bundle asset in release mode
* jsBundleDirRelease: "$buildDir/intermediates/assets/release",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in debug mode
* resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in release mode
* resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
*
* // by default the gradle tasks are skipped if none of the JS files or assets change; this means
* // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
* // date; if you have any other folders that you want to ignore for performance reasons (gradle
* // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
* // for example, you might want to remove it from here.
* inputExcludes: ["android/**", "ios/**"],
*
* // override which node gets called and with what additional arguments
* nodeExecutableAndArgs: ["node", "--max-old-space-size=8192"],
*
* // supply additional arguments to the packager
* extraPackagerArgs: []
* ]
*/ */
react {
/* Folders */
// The root of your project, i.e. where "package.json" lives. Default is '..'
// root = file("../")
// The folder where the react-native NPM package is. Default is ../node_modules/react-native
// reactNativeDir = file("../node_modules/react-native")
// The folder where the react-native Codegen package is. Default is ../node_modules/@react-native/codegen
// codegenDir = file("../node_modules/@react-native/codegen")
// The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js
// cliFile = file("../node_modules/react-native/cli.js")
/* Variants */ /*
// The list of variants to that are debuggable. For those we're going to Enabling Hermes on x86 devices is crashing the app after a few reloads,
// skip the bundling of the JS bundle and the assets. By default is just 'debug'. this flag can be used to disable Hermes while building app.
// If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants. https://github.com/status-im/status-mobile/issues/14031
// debuggableVariants = ["liteDebug", "prodDebug"] */
/* Bundling */ def disableHermes = System.getenv('DISABLE_HERMES') == 'true'
// A list containing the node command and its flags. Default is just 'node'.
nodeExecutableAndArgs = ["node", "--max-old-space-size=16384" ]
//
// The command to run when bundling. By default is 'bundle'
// bundleCommand = "ram-bundle"
//
// The path to the CLI configuration file. Default is empty.
// bundleConfig = file(../rn-cli.config.js)
//
// The name of the generated asset file containing your JS bundle
// bundleAssetName = "MyApplication.android.bundle"
//
// The entry file for bundle generation. Default is 'index.android.js' or 'index.js'
// entryFile = file("../js/MyApplication.android.js")
//
// A list of extra flags to pass to the 'bundle' commands.
// See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle
// extraPackagerArgs = []
/* Hermes Commands */ project.ext.react = [
// The hermes compiler command to run. By default it is 'hermesc' nodeExecutableAndArgs: ["node", "--max-old-space-size=16384"],
// hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc" entryFile: "index.js",
// /* NOTE: Hermes engine is required for Android 64-bit builds running on 64 devices,
// The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" * to guard against a hang in the UI thread after invoking status-go.
// hermesFlags = ["-O", "-output-source-map"] * Also a clean and rebuild is required when changing this. */
} enableHermes: !disableHermes,
/* Disable 'The first definition was here.' warnings */
hermesFlagsRelease: ["-w"],
bundleInPr: true,
inputExcludes: ["android/**", "ios/**", "react-native/**", "src/**", "test/**"]
]
// NOTE: Uncomment if building RN from a fork
// configurations.all {
// exclude group: 'com.facebook.react', module: 'react-native'
// }
apply from: "../../node_modules/react-native/react.gradle"
/** /**
* Set this to true to Run Proguard on Release builds to minify the Java bytecode. * Run Proguard to shrink the Java bytecode in release builds.
*/ */
def enableProguardInReleaseBuilds = false def enableProguardInReleaseBuilds = false
/** /**
* The preferred build flavor of JavaScriptCore (JSC) * The preferred build flavor of JavaScriptCore.
* *
* For example, to use the international variant, you can use: * For example, to use the international variant, you can use:
* `def jscFlavor = 'org.webkit:android-jsc-intl:+'` * `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
* *
* The international variant includes ICU i18n library and necessary data * The international variant includes ICU i18n library and necessary data
* allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
* give correct results when using with locales other than en-US. Note that * give correct results when using with locales other than en-US. Note that
* this variant is about 6MiB larger per architecture than default. * this variant is about 6MiB larger per architecture than default.
*/ */
def jscFlavor = 'org.webkit:android-jsc:+' def jscFlavor = 'org.webkit:android-jsc:+'
@@ -81,8 +130,7 @@ def jscFlavor = 'org.webkit:android-jsc:+'
* on project.ext.react, JavaScript will not be compiled to Hermes Bytecode * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode
* and the benefits of using Hermes will therefore be sharply reduced. * and the benefits of using Hermes will therefore be sharply reduced.
*/ */
def enableHermes = hermesEnabled.toBoolean(); def enableHermes = project.ext.react.get("enableHermes", false);
def getCommitHash = { -> def getCommitHash = { ->
if (project.hasProperty("commitHash")) { if (project.hasProperty("commitHash")) {
@@ -108,13 +156,12 @@ def getVersionCode = { ->
def getVersionName = { -> def getVersionName = { ->
new ByteArrayOutputStream().withStream { stdOut -> new ByteArrayOutputStream().withStream { stdOut ->
// TODO: probably not used, cleanup
if (project.hasProperty("releaseVersion")) { if (project.hasProperty("releaseVersion")) {
return project.releaseVersion return project.releaseVersion
} }
/* Necessary because Android Studio uses wrong PWD. /* Necessary because Android Studio uses wrong PWD.
* Is actually absolute directory path of this file. */ * Is actually absolute directory path of this file. */
def configDir = project.projectDir.toString() def configDir = project.projectDir.toString()
version = new File(configDir + '/../../VERSION').text version = new File(configDir + '/../../VERSION').text
return version.replaceAll("\\s","") return version.replaceAll("\\s","")
} }
@@ -136,16 +183,13 @@ def getEnvOrConfig = { varName ->
} }
android { android {
ndkVersion rootProject.ext.ndkVersion
compileSdkVersion rootProject.ext.compileSdkVersion compileSdkVersion rootProject.ext.compileSdkVersion
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_11 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_11 targetCompatibility JavaVersion.VERSION_1_8
} }
namespace "im.status.ethereum"
defaultConfig { defaultConfig {
applicationId "im.status.ethereum" applicationId "im.status.ethereum"
minSdkVersion rootProject.ext.minSdkVersion minSdkVersion rootProject.ext.minSdkVersion
@@ -162,7 +206,6 @@ android {
} }
} }
} }
/** /**
* Arbitrary project metadata * Arbitrary project metadata
* https://docs.gradle.org/current/dsl/org.gradle.api.plugins.ExtraPropertiesExtension.html * https://docs.gradle.org/current/dsl/org.gradle.api.plugins.ExtraPropertiesExtension.html
@@ -233,11 +276,10 @@ android {
versionNameSuffix ".pr" versionNameSuffix ".pr"
debuggable false debuggable false
matchingFallbacks = ["release"] matchingFallbacks = ["release"]
// necessary to make react-native-config's code generation work // necessary to make react-native-config's code generation work
resValue "string", "build_config_package", "im.status.ethereum" resValue "string", "build_config_package", "im.status.ethereum"
} }
} }
// applicationVariants are e.g. debug, release // applicationVariants are e.g. debug, release
applicationVariants.all { variant -> applicationVariants.all { variant ->
variant.outputs.each { output -> variant.outputs.each { output ->
@@ -253,7 +295,6 @@ android {
} }
} }
aaptOptions { aaptOptions {
// disable PNG optimization as for some reason it cannot be trusted to provide deterministic output (see https://f-droid.org/en/docs/Reproducible_Builds/) // disable PNG optimization as for some reason it cannot be trusted to provide deterministic output (see https://f-droid.org/en/docs/Reproducible_Builds/)
cruncherEnabled = false cruncherEnabled = false
@@ -265,31 +306,50 @@ android {
} }
dependencies { dependencies {
// The version of react-native is set by the React Native Gradle Plugin implementation fileTree(dir: "libs", include: ["*.jar"])
implementation("com.facebook.react:react-android") implementation "com.facebook.react:react-native:+" // From node_modules
implementation "androidx.core:core-splashscreen:1.0.0"
if (hermesEnabled.toBoolean()) { implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
implementation("com.facebook.react:hermes-android")
} else { debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
exclude group:'com.facebook.fbjni'
}
// TODO Uncomment once Flipper does not cause webview crashes in Debug mode
// debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
// exclude group:'com.facebook.flipper'
// }
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
}
if (enableHermes) {
def hermesPath = "../../node_modules/hermes-engine/android/";
debugImplementation files(hermesPath + "hermes-debug.aar")
releaseImplementation files(hermesPath + "hermes-release.aar")
prImplementation files(hermesPath + "hermes-release.aar")
} else {
implementation jscFlavor implementation jscFlavor
} }
// react-native-screens // react-native-screens
implementation 'androidx.appcompat:appcompat:1.1.0-rc01' implementation 'androidx.appcompat:appcompat:1.1.0-rc01'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-alpha02' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-alpha02'
implementation 'androidx.multidex:multidex:2.0.1' // required by status-mobile/android/app/src/main/java/im/status/ethereum/MainApplication.java
implementation 'androidx.multidex:multidex:2.0.1' // only needed if minSdkVersion is less than 21 (https://developer.android.com/studio/build/multidex)
implementation project(':react-native-dialogs')
implementation project(':react-native-blur') implementation project(':react-native-blur')
// Force using exact RN version instead of relying on gradle dependency resolution
// https://docs.gradle.org/current/userguide/introduction_dependency_management.html#sec:dependency_resolution
// NOTE: Uncomment if building RN from a fork
//compile ("com.facebook.react:react-native:0.55.4") { force = true } // From node_modules
implementation project(':react-native-status') implementation project(':react-native-status')
implementation project(':react-native-status-keycard') implementation project(':react-native-status-keycard')
implementation 'com.github.status-im:function:0.0.1' implementation 'com.github.status-im:function:0.0.1'
implementation 'com.facebook.fresco:fresco:2.5.0' implementation 'com.facebook.fresco:fresco:2.2.0'
implementation 'com.facebook.fresco:animated-gif:2.5.0' implementation 'com.facebook.fresco:animated-gif:2.2.0'
implementation "com.squareup.okhttp3:okhttp-tls:4.9.2" implementation "com.squareup.okhttp3:okhttp-tls:3.12.12"
implementation("com.google.prefab:cli:2.0.0")
} }
def getLocalNDKDir = { -> def getLocalNDKDir = { ->
def rootDir = project.rootDir def rootDir = project.rootDir
def localProperties = new File(rootDir, "local.properties") def localProperties = new File(rootDir, "local.properties")
+1 -3
View File
@@ -7,7 +7,5 @@
<!-- Remove licensing permission since we don't license our app and it blocks F-Droid submissions. --> <!-- Remove licensing permission since we don't license our app and it blocks F-Droid submissions. -->
<uses-permission tools:node="remove" android:name="com.android.vending.CHECK_LICENSE"/> <uses-permission tools:node="remove" android:name="com.android.vending.CHECK_LICENSE"/>
<application tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" android:usesCleartextTraffic="true" > <application tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" android:usesCleartextTraffic="true" />
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" android:exported="false" />
</application>
</manifest> </manifest>
@@ -0,0 +1,73 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
* directory of this source tree.
*/
package im.status.ethereum;
import android.content.Context;
import com.facebook.flipper.android.AndroidFlipperClient;
import com.facebook.flipper.android.utils.FlipperUtils;
import com.facebook.flipper.core.FlipperClient;
import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;
import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;
import com.facebook.flipper.plugins.inspector.DescriptorMapping;
import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
// import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
// import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.modules.network.NetworkingModule;
import okhttp3.OkHttpClient;
public class ReactNativeFlipper {
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
if (FlipperUtils.shouldEnableFlipper(context)) {
final FlipperClient client = AndroidFlipperClient.getInstance(context);
client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
client.addPlugin(new ReactFlipperPlugin());
client.addPlugin(new DatabasesFlipperPlugin(context));
client.addPlugin(new SharedPreferencesFlipperPlugin(context));
client.addPlugin(CrashReporterPlugin.getInstance());
// TODO Uncomment once Flipper does not cause webview crashes in Debug mode
// NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
// NetworkingModule.setCustomClientBuilder(
// new NetworkingModule.CustomClientBuilder() {
// @Override
// public void apply(OkHttpClient.Builder builder) {
// builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
// }
// });
// client.addPlugin(networkFlipperPlugin);
client.start();
// Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
// Hence we run if after all native modules have been initialized
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
if (reactContext == null) {
reactInstanceManager.addReactInstanceEventListener(
new ReactInstanceManager.ReactInstanceEventListener() {
@Override
public void onReactContextInitialized(ReactContext reactContext) {
reactInstanceManager.removeReactInstanceEventListener(this);
reactContext.runOnNativeModulesQueueThread(
new Runnable() {
@Override
public void run() {
client.addPlugin(new FrescoFlipperPlugin());
}
});
}
});
} else {
client.addPlugin(new FrescoFlipperPlugin());
}
}
}
}
+11 -15
View File
@@ -1,6 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:installLocation="auto"> android:installLocation="auto"
package="im.status.ethereum">
<!-- non-dangerous permissions --> <!-- non-dangerous permissions -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
@@ -16,11 +17,11 @@
<uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" /> <uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" /> <uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.RECORD_AUDIO" />
<application <application
@@ -28,23 +29,18 @@
android:allowBackup="false" android:allowBackup="false"
android:label="@string/app_name" android:label="@string/app_name"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:theme="@style/Theme.AppSplash" android:theme="@style/AppTheme"
android:name=".MainApplication" android:name=".MainApplication"
android:largeHeap="true" android:largeHeap="true"
android:usesCleartextTraffic="true" android:usesCleartextTraffic="true">
android:extractNativeLibs="true"
android:requestLegacyExternalStorage="true">
<!-- After upgrading Android Gradle Plugin to 4.2.0 and above we must get rid of `extractNativeLibs="true"`
and use`useLegacyPackaging` flag in our app's `build.gradle`-->
<meta-data android:name="commitHash" android:value="${commitHash}"/> <meta-data android:name="commitHash" android:value="${commitHash}"/>
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"
android:label="@string/app_name" android:label="@string/app_name"
android:theme="@style/Theme.AppSplash"
android:screenOrientation="portrait" android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize" android:windowSoftInputMode="adjustResize"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
android:resizeableActivity="false" android:resizeableActivity="false"
android:launchMode="singleTask"> android:launchMode="singleTask">
<intent-filter> <intent-filter>
@@ -62,14 +58,14 @@
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" android:host="status.app" /> <data android:scheme="http" android:host="join.status.im" />
<data android:scheme="https" android:host="status.app" /> <data android:scheme="https" android:host="join.status.im" />
</intent-filter> </intent-filter>
<intent-filter android:autoVerify="true"> <intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="status-app" /> <data android:scheme="status-im" />
<data android:scheme="ethereum" /> <data android:scheme="ethereum" />
</intent-filter> </intent-filter>
</activity> </activity>
@@ -0,0 +1,265 @@
package im.status.ethereum;
import android.content.Context;
import android.annotation.TargetApi;
import androidx.annotation.Nullable;
import android.app.AlertDialog;
import android.app.ActivityManager;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnClickListener;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Looper;
import android.preference.PreferenceManager;
import androidx.core.app.ActivityCompat;
import android.util.Log;
import android.view.WindowManager;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.provider.Settings;
import android.os.Bundle;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableMap;
import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;
import com.facebook.react.ReactFragmentActivity;
import com.reactnativenavigation.NavigationActivity;
import com.facebook.react.modules.core.PermissionListener;
import org.devio.rn.splashscreen.SplashScreen;
import java.util.Properties;
import im.status.ethereum.module.StatusThreadPoolExecutor;
import im.status.ethereum.MainApplication;
public class MainActivity extends NavigationActivity
implements ActivityCompat.OnRequestPermissionsResultCallback{
@Nullable private PermissionListener mPermissionListener;
private static void registerUncaughtExceptionHandler(final Context context) {
final Thread.UncaughtExceptionHandler defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(final Thread thread, final Throwable t) {
// High priority, so don't use StatusThreadPoolExecutor
new Thread() {
@Override
public void run() {
Looper.prepare();
new AlertDialog.Builder(context)
.setTitle("Error")
.setMessage(t.toString())
.setNegativeButton("Exit", new DialogInterface.OnClickListener() {
public void onClick(final DialogInterface dialog, final int id) {
dialog.dismiss();
defaultUncaughtExceptionHandler.uncaughtException(thread, t);
}
}).show();
Looper.loop();
}
}.start();
}
});
}
private ActivityManager getActivityManager() {
return (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
}
private ActivityManager.MemoryInfo getAvailableMemory(final ActivityManager activityManager) {
final ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(memoryInfo);
return memoryInfo;
}
protected void configureStatus() {
// Required because of crazy APN settings redirecting localhost (found in GB)
Properties properties = System.getProperties();
properties.setProperty("http.nonProxyHosts", "localhost|127.0.0.1");
properties.setProperty("https.nonProxyHosts", "localhost|127.0.0.1");
}
private Intent createNotificationSettingsIntent() {
final Intent intent = new Intent();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
} else {
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setData(Uri.parse("package:" + getPackageName()));
}
return intent;
}
private void tryToEmit(String eventName, WritableMap event) {
try {
((MainApplication) getApplication()).getReactNativeHost()
.getReactInstanceManager()
.getCurrentReactContext()
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("url", event);
} catch(Exception e) {/* we expect NPE on first start, which is OK because we have a fallback */}
}
@Override
public void onNewIntent(final Intent intent) {
super.onNewIntent(intent);
if (intent.getDataString() != null && intent.getData().getScheme().startsWith("app-settings")) {
startActivity(createNotificationSettingsIntent());
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
switch (getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) {
case Configuration.UI_MODE_NIGHT_YES:
setTheme(R.style.DarkTheme);
SplashScreen.show(this, R.style.DarkTheme, R.id.lottie);
break;
case Configuration.UI_MODE_NIGHT_NO:
setTheme(R.style.LightTheme);
SplashScreen.show(this, R.style.LightTheme, R.id.lottie);
break;
default:
setTheme(R.style.LightTheme);
SplashScreen.show(this, R.style.LightTheme, R.id.lottie);
}
SplashScreen.setAnimationFinished(true);
// Make sure we get an Alert for every uncaught exceptions
registerUncaughtExceptionHandler(MainActivity.this);
// Report memory details for this application
final ActivityManager activityManager = getActivityManager();
Log.v("RNBootstrap", "Available system memory "+getAvailableMemory(activityManager).availMem + ", maximum usable application memory " + activityManager.getLargeMemoryClass()+"M");
setSecureFlag();
// NOTE: Try to not restore the state https://github.com/software-mansion/react-native-screens/issues/17
super.onCreate(null);
if (!shouldShowRootedNotification()) {
configureStatus();
} else {
AlertDialog dialog = new AlertDialog.Builder(MainActivity.this)
.setMessage(getResources().getString(R.string.root_warning))
.setPositiveButton(getResources().getString(R.string.root_okay), new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
rejectRootedNotification();
dialog.dismiss();
configureStatus();
}
})
.setNegativeButton(getResources().getString(R.string.root_cancel), new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
MainActivity.this.finishAffinity();
}
})
.setOnCancelListener(new OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
dialog.dismiss();
MainActivity.this.finishAffinity();
}
})
.create();
dialog.show();
}
Runnable r = new Runnable() {
@Override
public void run() {
System.loadLibrary("status-logs");
// when app is started but the Activity has been destroyed, the deep linking url event is
// not emitted when coming back to foreground. This is a workaround. If the problem is
// resolved in react-native this code should be removed
if (getIntent().getData() != null) {
WritableMap event = Arguments.createMap();
event.putString("url", getIntent().getDataString());
// on first start emit will (silently) fail, but the regular deep linking handler will work
tryToEmit("url", event);
}
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
}
@Override
protected void onDestroy() {
super.onDestroy();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Intent intent = new Intent("onConfigurationChanged");
intent.putExtra("newConfig", newConfig);
this.sendBroadcast(intent);
}
private static final String REJECTED_ROOTED_NOTIFICATION = "rejectedRootedNotification";
private static final Integer FREQUENCY_OF_REMINDER_IN_PERCENT = 5;
private boolean shouldShowRootedNotification() {
if (RootUtil.isDeviceRooted() && BuildConfig.ENABLE_ROOT_ALERT == "1") {
if (userRejectedRootedNotification()) {
return ((Math.random() * 100) < FREQUENCY_OF_REMINDER_IN_PERCENT);
} else return true;
} else {
return false;
}
}
private boolean userRejectedRootedNotification() {
SharedPreferences preferences = getPreferences(0);
return preferences.getBoolean(REJECTED_ROOTED_NOTIFICATION, false);
}
private void rejectRootedNotification() {
SharedPreferences preferences = getPreferences(0);
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean(REJECTED_ROOTED_NOTIFICATION, true);
editor.commit();
}
private void setSecureFlag() {
final SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
final boolean setSecure = sharedPrefs.getBoolean("BLANK_PREVIEW", false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH && setSecure) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
} else {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
}
}
@TargetApi(Build.VERSION_CODES.M)
public void requestPermissions(String[] permissions, int requestCode, PermissionListener listener) {
mPermissionListener = listener;
requestPermissions(permissions, requestCode);
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (mPermissionListener != null && mPermissionListener.onRequestPermissionsResult(requestCode, permissions, grantResults)) {
mPermissionListener = null;
}
}
}
@@ -1,236 +0,0 @@
package im.status.ethereum
import android.annotation.TargetApi
import android.app.ActivityManager
import android.app.AlertDialog
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.preference.PreferenceManager
import android.provider.Settings
import android.util.Log
import android.view.WindowManager
import androidx.annotation.Nullable
import androidx.core.app.ActivityCompat
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import com.facebook.react.ReactActivityDelegate
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.WritableMap
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint
import com.facebook.react.defaults.DefaultReactActivityDelegate
import com.facebook.react.modules.core.DeviceEventManagerModule
import com.facebook.react.modules.core.PermissionListener
import com.reactnativenavigation.NavigationActivity
import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView
import im.status.ethereum.MainApplication
import im.status.ethereum.module.StatusThreadPoolExecutor
import java.util.Properties
class MainActivity : NavigationActivity(), ActivityCompat.OnRequestPermissionsResultCallback {
@Nullable
private var mPermissionListener: PermissionListener? = null
private var keepSplash = true
private val SPLASH_DELAY = 3200
/**
* Returns the name of the main component registered from JavaScript. This is used to schedule
* rendering of the component.
*/
protected fun getMainComponentName(): String {
return "StatusIm"
}
private fun registerUncaughtExceptionHandler(context: Context) {
val defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler()
// High priority, so don't use StatusThreadPoolExecutor
Thread.setDefaultUncaughtExceptionHandler { thread, t ->
Thread {
Looper.prepare()
AlertDialog.Builder(context)
.setTitle("Error")
.setMessage(t.toString())
.setNegativeButton("Exit") { dialog, id ->
dialog.dismiss()
defaultUncaughtExceptionHandler.uncaughtException(thread, t)
}.show()
Looper.loop()
}.start()
}
}
private fun getActivityManager(): ActivityManager {
return getSystemService(ACTIVITY_SERVICE) as ActivityManager
}
private fun getAvailableMemory(activityManager: ActivityManager): ActivityManager.MemoryInfo {
val memoryInfo = ActivityManager.MemoryInfo()
activityManager.getMemoryInfo(memoryInfo)
return memoryInfo
}
protected fun configureStatus() {
// Required because of crazy APN settings redirecting localhost (found in GB)
val properties = System.getProperties()
properties.setProperty("http.nonProxyHosts", "localhost|127.0.0.1")
properties.setProperty("https.nonProxyHosts", "localhost|127.0.0.1")
}
private fun createNotificationSettingsIntent(): Intent {
val intent = Intent()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
intent.action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName)
} else {
intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
intent.addCategory(Intent.CATEGORY_DEFAULT)
intent.data = Uri.parse("package:$packageName")
}
return intent
}
private fun tryToEmit(eventName: String, event: WritableMap) {
try {
(getApplication() as MainApplication).getReactNativeHost()
.getReactInstanceManager()
.getCurrentReactContext()
?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
?.emit("url", event)
} catch (e: Exception) { // we expect NPE on first start, which is OK because we have a fallback
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
if (intent.dataString != null && intent.data!!.scheme!!.startsWith("app-settings")) {
startActivity(createNotificationSettingsIntent())
}
}
override fun onCreate(savedInstanceState: Bundle?) {
val splashScreen = installSplashScreen();
setTheme(R.style.DarkTheme)
// Make sure we get an Alert for every uncaught exceptions
registerUncaughtExceptionHandler(this)
// Report memory details for this application
val activityManager = getActivityManager()
Log.v("RNBootstrap", "Available system memory " + getAvailableMemory(activityManager).availMem + ", maximum usable application memory " + activityManager.largeMemoryClass + "M")
setSecureFlag()
// NOTE: Try to not restore the state https://github.com/software-mansion/react-native-screens/issues/17
super.onCreate(null)
if (!shouldShowRootedNotification()) {
configureStatus()
} else {
val dialog = AlertDialog.Builder(this)
.setMessage(resources.getString(R.string.root_warning))
.setPositiveButton(resources.getString(R.string.root_okay)) { dialog, which ->
rejectRootedNotification()
dialog.dismiss()
configureStatus()
}
.setNegativeButton(resources.getString(R.string.root_cancel)) { dialog, which ->
dialog.dismiss()
finishAffinity()
}
.setOnCancelListener {
it.dismiss()
finishAffinity()
}
.create()
dialog.show()
}
val r = Runnable {
System.loadLibrary("status-logs")
// when app is started but the Activity has been destroyed, the deep linking url event is
// not emitted when coming back to foreground. This is a workaround. If the problem is
// resolved in react-native this code should be removed
if (intent.data != null) {
val event = Arguments.createMap()
event.putString("url", intent.dataString)
// on first start emit will (silently) fail, but the regular deep linking handler will work
tryToEmit("url", event)
}
}
splashScreen.setKeepOnScreenCondition { keepSplash }
val handler = Handler()
handler.postDelayed({ keepSplash = false }, SPLASH_DELAY.toLong())
StatusThreadPoolExecutor.getInstance().execute(r)
}
override fun onDestroy() {
super.onDestroy()
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
val intent = Intent("onConfigurationChanged")
intent.putExtra("newConfig", newConfig)
sendBroadcast(intent)
}
private val REJECTED_ROOTED_NOTIFICATION = "rejectedRootedNotification"
private val FREQUENCY_OF_REMINDER_IN_PERCENT = 5
private fun shouldShowRootedNotification(): Boolean {
if (RootUtil.isDeviceRooted() && BuildConfig.ENABLE_ROOT_ALERT == "1") {
return if (userRejectedRootedNotification()) {
(Math.random() * 100) < FREQUENCY_OF_REMINDER_IN_PERCENT
} else true
} else {
return false
}
}
private fun userRejectedRootedNotification(): Boolean {
val preferences = getPreferences(0)
return preferences.getBoolean(REJECTED_ROOTED_NOTIFICATION, false)
}
private fun rejectRootedNotification() {
val preferences = getPreferences(0)
val editor = preferences.edit()
editor.putBoolean(REJECTED_ROOTED_NOTIFICATION, true)
editor.commit()
}
private fun setSecureFlag() {
val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this)
val setSecure = sharedPrefs.getBoolean("BLANK_PREVIEW", false)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH && setSecure) {
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
} else {
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
}
}
@TargetApi(Build.VERSION_CODES.M)
override fun requestPermissions(permissions: Array<String>, requestCode: Int, listener: PermissionListener) {
mPermissionListener = listener
super.requestPermissions(permissions, requestCode)
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
if (mPermissionListener != null && mPermissionListener!!.onRequestPermissionsResult(requestCode, permissions, grantResults)) {
mPermissionListener = null
}
}
}
@@ -0,0 +1,107 @@
package im.status.ethereum;
import androidx.multidex.MultiDexApplication;
import android.util.Log;
import android.content.Context;
import android.webkit.WebView;
import java.lang.reflect.InvocationTargetException;
import com.facebook.react.PackageList;
import com.aakashns.reactnativedialogs.ReactNativeDialogsPackage;
import com.facebook.react.ReactApplication;
import cl.json.RNSharePackage;
import com.facebook.react.ReactNativeHost;
import com.reactnativenavigation.NavigationApplication;
import com.reactnativenavigation.react.NavigationReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.modules.network.OkHttpClientProvider;
import com.cmcewen.blurview.BlurViewPackage;
import java.util.List;
import im.status.ethereum.keycard.RNStatusKeycardPackage;
import im.status.ethereum.module.StatusPackage;
import im.status.ethereum.pushnotifications.PushNotificationPackage;
import im.status.ethereum.StatusOkHttpClientFactory;
import com.facebook.react.bridge.JSIModulePackage;
import com.swmansion.reanimated.ReanimatedJSIModulePackage;
public class MainApplication extends NavigationApplication {
private final ReactNativeHost mReactNativeHost = new NavigationReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
StatusPackage statusPackage = new StatusPackage(RootUtil.isDeviceRooted());
List<ReactPackage> packages = new PackageList(this).getPackages();
packages.add(statusPackage);
packages.add(new ReactNativeDialogsPackage());
packages.add(new RNStatusKeycardPackage());
packages.add(new PushNotificationPackage());
packages.add(new BlurViewPackage());
return packages;
}
@Override
protected String getJSMainModuleName() {
return "index";
}
@Override
protected JSIModulePackage getJSIModulePackage() {
return new ReanimatedJSIModulePackage();
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
OkHttpClientProvider.setOkHttpClientFactory(new StatusOkHttpClientFactory());
WebView.setWebContentsDebuggingEnabled(BuildConfig.DEBUG_WEBVIEW == "1");
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
}
/**
* Loads Flipper in React Native templates. Call this in the onCreate method with something like
* initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
*
* @param context
* @param reactInstanceManager
*/
private static void initializeFlipper(
Context context, ReactInstanceManager reactInstanceManager) {
if (BuildConfig.DEBUG) {
try {
/*
We use reflection here to pick up the class that initializes Flipper,
since Flipper library is not available in release mode
*/
Class<?> aClass = Class.forName("im.status.ethereum.ReactNativeFlipper");
aClass
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
.invoke(null, context, reactInstanceManager);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
@@ -1,61 +0,0 @@
package im.status.ethereum
import android.webkit.WebView
import androidx.multidex.MultiDexApplication
import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage
import com.facebook.react.bridge.JSIModulePackage
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint
import com.facebook.react.modules.network.OkHttpClientProvider
import com.reactnativenavigation.NavigationApplication
import com.reactnativenavigation.react.NavigationReactNativeHost
import cl.json.RNSharePackage
import com.reactnativecommunity.blurview.BlurViewPackage
import im.status.ethereum.keycard.RNStatusKeycardPackage
import im.status.ethereum.module.StatusPackage
import im.status.ethereum.pushnotifications.PushNotificationPackage
import im.status.ethereum.StatusOkHttpClientFactory
class MainApplication : NavigationApplication() {
private val mReactNativeHost = object : NavigationReactNativeHost(this) {
override fun getUseDeveloperSupport(): Boolean {
return BuildConfig.DEBUG
}
override fun getPackages(): List<ReactPackage> {
val statusPackage = StatusPackage(RootUtil.isDeviceRooted())
val packages = PackageList(this).getPackages()
packages.add(statusPackage)
packages.add(RNStatusKeycardPackage())
packages.add(PushNotificationPackage())
packages.add(BlurViewPackage())
return packages
}
override fun getJSMainModuleName(): String = "index"
override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
}
override fun getReactNativeHost(): ReactNativeHost {
return mReactNativeHost
}
override fun onCreate() {
super.onCreate()
OkHttpClientProvider.setOkHttpClientFactory(StatusOkHttpClientFactory())
WebView.setWebContentsDebuggingEnabled(BuildConfig.DEBUG_WEBVIEW == "1")
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
// If you opted-in for the New Architecture, we load the native entry point for this app.
DefaultNewArchitectureEntryPoint.load()
}
}
}
@@ -1,88 +0,0 @@
package im.status.ethereum
import android.util.Log
import com.facebook.react.modules.network.OkHttpClientFactory
import com.facebook.react.modules.network.OkHttpClientProvider
import okhttp3.OkHttpClient
import okhttp3.tls.HandshakeCertificates
import java.io.ByteArrayInputStream
import java.lang.RuntimeException
import java.lang.reflect.Field
import java.lang.reflect.Method
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
import im.status.ethereum.module.StatusPackage
class StatusOkHttpClientFactory : OkHttpClientFactory {
companion object {
private const val TAG = "StatusOkHttpClientFactory"
private const val SLEEP_DURATION = 500L // milliseconds
}
override fun createNewNetworkModuleClient(): OkHttpClient? {
val certPem = getCertificatePem().takeIf { it.isNotEmpty() }
?: return logAndReturnNull("Certificate is empty, cannot create OkHttpClient without a valid certificate")
val cert = try {
induceSleep()
// Convert PEM certificate string to X509Certificate object
CertificateFactory.getInstance("X.509")
.generateCertificate(ByteArrayInputStream(certPem.toByteArray())) as? X509Certificate
?: return logAndReturnNull("Certificate could not be parsed as non-null")
} catch (e: Exception) {
return logAndReturnNull("Could not parse certificate", e)
}
val clientCertificates = try {
induceSleep()
// Create HandshakeCertificates object with our certificate
HandshakeCertificates.Builder()
.addPlatformTrustedCertificates()
.addTrustedCertificate(cert)
.build()
} catch (e: Exception) {
return logAndReturnNull("Could not build HandshakeCertificates", e)
}
return try {
OkHttpClientProvider.createClientBuilder()
.sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager)
.build()
} catch (e: Exception) {
logAndReturnNull("Could not create OkHttpClient", e)
}
}
private fun getCertificatePem(): String {
return try {
// Create OkHttpClient with custom SSL socket factory and trust manager
StatusPackage.getImageTLSCert().takeIf { !it.isNullOrBlank() }
?: logAndReturnEmpty("Certificate PEM string is null or empty")
} catch (e: Exception) {
logAndReturnEmpty("Could not getImageTLSCert", e)
}
}
private fun induceSleep() {
try {
// induce half second sleep because sometimes a cert is not immediately available
// TODO : remove sleep if App no longer crashes on Android 10 devices with
// java.lang.RuntimeException: Could not invoke WebSocketModule.connect
Thread.sleep(SLEEP_DURATION)
} catch (e: InterruptedException) {
Log.e(TAG, "Sleep interrupted", e)
}
}
private fun logAndReturnNull(message: String, e: Exception? = null): Nothing? {
Log.e(TAG, message, e)
return null
}
private fun logAndReturnEmpty(message: String, e: Exception? = null): String {
Log.e(TAG, message, e)
return ""
}
}
@@ -0,0 +1,44 @@
package im.status.ethereum;
import android.util.Log;
import com.facebook.react.modules.network.OkHttpClientFactory;
import com.facebook.react.modules.network.OkHttpClientProvider;
import okhttp3.OkHttpClient;
import okhttp3.Interceptor;
import okhttp3.tls.HandshakeCertificates;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.RuntimeException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import im.status.ethereum.module.StatusPackage;
class StatusOkHttpClientFactory implements OkHttpClientFactory {
public OkHttpClient createNewNetworkModuleClient() {
String certPem = StatusPackage.getImageTLSCert();
X509Certificate cert;
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
cert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(certPem.getBytes()));
} catch(Exception e) {
Log.e("StatusOkHttpClientFactory", "Could not parse certificate");
cert = null;
}
HandshakeCertificates clientCertificates = new HandshakeCertificates.Builder()
.addPlatformTrustedCertificates()
.addTrustedCertificate(cert)
.build();
return OkHttpClientProvider.createClientBuilder()
.sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager())
.build();
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

@@ -2,6 +2,4 @@
<resources> <resources>
<color name="alert_background">#ffffff</color> <color name="alert_background">#ffffff</color>
<color name="alert_text">#000000</color> <color name="alert_text">#000000</color>
<color name="splash_background">#09101C</color>
<color name="splash_status_bar_color">#ffffff</color>
</resources> </resources>
@@ -1,13 +0,0 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<style name="Theme.AppSplash" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">@color/splash_background</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/splash_logo</item>
<item name="windowSplashScreenAnimationDuration">1000</item>
<!-- Status bar and Nav bar configs -->
<item name="android:statusBarColor" tools:targetApi="l">@color/splash_background</item>
<item name="android:windowLightStatusBar">false</item>
<item name="postSplashScreenTheme">@style/DarkTheme</item>
</style>
</resources>
+11 -10
View File
@@ -4,18 +4,13 @@
* Project-wide gradle configuration properties for use by all modules * Project-wide gradle configuration properties for use by all modules
*/ */
ext { ext {
// kotlin_version is needed for react-native-camera-kit library RNNKotlinVersion = "1.4.31"
kotlin_version = project.kotlinPluginVersion
RNNKotlinVersion = project.kotlinPluginVersion
RNGH_kotlinVersion = project.kotlinPluginVersion
buildToolsVersion = project.buildToolsVersion buildToolsVersion = project.buildToolsVersion
minSdkVersion = Integer.valueOf(project.minSdkVersion) minSdkVersion = Integer.valueOf(project.minSdkVersion)
compileSdkVersion = Integer.valueOf(project.compileSdkVersion) compileSdkVersion = Integer.valueOf(project.compileSdkVersion)
targetSdkVersion = Integer.valueOf(project.targetSdkVersion) targetSdkVersion = Integer.valueOf(project.targetSdkVersion)
supportLibVersion = project.supportLibVersion supportLibVersion = project.supportLibVersion
gradlePluginVersion = project.gradlePluginVersion gradlePluginVersion = project.gradlePluginVersion
kotlinVersion = project.kotlinPluginVersion
ndkVersion = "25.2.9519653"
} }
buildscript { buildscript {
@@ -25,9 +20,10 @@ buildscript {
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${project.ext.kotlinPluginVersion}" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.31"
classpath("com.android.tools.build:gradle") classpath "com.android.tools.build:gradle:${project.ext.gradlePluginVersion}"
classpath("com.facebook.react:react-native-gradle-plugin") // WARNING: Do not place your application dependencies here!
// They belong in the individual module build.gradle files.
} }
} }
@@ -52,14 +48,19 @@ allprojects {
throw new GradleException('STATUS_GO_ANDROID_LIBDIR environment variable is not valid!') throw new GradleException('STATUS_GO_ANDROID_LIBDIR environment variable is not valid!')
} }
} }
repositories { repositories {
mavenLocal() mavenLocal()
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
maven { url("$rootDir/../node_modules/react-native/android") }
// Android JSC is installed from npm // Android JSC is installed from npm
maven { url("$rootDir/../node_modules/jsc-android/dist") } maven { url("$rootDir/../node_modules/jsc-android/dist") }
// For geth, function, and status-go // For geth, function, and status-go
flatDir { dirs "libs", System.env.STATUS_GO_ANDROID_LIBDIR } flatDir { dirs "libs", System.env.STATUS_GO_ANDROID_LIBDIR }
// Everything Else
google() google()
jcenter() // Required for @react-native-community/blur:3.6.1, can be removed after updating to 3.6.1+
mavenCentral() mavenCentral()
maven { url 'https://mvnrepository.com/artifact/com.github.gundy/semver4j'} maven { url "https://www.jitpack.io" }
} }
} }
+10 -18
View File
@@ -21,14 +21,14 @@
# $keytool -genkey -v -keystore ./status-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias status # $keytool -genkey -v -keystore ./status-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias status
# Version requirements used throughout the Gradle scripts # Version requirements used throughout the Gradle scripts
minSdkVersion=24 kotlinVersion=1.3.50
compileSdkVersion=33 minSdkVersion=23
targetSdkVersion=33 compileSdkVersion=31
buildToolsVersion=33.0.0 targetSdkVersion=31
buildToolsVersion=31.0.0
supportLibVersion=28.0.0 supportLibVersion=28.0.0
# This should match version from nix/pkgs/aapt2/default.nix # This should match version from nix/mobile/android/maven-and-npm-deps/maven/default.nix
gradlePluginVersion=7.4.2 gradlePluginVersion=3.5.4
kotlinPluginVersion=1.9.0
android.useAndroidX=true android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
@@ -41,20 +41,12 @@ KEYSTORE_KEY_PASSWORD=password
# By default we build a mostly universal APK # By default we build a mostly universal APK
ANDROID_ABI_SPLIT=false ANDROID_ABI_SPLIT=false
# Some platforms are excluded though # Some platforms are excluded though
ANDROID_ABI_INCLUDE=armeabi-v7a;arm64-v8a;x86;x86_64 ANDROID_ABI_INCLUDE=armeabi-v7a;arm64-v8a;x86
org.gradle.jvmargs=-Xmx8704M org.gradle.jvmargs=-Xmx8704M
versionCode=9999 versionCode=9999
commitHash=unknown commitHash=unknown
# Use this property to enable support to the new architecture. # Flipper
# This will allow you to use TurboModules and the Fabric render in FLIPPER_VERSION=0.54.0
# your application. You should enable this flag either if you want
# to write custom TurboModules/Fabric components OR use libraries that
# are providing them.
newArchEnabled=false
# Use this property to enable or disable the Hermes JS engine.
# If set to false, you will be using JSC instead.
hermesEnabled=true
+2 -1
View File
@@ -12,10 +12,11 @@ apply from: file("../node_modules/@react-native-community/cli-platform-android/n
include ':react-native-nfc-manager' include ':react-native-nfc-manager'
project(':react-native-nfc-manager').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-nfc-manager/android') project(':react-native-nfc-manager').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-nfc-manager/android')
include ':app' include ':app'
include ':react-native-dialogs'
project(':react-native-dialogs').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-dialogs/android')
include ':react-native-status' include ':react-native-status'
project(':react-native-status').projectDir = new File(rootProject.projectDir, '../modules/react-native-status/android') project(':react-native-status').projectDir = new File(rootProject.projectDir, '../modules/react-native-status/android')
include ':react-native-status-keycard' include ':react-native-status-keycard'
project(':react-native-status-keycard').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-status-keycard/android') project(':react-native-status-keycard').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-status-keycard/android')
include ':react-native-blur' include ':react-native-blur'
project(':react-native-blur').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/blur/android') project(':react-native-blur').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/blur/android')
includeBuild('../node_modules/@react-native/gradle-plugin')
+1 -1
View File
@@ -1,4 +1,4 @@
{ {
"name": "StatusIm", "name": "StatusIm",
"displayName": "StatusIm" "displayName": "StatusIm"
} }
+23 -18
View File
@@ -1,19 +1,24 @@
module.exports = { module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: ['react-native-reanimated/plugin', '@babel/plugin-transform-named-capturing-groups-regex'], "presets": [
env: { "module:metro-react-native-babel-preset"
test: { ],
presets: [ "plugins": [
'@babel/preset-react', "react-native-reanimated/plugin"
[ ],
'@babel/preset-env', "env": {
{ "test": {
targets: { "presets": [
node: 'current', '@babel/preset-react',
}, [
}, '@babel/preset-env',
], {
], targets: {
}, node: '14',
}, },
}; },
],
],
}
}
}
+16 -5
View File
@@ -1,11 +1,10 @@
#!/usr/bin/env groovy library 'status-jenkins-lib@v1.6.3'
library 'status-jenkins-lib@v1.8.4'
/* Options section can't access functions in objects. */ /* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild() def isPRBuild = utils.isPRBuild()
pipeline { pipeline {
agent { label 'linux && x86_64 && nix-2.14' } agent { label 'linux && x86_64 && nix-2.11' }
options { options {
timestamps() timestamps()
@@ -41,12 +40,16 @@ pipeline {
BUILD_ENV = 'prod' BUILD_ENV = 'prod'
NIX_CONF_DIR = "${env.WORKSPACE}/nix" NIX_CONF_DIR = "${env.WORKSPACE}/nix"
FASTLANE_DISABLE_COLORS = 1 FASTLANE_DISABLE_COLORS = 1
/* coverage report identification */
COVERALLS_SERVICE_NAME = "jenkins"
COVERALLS_SERVICE_JOB_ID = "${JOB_NAME}#${BUILD_NUMBER}"
} }
stages { stages {
stage('Prep') { stage('Prep') {
steps { steps {
script { script {
utils.doGitRebasePR()
utils.symlinkEnv() utils.symlinkEnv()
println("Build Number: ${utils.genBuildNumber()}") println("Build Number: ${utils.genBuildNumber()}")
} }
@@ -72,12 +75,20 @@ pipeline {
stage('Upload') { stage('Upload') {
steps { script { steps { script {
def urls = apks.collect { s3.uploadArtifact(it) } def urls = apks.collect { s3.uploadArtifact(it) }
if (urls.size() > 1) { /* Return only the universal APK. */ /* return only the universal APK */
if (urls.size() > 1) {
env.PKG_URL = urls.find { it.contains('universal') } env.PKG_URL = urls.find { it.contains('universal') }
} else { /* If no universal is available pick first. */ } else { /* if no universal is available pick first */
env.PKG_URL = urls.first() env.PKG_URL = urls.first()
} }
jenkins.setBuildDesc(APK: env.PKG_URL) jenkins.setBuildDesc(APK: env.PKG_URL)
/* e2e builds get tested in SauceLabs */
if (utils.isE2EBuild()) {
env.SAUCE_URL = android.uploadToSauceLabs()
}
if (utils.isNightlyBuild()) {
env.DIAWI_URL = android.uploadToDiawi()
}
} } } }
} }
} }
+20 -5
View File
@@ -1,5 +1,4 @@
#!/usr/bin/env groovy library 'status-jenkins-lib@v1.6.3'
library 'status-jenkins-lib@v1.8.4'
pipeline { pipeline {
agent { label 'linux' } agent { label 'linux' }
@@ -18,7 +17,7 @@ pipeline {
} }
/* WARNING: Defining parameters here with the ?: trick causes them to remember last value. */ /* WARNING: Defining parameters here with the ?: trick causes them to remember last value. */
parameters { parameters {
choice( choice(
name: 'BUILD_TYPE', name: 'BUILD_TYPE',
description: 'Makefile target to build. Optional Parameter.', description: 'Makefile target to build. Optional Parameter.',
@@ -47,6 +46,9 @@ pipeline {
stage('Android') { steps { script { stage('Android') { steps { script {
apk = jenkins.Build('status-mobile/platforms/android') apk = jenkins.Build('status-mobile/platforms/android')
} } } } } }
stage('Android e2e') { steps { script {
apke2e = jenkins.Build('status-mobile/platforms/android-e2e')
} } }
stage('Tests') { steps { script { stage('Tests') { steps { script {
jenkins.Build('status-mobile/platforms/tests') jenkins.Build('status-mobile/platforms/tests')
} } } } } }
@@ -56,7 +58,9 @@ pipeline {
steps { script { steps { script {
sh('rm -f pkg/*') sh('rm -f pkg/*')
jenkins.copyArts(ios) jenkins.copyArts(ios)
//jenkins.copyArts(iose2e)
jenkins.copyArts(apk) jenkins.copyArts(apk)
jenkins.copyArts(apke2e)
sha = "pkg/${utils.pkgFilename(ext: 'sha256')}" sha = "pkg/${utils.pkgFilename(ext: 'sha256')}"
dir('pkg') { dir('pkg') {
/* generate sha256 checksums for upload */ /* generate sha256 checksums for upload */
@@ -70,8 +74,8 @@ pipeline {
/* object for easier URLs handling */ /* object for easier URLs handling */
urls = [ urls = [
/* mobile */ /* mobile */
Apk: utils.pkgUrl(apk), Apk: utils.pkgUrl(apk), Apke2e: utils.pkgUrl(apke2e),
iOS: utils.pkgUrl(ios), iOS: utils.pkgUrl(ios), /*iOSe2e: utils.pkgUrl(iose2e),*/
Diawi: utils.getEnv(ios, 'DIAWI_URL'), Diawi: utils.getEnv(ios, 'DIAWI_URL'),
/* upload the sha256 checksums file too */ /* upload the sha256 checksums file too */
SHA: s3.uploadArtifact(sha), SHA: s3.uploadArtifact(sha),
@@ -95,6 +99,17 @@ pipeline {
} }
} } } }
} }
stage('Run e2e') {
when { expression { btype == 'nightly' && params.PUBLISH } }
steps { script {
e2eApk = utils.getEnv(apke2e, 'SAUCE_URL')
build(
job: 'status-mobile/e2e/status-app-nightly',
parameters: [string(name: 'APK_NAME', value: e2eApk)],
wait: false
)
} }
}
} }
} }
-51
View File
@@ -1,51 +0,0 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.4'
pipeline {
agent { label 'linux' }
triggers {
// Nightly at 2am
cron 'H 2 * * *'
}
parameters {
string(
name: 'BRANCH',
description: 'Name of the branch to checkout and build.',
defaultValue: 'develop',
)
}
options {
timestamps()
disableConcurrentBuilds()
buildDiscarder(logRotator(
numToKeepStr: '10',
daysToKeepStr: '30',
))
}
stages {
stage('Build') {
steps {
script {
apk_build = jenkins.Build('status-mobile/platforms/android-e2e')
apk_build_number = apk_build.getNumber().toString()
}
}
}
stage('Run e2e') {
steps {
build(
job: 'status-mobile/e2e/status-app-nightly',
parameters: [
string(name: 'APK_BUILD_NUMBER', value: apk_build_number),
string(name: 'BRANCH', value: env.BRANCH),
]
)
}
}
}
}
+9 -11
View File
@@ -1,11 +1,10 @@
#!/usr/bin/env groovy library 'status-jenkins-lib@v1.6.3'
library 'status-jenkins-lib@v1.8.4'
/* Options section can't access functions in objects. */ /* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild() def isPRBuild = utils.isPRBuild()
pipeline { pipeline {
agent { label 'macos && arm64 && nix-2.14 && xcode-15.1' } agent { label 'macos && x86_64 && nix-2.11 && xcode-13.4' }
parameters { parameters {
string( string(
@@ -49,6 +48,7 @@ pipeline {
stage('Prep') { stage('Prep') {
steps { steps {
script { script {
utils.doGitRebasePR()
utils.symlinkEnv() utils.symlinkEnv()
println("Build Number: ${utils.genBuildNumber()}") println("Build Number: ${utils.genBuildNumber()}")
} }
@@ -63,11 +63,6 @@ pipeline {
steps { steps {
script { api = ios.bundle() } script { api = ios.bundle() }
} }
post {
failure {
archiveArtifacts 'ios/logs/*'
}
}
} }
stage('Parallel Upload') { stage('Parallel Upload') {
parallel { parallel {
@@ -78,11 +73,14 @@ pipeline {
} }
stage('Upload') { stage('Upload') {
steps { script { steps { script {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { env.PKG_URL = s3.uploadArtifact(api)
jenkins.setBuildDesc(IPA: env.PKG_URL)
/* e2e builds get tested in SauceLabs */
if (utils.isE2EBuild()) {
env.SAUCE_URL = ios.uploadToSauceLabs()
} else if (!utils.isReleaseBuild()) {
env.DIAWI_URL = ios.uploadToDiawi() env.DIAWI_URL = ios.uploadToDiawi()
} }
env.PKG_URL = env.DIAWI_URL
jenkins.setBuildDesc(IPA: env.PKG_URL)
} } } }
} }
} }
+116
View File
@@ -0,0 +1,116 @@
library 'status-jenkins-lib@v1.6.3'
pipeline {
agent { label params.AGENT_LABEL }
parameters {
string(
name: 'NIX_CACHE_HOST',
description: 'FQDN of Nix binary cache host.',
defaultValue: params.NIX_CACHE_HOST ?: 'cache-01.do-ams3.nix.ci.statusim.net'
)
string(
name: 'NIX_CACHE_USER',
description: 'Username for Nix binary cache host.',
defaultValue: params.NIX_CACHE_USER ?: 'nix-cache'
)
}
environment {
/* See nix/README.md */
NIX_IGNORE_SYMLINK_STORE = 1
/* we source .bash_profile to be able to use nix-store */
NIX_SSHOPTS = "-o StrictHostKeyChecking=no source .profile;"
NIX_CONF_DIR = "${env.WORKSPACE}/nix"
}
options {
timestamps()
disableConcurrentBuilds()
/* Prevent Jenkins jobs from running forever */
timeout(time: 300, unit: 'MINUTES')
/* Limit builds retained */
buildDiscarder(logRotator(
numToKeepStr: '20',
daysToKeepStr: '30',
))
}
stages {
stage('Setup') {
steps { script {
nix.shell('nix-env -i openssh', sandbox: false, pure: false)
/* some build targets don't build on MacOS */
uname = sh(script: 'uname', returnStdout: true)
} }
}
stage('Build status-go') {
steps { script {
def platforms = ['mobile.android', 'mobile.ios']
if (uname != "Darwin") {
platforms.removeAll { it == "ios" }
}
platforms.each { os ->
nix.build(
attr: "targets.status-go.${os}.buildInputs",
sandbox: false,
link: false
)
}
} }
}
stage('Build android jsbundle') {
steps { script {
/* build/fetch things required to produce a js-bundle for android
* (e.g. maven and node repos) */
nix.build(
attr: 'targets.mobile.android.jsbundle',
sandbox: false,
pure: false,
link: false
)
} }
}
stage('Build android deps') {
steps { script {
/* build/fetch things required to build jsbundle and android */
nix.build(
attr: 'targets.mobile.android.release.buildInputs',
sandbox: false,
pure: false,
link: false
)
} }
}
stage('Build nix shell deps') {
steps { script {
/* build/fetch things required to instantiate shell.nix for TARGET=all */
nix.build(
attr: 'shells.default.buildInputs',
sandbox: false,
link: false
)
} }
}
stage('Upload') {
steps { script {
sshagent(credentials: ['nix-cache-ssh']) {
nix.shell("""
find /nix/store/ -mindepth 1 -maxdepth 1 -type d \
-not -name '*.links' -and -not -name '*-status-mobile-*' \
| xargs nix copy \
--to ssh-ng://${params.NIX_CACHE_USER}@${params.NIX_CACHE_HOST}
""",
pure: false
)
}
} }
}
}
post {
always { script {
nix.shell('nix-store --optimize', pure: false)
nix.shell('nix/scripts/clean.sh', pure: false)
} }
}
}
+13 -23
View File
@@ -1,16 +1,15 @@
#!/usr/bin/env groovy library 'status-jenkins-lib@v1.6.3'
library 'status-jenkins-lib@v1.8.4'
/* Options section can't access functions in objects. */ /* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild() def isPRBuild = utils.isPRBuild()
pipeline { pipeline {
agent { label 'linux && x86_64 && nix-2.14' } agent { label 'linux && x86_64 && nix-2.11' }
options { options {
timestamps() timestamps()
/* Prevent Jenkins jobs from running forever */ /* Prevent Jenkins jobs from running forever */
timeout(time: 15, unit: 'MINUTES') timeout(time: 10, unit: 'MINUTES')
/* Limit builds retained */ /* Limit builds retained */
buildDiscarder(logRotator( buildDiscarder(logRotator(
numToKeepStr: '10', numToKeepStr: '10',
@@ -42,42 +41,33 @@ pipeline {
} }
stages { stages {
stage('Prep') {
steps {
script {
utils.doGitRebasePR()
}
}
}
stage('Checks') { stage('Checks') {
parallel { parallel {
stage('Lint') { stage('Lint') {
steps { steps {
sh """#!/bin/bash sh """#!/bin/bash
set -eo pipefail set -eo pipefail
make lint CLJ_LINTER_PRINT_WARNINGS=true 2>&1 | tee ${LOG_FILE} make lint 2>&1 | tee ${LOG_FILE}
""" """
} }
} }
stage('Unit Tests') { stage('Tests') {
steps { steps {
sh """#!/bin/bash sh """#!/bin/bash
set -eo pipefail set -eo pipefail
make test-unit 2>&1 | tee -a ${LOG_FILE} make test 2>&1 | tee -a ${LOG_FILE}
""" """
} }
} }
} }
} }
stage('Integration Tests') {
steps {
sh """#!/bin/bash
set -eo pipefail
make test-integration 2>&1 | tee -a ${LOG_FILE}
"""
}
}
stage('Component Tests') {
steps {
sh """#!/bin/bash
set -eo pipefail
make component-test 2>&1 | tee -a ${LOG_FILE}
"""
}
}
stage('Upload') { stage('Upload') {
steps { steps {
script { script {
+5 -33
View File
@@ -1,49 +1,25 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.15'
pipeline { pipeline {
agent { label 'linux' } agent { label 'linux' }
parameters { parameters {
string( string(
name: 'APK_BUILD_NUMBER', name: 'APK_NAME',
description: 'platform/e2e build number for apk artifact', description: 'Filename of APK uploaded to SauceLabs.',
) )
string( string(
name: 'KEYWORD_EXPRESSION', name: 'KEYWORD_EXPRESSION',
description: 'This will run tests which contain names that match the given string expression (Optional)', description: 'This will run tests which contain names that match the given string expression (Optional)',
defaultValue: '', defaultValue: '',
) )
string(
name: 'BRANCH',
description: 'Name of the branch to checkout and build.',
defaultValue: 'develop',
)
string(
name: 'TR_CASE_IDS',
description: 'IDs of the TestRail case, separated by a comma (Optional)',
defaultValue: '',
)
} }
options { options {
disableConcurrentBuilds() disableConcurrentBuilds()
} }
stages { stages {
stage('Fetch') {
steps { script {
copyArtifacts(
projectName: "status-mobile/platforms/android-e2e",
filter: 'result/*-x86_64.apk',
selector: specific(env.APK_BUILD_NUMBER),
)
apk_path = "${env.WORKSPACE}/${utils.findFile('result/*-x86_64.apk')}"
} }
}
stage('Setup') { stage('Setup') {
steps { script { steps { script {
dir('test/appium') { dir('test/appium') {
@@ -51,7 +27,6 @@ pipeline {
} }
} } } }
} }
stage('Test') { stage('Test') {
steps { steps {
withCredentials([ withCredentials([
@@ -83,13 +58,13 @@ pipeline {
sh 'cp -f $TEST_ETH_ACCOUNTS_FILE users.py' sh 'cp -f $TEST_ETH_ACCOUNTS_FILE users.py'
sh """ sh """
python3 -m pytest \ python3 -m pytest \
--numprocesses 8 \ --numprocesses 9 \
--rerun_count=2 \ --rerun_count=2 \
--testrail_report=True \ --testrail_report=True \
-m testrail_id \ -m testrail_id \
-m \"new_ui_critical or new_ui_medium\" \ -m \"new_ui_critical or new_ui_medium\" \
-k \"${params.KEYWORD_EXPRESSION}\" \ -k \"${params.KEYWORD_EXPRESSION}\" \
--apk=${params.APK_URL ?: apk_path} --apk=${params.APK_NAME}
""" """
} }
} }
@@ -113,8 +88,5 @@ pipeline {
) )
} }
} }
cleanup {
sh 'make purge'
}
} }
} }
+17 -46
View File
@@ -1,5 +1,4 @@
#!/usr/bin/env groovy library 'status-jenkins-lib@v1.6.3'
library 'status-jenkins-lib@v1.7.15'
pipeline { pipeline {
@@ -11,14 +10,20 @@ pipeline {
description: 'Name of the branch to checkout and build.', description: 'Name of the branch to checkout and build.',
defaultValue: 'develop', defaultValue: 'develop',
) )
/* Commented to use TEST_MARKERS values from job params
string(
name: 'TEST_MARKERS',
description: 'Marker expression for matching tests to run.',
defaultValue: 'new_ui_critical',
) */
string(
name: 'APK_NAME',
description: 'Filename of APK uploaded to SauceLabs, path, or URL.',
)
string( string(
name: 'PR_ID', name: 'PR_ID',
description: 'ID of the Pull Request triggering this build.', description: 'ID of the Pull Request triggering this build.',
) )
string(
name: 'APK_URL',
description: 'Optional, set if job require APK to be downloaded from URL.',
)
string( string(
name: 'KEYWORD_EXPRESSION', name: 'KEYWORD_EXPRESSION',
description: 'This will run tests which contain names that match the given string expression (Optional)', description: 'This will run tests which contain names that match the given string expression (Optional)',
@@ -29,48 +34,19 @@ pipeline {
description: 'IDs of the TestRail case, separated by a comma (Optional)', description: 'IDs of the TestRail case, separated by a comma (Optional)',
defaultValue: '', defaultValue: '',
) )
/* FIXME: Remove this no longer relevant argument */
string(
name: 'APK_NAME',
description: 'OBSOLETE ARGUMENT TO BE REMOVED',
defaultValue: 'DUMMY',
)
/* Commented to use TEST_MARKERS values from job params
string(
name: 'TEST_MARKERS',
description: 'Marker expression for matching tests to run.',
defaultValue: 'new_ui_critical',
)
*/
} }
options { options {
disableConcurrentBuilds() disableConcurrentBuilds()
timeout(time: 90, unit: 'MINUTES')
} }
stages { stages {
stage('Prep') { stage('Checks') {
steps { script { steps { script {
currentBuild.displayName = "PR-${params.PR_ID}" if (params.APK_NAME == null) { error("APK_NAME parameter not set!") }
if (params.PR_ID == null) { if (params.PR_ID == null) { error("PR_ID parameter not set!") }
error("PR_ID parameter not set!")
}
} } } }
} }
stage('Fetch') {
when { expression { !params.APK_URL } }
steps { script {
copyArtifacts(
projectName: "status-mobile/prs/android-e2e/PR-${params.PR_ID}",
/* WARNING: This copies the latest available artifact. */
selector: lastWithArtifacts(),
)
apk_path = "${env.WORKSPACE}/${utils.findFile('result/*.apk')}"
} }
}
stage('Setup') { stage('Setup') {
steps { script { steps { script {
dir('test/appium') { dir('test/appium') {
@@ -78,9 +54,9 @@ pipeline {
} }
} } } }
} }
stage('Test') { stage('Test') {
steps { script { steps { script {
currentBuild.displayName = "PR-${params.PR_ID}"
/* for managing optional arguments */ /* for managing optional arguments */
def extraPytestOpts = '' def extraPytestOpts = ''
if (params.TR_CASE_IDS != '') { if (params.TR_CASE_IDS != '') {
@@ -123,11 +99,11 @@ pipeline {
sh 'cp -f $TEST_ETH_ACCOUNTS_FILE users.py' sh 'cp -f $TEST_ETH_ACCOUNTS_FILE users.py'
sh """ sh """
python3 -m pytest \ python3 -m pytest \
--numprocesses 8 \ --numprocesses 9 \
--rerun_count=2 \ --rerun_count=2 \
--testrail_report=True \ --testrail_report=True \
-k \"${params.KEYWORD_EXPRESSION}\" \ -k \"${params.KEYWORD_EXPRESSION}\" \
--apk=${params.APK_URL ?: apk_path} \ --apk=${params.APK_NAME} \
--build=PR-${params.PR_ID}-${utils.timestamp()} \ --build=PR-${params.PR_ID}-${utils.timestamp()} \
--pr_number=${params.PR_ID} \ --pr_number=${params.PR_ID} \
${extraPytestOpts} ${extraPytestOpts}
@@ -137,9 +113,4 @@ pipeline {
} } } }
} }
} }
post {
cleanup {
sh 'make purge'
}
}
} }
+7 -25
View File
@@ -1,18 +1,15 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.15'
pipeline { pipeline {
agent { label 'linux' } agent { label 'linux' }
parameters { parameters {
string( string(
name: 'APK_URL', name: 'APK_NAME',
description: 'URL of APK to be tested(base for upgrade, usually release build)', description: 'Filename of APK uploaded to SauceLabs (base for upgrade, usually release build)',
) )
string( string(
name: 'APK_URL_UPGRADE', name: 'APK_NAME_UPGRADE',
description: 'URL of APK of upgraded application (installed on top of base)', description: 'Filename of APK of upgraded application (installed on top of base)',
) )
string( string(
name: 'KEYWORD_EXPRESSION', name: 'KEYWORD_EXPRESSION',
@@ -32,17 +29,6 @@ pipeline {
stages { stages {
stage('Prep') {
steps { script {
if (params.APK_URL == null) {
error("APK_URL parameter not set!")
}
if (params.APK_URL_UPGRADE == null) {
error("APK_URL_UPGRADE parameter not set!")
}
} }
}
stage('Setup') { stage('Setup') {
steps { script { steps { script {
dir('test/appium') { dir('test/appium') {
@@ -50,7 +36,6 @@ pipeline {
} }
} } } }
} }
stage('Test') { stage('Test') {
steps { script { steps { script {
/* for managing optional arguments */ /* for managing optional arguments */
@@ -89,11 +74,11 @@ pipeline {
python3 -m pytest \ python3 -m pytest \
-m "upgrade" \ -m "upgrade" \
-k \"${params.KEYWORD_EXPRESSION}\" \ -k \"${params.KEYWORD_EXPRESSION}\" \
--numprocesses 4 \ --numprocesses 15 \
--rerun_count=2 \ --rerun_count=2 \
--testrail_report=True \ --testrail_report=True \
--apk=${params.APK_URL} \ --apk=${params.APK_NAME} \
--apk_upgrade=${params.APK_URL_UPGRADE} \ --apk_upgrade=${params.APK_NAME_UPGRADE} \
${extraPytestOpts} ${extraPytestOpts}
""" """
} }
@@ -118,8 +103,5 @@ pipeline {
) )
} }
} }
cleanup {
sh 'make purge'
}
} }
} }
+1 -2
View File
@@ -1,5 +1,4 @@
#!/usr/bin/env groovy library 'status-jenkins-lib@v1.6.3'
library 'status-jenkins-lib@v1.7.15'
pipeline { pipeline {
agent { label 'macos' } agent { label 'macos' }
-138
View File
@@ -1,138 +0,0 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.15'
pipeline {
agent { label params.AGENT_LABEL }
parameters {
string(
name: 'NIX_CACHE_HOST',
description: 'FQDN of Nix binary cache host.',
defaultValue: params.NIX_CACHE_HOST ?: 'cache-01.do-ams3.nix.ci.statusim.net'
)
string(
name: 'NIX_CACHE_USER',
description: 'Username for Nix binary cache host.',
defaultValue: params.NIX_CACHE_USER ?: 'nix-cache'
)
}
environment {
/* See nix/README.md */
NIX_IGNORE_SYMLINK_STORE = 1
/* we source .bash_profile to be able to use nix-store */
NIX_SSHOPTS = "-oStrictHostKeyChecking=no"
NIX_CONF_DIR = "${env.WORKSPACE}/nix"
NIX_STORE_CMD = '/nix/var/nix/profiles/default/bin/nix-store'
NIX_SSH_REMOTE = "ssh://${params.NIX_CACHE_USER}@${params.NIX_CACHE_HOST}?remote-program=${env.NIX_STORE_CMD}"
}
options {
timestamps()
disableConcurrentBuilds()
/* Prevent Jenkins jobs from running forever */
timeout(time: 120, unit: 'MINUTES')
/* Limit builds retained */
buildDiscarder(logRotator(
numToKeepStr: '20',
daysToKeepStr: '30',
))
}
stages {
stage('Setup') {
steps { script {
nix.shell('nix-env -i openssh', sandbox: false, pure: false)
/* some build targets don't build on MacOS */
os = sh(script: 'uname', returnStdout: true).trim()
arch = sh(script: 'arch', returnStdout: true).trim()
} }
}
stage('Build status-go') {
steps { script {
def platforms = ['mobile.android', 'mobile.ios', 'library']
if (os != 'Darwin') { platforms.removeAll { it == 'mobile.ios' } }
/* FIXME: "'x86_64-darwin' with features {} is required to build" */
if (arch == 'arm64') { platforms.removeAll { it == 'mobile.android' } }
platforms.each { platform ->
/* Allow for Android builds on Apple ARM. */
env.NIXPKGS_SYSTEM_OVERRIDE = nixSysOverride(os, arch, platform)
nix.build(
attr: "targets.status-go.${platform}",
sandbox: false,
link: false
)
}
} }
}
stage('Build android jsbundle') {
steps { script {
/* Build/fetch deps required for jsbundle build. */
nix.build(
attr: 'targets.mobile.jsbundle',
sandbox: false,
pure: false,
link: false
)
} }
}
stage('Build android deps') {
steps { script {
/* Allow for Android builds on Apple ARM. */
env.NIXPKGS_SYSTEM_OVERRIDE = nixSysOverride(os, arch, 'android')
/* Build/fetch deps required to build android release. */
nix.build(
attr: 'targets.mobile.android.release.buildInputs',
sandbox: false,
pure: false,
link: false
)
} }
}
stage('Build nix shell deps') {
steps { script {
def shells = ['android', 'ios', 'fastlane', 'keytool', 'clojure', 'gradle']
if (os != 'Darwin') { shells.removeAll { it == 'ios' } }
/* FIXME: "'x86_64-darwin' with features {} is required to build" */
if (arch == 'arm64') { shells.removeAll { it == 'android' } }
/* Build/fetch deps required to start default Nix shell. */
shells.each { shell ->
/* Allow for Android builds on Apple ARM. */
env.NIXPKGS_SYSTEM_OVERRIDE = nixSysOverride(os, arch, shell)
nix.build(
attr: "shells.${shell}.buildInputs",
sandbox: false,
link: false
)
}
} }
}
stage('Upload') {
steps { script {
sshagent(credentials: ['nix-cache-ssh']) {
nix.shell("""
find /nix/store/ -mindepth 1 -maxdepth 1 -type d \
-not -name '*.links' -and -not -name '*-status-mobile-*' \
| xargs nix copy --to ${NIX_SSH_REMOTE}
""",
pure: false
)
}
} }
}
}
post {
always { script {
nix.shell('nix-store --optimize', pure: false)
nix.shell('nix/scripts/clean.sh', pure: false)
} }
}
}
def nixSysOverride(os, arch, target='android') {
return (
os == 'Darwin' &&
arch == 'arm64' &&
target =~ /.*android$/
) ? 'x86_64-darwin' : ''
}
+1 -2
View File
@@ -1,5 +1,4 @@
#!/usr/bin/env groovy library 'status-jenkins-lib@v1.6.3'
library 'status-jenkins-lib@v1.7.15'
pipeline { pipeline {
agent { label 'linux' } agent { label 'linux' }
-1
View File
@@ -1,4 +1,3 @@
#!/usr/bin/env groovy
/** /**
* This job runs daily and executes `pod repo update` on MacOS * This job runs daily and executes `pod repo update` on MacOS
* This is done to avoid issues with out of date repo causing errors like: * This is done to avoid issues with out of date repo causing errors like:
-48
View File
@@ -1,48 +0,0 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.15'
pipeline {
agent {
label 'linux'
}
triggers {
cron('H 5 * * *')
}
options {
timestamps()
/* Prevent Jenkins jobs from running forever */
timeout(time: 15, unit: 'MINUTES')
/* Disable concurrent jobs */
disableConcurrentBuilds()
/* Don't keep more than 50 builds */
buildDiscarder(logRotator(numToKeepStr: '10'))
}
stages {
stage('Get Nodes') {
steps { script {
stagePerNode = nodesByLabel('macos').collectEntries {
["${it}" : generateNodeCleanupStage(it)]
}
} }
}
stage('Clean Xcode') {
steps { script {
parallel stagePerNode
} }
}
}
}
def generateNodeCleanupStage(nodeLabel) {
return { stage(nodeLabel) {
node(nodeLabel) {
dir('/Users/jenkins/Library/Developer/Xcode') {
sh 'rm -fr Archives DerivedData'
}
}
} }
}
View File
+15
View File
@@ -0,0 +1,15 @@
# new icons
## Export icons
![](./export-icons.gif)
1. Export from figma 2 pngs 2x and 3x put them in `./resources/images/icons`
2. if necessary, rename file so that filename contains only lower case chars, e.g. `"Icon-Name@2x.png"` should be renamed to `"icon_name@2x.png"`.
3. In the app `icon_name.png` still can be accessed as `icon-name`, so in order to use can add the next code:
```clojure
;; icon_name.png
[vector-icons/icon :icon-name {:color ...}]
```
2x@2x
4. If you want paltform specific icon use `.android` or `.ios` suffixes. Example `icon_name@2x.android.png`.:w
+202
View File
@@ -0,0 +1,202 @@
# Setup your Editor/IDE
You can use any Clojure enabled editor. Here are instructions for developing the status-mobile app using:
* IntelliJ IDEA and Cursive
* VS Code and Calva
* Emacs/Cider
(Please add instructions for your favorite editor.)
## Table of Contents
- [Using Cursive](#using-cursive)
- [Install Cursive](#install-cursive)
- [Getting Cursive to understand `status-mobile`](#getting-cursive-to-understand-status-mobile)
- [I get a lot of `cannot be resolved`](#i-get-a-lot-of-cannot-be-resolved)
- [REPL!](#repl)
- [Connecting to REPL to IntelliJ](#connecting-to-repl-to-intellij)
- [Connecting REPL and IntelliJ to `status-mobile`](#connecting-repl-and-intellij-to-status-mobile)
- [Using Calva](#using-calva)
- [Start and connect the REPL](#start-and-connect-the-repl)
- [Use the REPL](#use-the-repl)
## Using Cursive
### Install Cursive
See https://cursive-ide.com/userguide/index.html
### Getting Cursive to understand `status-mobile`
- Add this file to the root of the `status-mobile` project dir
- https://gist.github.com/Samyoul/f71a0593ba7a12d24dd0d5ef986ebbec
- Right click and "add as leiningen project"
<img src="images/IDE_SETUP/1_fake_project_file.png" width=75% />
## I get a lot of `cannot be resolved`
Are you getting problems where you get a lot of `cannot be resolved` on everything?
<img src="images/IDE_SETUP/2_resolve.jpeg" width=75% />
See https://cursive-ide.com/userguide/macros.html
- opt+enter (on macOS)
- resolve defview as fn and letsubs as let
- move selection on resolve and hit enter
- and select defn for defview and let for letsubs
### REPL!
#### Connecting to REPL to IntelliJ
I had a number of problems connecting to REPL, the solution is as follows:
At the top of IntelliJ IDEA click on the `Add Configuration...` option:
<img src="images/IDE_SETUP/3_REPL_1.png" width=75% />
This will load the following menu:
<img src="images/IDE_SETUP/4_REPL_2.png" width=75% />
Click on the `+` icon in the top left corner of the menu.
Select `Clojure REPL > Remote`
<img src="images/IDE_SETUP/5_REPL_3.png" width=75% />
Which will load the following menu
<img src="images/IDE_SETUP/6_REPL_4.png" width=75% />
Enter the below options:
- Name = status-mobile
- Display Name = status-mobile
- Connection type = nREPL
- Connection details
- Host = 127.0.0.1
- Port = 7888
<img src="images/IDE_SETUP/7_REPL_5.png" width=75% />
Press `OK`
Now the below option will be visible.
Press the green run button
<img src="images/IDE_SETUP/8_REPL_6.png" width=75% />
You should now see an dialog with the following message:
```shell
Connecting to remote nREPL server...
Clojure 1.10.1
```
To confirm you have a working connection with REPL enter the following command in the input box below the output:
```shell
(prn 1)
```
Which should output
```shell
(prn 1)
1
=> nil
```
See below:
<img src="images/IDE_SETUP/9_REPL_7.png" width=75% />
#### Connecting REPL and IntelliJ to `status-mobile`
**The important next step is telling REPL the context in which to interact with the code.**
Do the following:
Ensure you have 3 terminals running the following
- `make run-clojure`
- `make run-metro`
- `make run-ios` / `make run-android`
[See the STARTING GUIDE for details](STARTING_GUIDE.md#development)
Next go back to the REPL input and enter the following commands:
```clojure
(shadow/watch :mobile)
(shadow/repl :mobile)
```
See Below
<img src="images/IDE_SETUP/10_REPL_8.png" width="75%" />
Which should switch the clj file type target to cljs as shown above
Finally you are ready to test REPL.
Create a sample function to evaluate something simple like `(prn "I'm working")`, move your cursor to one of the outer parentheses. Right or `control` click and select the `REPL` option. From there select `Sync files in REPL` and then `Send '...' to REPL'`.
<img src="images/IDE_SETUP/11_REPL_9.png" width="75%" />
Alternatively you can use the shortcut commands `⇧⌘M` to sync your files and `⇧⌘P` to send the statement to REPL. You may also need to switch the REPL namespace to match the current file, which can be done manually from the dialogue box or using the `⇧⌘N` shortcut key.
Following the above should give you the below result:
<img src="images/IDE_SETUP/12_REPL_10.png" width="75%" />
🎉 Tada! Working! 🎉
---
For additional details on issues you may face when setting up REPL with Cursive [see this document](https://notes.status.im/9Gr7kqF8SzC_SmYK0eB7uQ?view#Connecting-Cursive--IntelliJ-IDEA-to-REPL-Problems)
## Using Calva
For VS Code users.
0. Install Calva.
### Start and connect the REPL
1. Open the `status-mobile` folder.
1. Start [Status development](STARTING_GUIDE.md#development) (Starting the `run-clojure` and `run-metro` jobs in split view in the VS Code integrated terminal works great.)
1. Run the VS Code command: **Calva: Connect to a running REPL Server in the project**
1. Select the project type `shadow-cljs`
1. Accept the suggested connection `host:port`
1. Select to connect to the `:mobile` build
### Use the REPL
Open any `.cljs` file in the project and evaluate forms in it. See https://calva.io/try-first/ for some starter tips and links. Confirm that your REPL is connected to the app by evaluating:
```clojure
(js/alert "Hello from Status App!")
```
🎉 Tada! You are ready to use the REPL to improve Status.im! 🎉
Please consider bookmarking [calva.io](https://calva.io/) for quick access to the Calva documentation.
## Using Emacs/Cider
1. Install Emacs/Cider/etc. (there is a lot of variability in how to manage things in emacs, so please google for help with this)
2. Add a local ~/.shadow-cljs/config.edn file like below (corresponding to the version numbers of the packages you are using):
```clojure
{:dependencies
[[nrepl/nrepl "0.9.0"]
[cider/cider-nrepl "0.28.4"]
[cider/piggieback "0.5.2"]]}
```
-63
View File
@@ -1,63 +0,0 @@
## Getting Started
[Starting Guide](starting-guide.md)
[IDE Setup](ide-setup.md)
## Development Process
[Coding guidelines](new-guidelines.md)
[Release Checklist](release-checklist.md)
[Release Guide](release-guide.md)
[Merging PR process](merging-pr-process.md)
[PR Review Policy](pr-review-policy.md)
[Working on PR together with QA team](pipeline_process.md)
[Debugging](debugging.md)
[Patching](patching.md)
[Creating a pixel perfect UI](pixel-perfection.md)
[Contributing to status-go](status-go-changes.md)
## Testing
[How to run local tests](testing.md)
[End-to-end tests (e2e) overview](how-to-launch-e2e.md)
[Component tests (jest) overview](component-tests-overview.md)
## Project details
[status-go introduction (recorded meeting)](https://drive.google.com/file/d/1B7TljmTZ8fHkqJH8ChU1Cp4FGDFM03gq/view)
[re-frame usage (recorded meeting)](https://drive.google.com/file/d/1qv_E0CEGzQpu_zGXD0gCTU5EvhC2k8Jy/view)
[status app functionality demo](https://drive.google.com/file/u/0/d/1PmwsMLTLDNNIdv5_6wvMOwoj2PfT50c6/view)
## Misc
[Importing icons from Figma into project](export-icons.md)
[Updating Status APK builds for the F-Droid Android application catalogue](fdroid.md)
[Troubleshooting for known errors](troubleshooting.md)
## Outdated:
[Old guidelines](codebase-structure-and-guidelines.md)
[Post mortem analysis](post-mortem.md)
+42
View File
@@ -0,0 +1,42 @@
This document MUST be updated everytime a PR has been identified has the source of a bug in develop. The post mortem analysis MUST include: the CAUSE of the bug, the RESOLUTION PROCESS and PREVENTION MEASURES.
# "sql: no rows in result set" error on iOS login
## Cause
There were errors in the iOS native code:
- "loginWithKeycard" method was not implemented
- "createAndLoginWithKeycard" method was actually used instead of "createAndLogin** which is used for regular account creation without keycard and doesn't have the same final argument
QA process was focused on account creation and login with keycard, and this bug would only appear specifically on iOS when creating an account without keycard and only during the next login. It was therefore a more complex path to reach than what could have been expected from this PR, and it was caused in develop by a developer working on iOS simulator because that is a common path during development.
## Resolution process
- the commit was reverted locally by the developer which fixed the issue localy and confirmed the faulty commit
- the bug was only reproducible on iOS which strongly hinted at a potential issue with native code
- the missing method was not the origin of the problem but was found at this point and further analysis lead to the shadowing error
## Prevention measures
- PRs that change native code should be checked for platform parity:
- same methods are created/modified for each platform
- test cases in the PR should take these methods in consideration
# Missing labels for en translation
https://github.com/status-im/status-mobile/issues/9003
## Cause
Unused labels in the application have been listed by QA and an issue created for their removal. The PR was made by an external contributor and it had to be rebased many time because it touched many files and other PRs got merged before this one could be tested. After a last rebase the PR was merged with 100% e2e test but no manual testing.
The reason some translations got deleted despite the fact that they were used is because the `message status` related labels were not explicitly mentioned in the code unlike every other labels. They were built from the actual `message status` and the prefix `status-`.
## Resolution process
The mistake was quickly noticed in develop and an issue created. The fix was to recover the 3 labels that were accidentally deleted.
## Prevention measures
The code has been changed so that the labels are no longer generated and appear in the code like other labels.
+98
View File
@@ -0,0 +1,98 @@
# Description
This document provides information on how to start developing Status App.
# Getting Started
To start developing start a shell for platform you are interested in.
```
make shell TARGET=android
```
This step will take a while the first time as it will download all dependencies.
# Development
There are three steps necessary to start development, in this case for Android:
1. `make run-clojure` - Compiles Clojure into JavaScript, watches for changes on cljs files, and hot-reloads code in the app.
2. `make run-metro` - Starts metro bundler and watches JavaScript code.
3. `make run-android` or `make run-ios` - Builds the Android/iOS app and starts it on the device.
The first two will continue watching for changes and keep re-building the app. They need to be ready first.
The last one will exit once the app is up and ready.
## Simulators and Devices
### Android
You need to have an emulator like [AVD](https://developer.android.com/studio/run/emulator), or [Genymotion](#genymotion-virtualization), or a real device running and visible to [adb](https://developer.android.com/studio/command-line/adb), before you run `make run-android`.
### iOS
You can specify the simulator type by adding the `SIMULATOR` flag:
```sh
make run-ios SIMULATOR="iPhone 11 Pro"
```
Some manual steps are necesary for [developing on a physical iOS Device](#physical-ios-device).
# Build release
To build the app, your can simply run on of the following:
```
make release-android
make release-ios
```
For more `make` targets run `make help`.
# Updating Dependencies
* `make nix-update-pods` - iOS CocoaPods dependencies (updates `ios/Podfile` and `ios/Podfile.loc`)
* `make nix-update-gradle` - Android Gradle/Maven dependencies (updates `nix/deps/gradle/deps.json`)
* `make nix-update-clojure` - Clojure Maven dependencies (updates `nix/deps/clojure/deps.json`)
* `make nix-update-gems` - Fastlane Ruby dependencies (updates `fastlane/Gemfile.lock` and `fastlane/gemset.nix`)
# Manual Steps
There are a few manual steps you might want to do in order to start contributing.
## Genymotion Virtualization
Optionally set up Genymotion if you don't want to use Android Virtual Device:
https://www.genymotion.com
## Android Development Environment
You can also setup Android Development Environment + Simulator:
https://facebook.github.io/react-native/docs/getting-started.html
## Configure GitHub Account
The optimal way of pushing to GitHubis using SSH instead of user/pass auth.
It's recommented that you [add your public SSH key to your GitHub account](https://help.github.com/en/github/authenticating-to-github/adding-a-new-ssh-key-to-your-github-account).
## Configure GPG Keys for signing commits
In order to increase security we require all commits in `status-mobile` repo to be signed with a GPG key.
Steps:
1. [Generate a new GPG key](https://help.github.com/en/github/authenticating-to-github/generating-a-new-gpg-key)
2. [Setup Git to use your GPG key](https://help.github.com/en/github/authenticating-to-github/telling-git-about-your-signing-key)
3. [Setup Git to sign commits](https://help.github.com/en/github/authenticating-to-github/signing-commits)
4. [Setup GitHub to validate commits](https://help.github.com/en/github/authenticating-to-github/adding-a-new-gpg-key-to-your-github-account)
## Physical iOS Device
To use a physical iPhone your device UDID must be added to provisioning profiles and your Apple account invited as Developer to Status team.
1. [Get your UDID of your iPhone.](https://www.extentia.com/post/finding-the-udid-of-an-ios-device)
2. Request from someone with access like @cammellos or @jakubgs to
- Add the UDID to development devices on Apple Developer Portal.
- Invite your Apple account to be Developer in Status team.
3. Run a build in XCode using the project from `status-mobile/ios` directory.
- You might see error: `Select a development team in the Signing & Capabilities editor`
- Select `Status Research & Development GmbH` as the development team and rebuild again.
Once build finishes Status should start on your iPhone with its logs in terminal running `make run-metro`.
+40
View File
@@ -0,0 +1,40 @@
# Testing
### Unit & integration tests
To run tests:
```
make test
```
To watch the tests:
```
make test-watch
```
To run test in REPL
```
make test
yarn shadow-cljs cljs-repl test # or start the REPL in your editor
```
Then start the test process with
```
node --require ./test-resources/override.js target/test/test.js --repl
```
You can run single test in REPL like this
```clojure
(require 'cljs.test)
(cljs.test/test-var #'status-im.data-store.chats-test/normalize-chat-test)
```
Tests will use the bindings in `modules/react-native-status/nodejs`, if you make any changes to these you will need to restart the watcher.
+128
View File
@@ -0,0 +1,128 @@
# [DEPRECATED] Undefined is not an object evaluating `register_handler_fx`
## Deprecation note
This type of error should not occur anymore now that we require the namespace in the `fx.cljs` file.
It can however happen with other macros requiring a cljs namespace.
The general fix for that type of issue is to have two files for the namespace where your macros are defined, let's say for `my-project.my-macro` namespace you would have:
- my_macro.cljs in which you need `(:require-macros my-project.my-macro)` and `(:require my-project.the-namespace-used-in-the-macro)`
- my_macro.clj in which you define the macro
That way you don't need to use any magical call like `find-ns` or inline `require` with some kind of call only once switch (which was the root cause of another bug in ``defstyle`` macro because the compilation phase at which the evaluation of the switch is done was not properly considered).
You also want to make sure users are using the macro by using a aliased namespace defined in require statement rather than require-macro and refer to the macro directly. Otherwise it won't require the cljs file and the require statement of the namespace in the macroexpension might not be there.
## Stacktrace
```
13:25:22, Requiring: hi-base32
13:25:23, Possible Unhandled Promise Rejection (id: 0):
TypeError: undefined is not an object (evaluating 'status_im.utils.handlers.register_handler_fx')
eval code
eval@[native code]
asyncImportScripts$@http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false:200728:21
tryCatch@http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false:26567:23
invoke@http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false:26742:32
tryCatch@http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false:26567:23
invoke@http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false:26643:30
http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false:26653:21
tryCallOne@http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false:3725:16
http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false:3826:27
_callTimer@http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false:28405:17
_callImmediatesPass@http://localhost:8081/index.bundle?pla<…>
```
## Cause
- stacktrace mentions `register_handler_fx`,
- common cause is when requires have been cleaned up and a require of `status-im.utils.handlers` namespace was removed because it looked like it was unused but was actually used through a fx/defn macro
## Solution
go through known faulty commit looking for deleted requires
# Git "unable to access" errors during `yarn install`
## Description
Developer updates `package.json` file with a new dependency using a GitHub URL. So it looks like this:
```
"react-native-status-keycard": "git+https://github.com/status-im/react-native-status-keycard.git#feature/exportKeyWithPath",
```
Afterwards, when running e.g. `make run-metro`, they might see the following confusing error:
```
# macOS
fatal: unable to access 'https://github.com/siphiuel/react-native-status-keycard.git/': SSL certificate problem: unable to get local issuer certificate
# Linux
fatal: unable to access 'https://github.com/status-im/react-native-status-keycard.git/': Could not resolve host: github.com
info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.
```
## Cause
`yarn.lock` is not updated to be in sync with `package.json`.
## Solution
Update yarn.lock file. In order to do this, perform the following steps on a clean `status-mobile` repo:
```
cd status-mobile
yarn install
```
and don't forget to commit updated `yarn.lock` together with `package.json`.
# adb server/client version mismatch errors
## Description
Running some adb commands, e.g. `adb devices` or `make android-ports` (in turn invokes `adb reverse`/`adb forward` commands) may display the following message:
```
adb server version (40) doesn't match this client (41); killing...
```
or the reverse
```
adb server version (41) doesn't match this client (40); killing...
```
This might cause all kinds of difficult-to-debug errors, e.g.:
- not being able to find the device through `adb devices`
- `make run-android` throwing `com.android.builder.testing.api.DeviceException: com.android.ddmlib.InstallException: device 'device-id' not found.`
- `make run-android` throwing `- Error: Command failed: ./gradlew app:installDebug -PreactNativeDevServerPort=8081 Unable to install /status-mobile/android/app/build/outputs/apk/debug/app-debug.apk com.android.ddmlib.InstallException: EOF`
- dropped CLJS repl connections (that have been enabled previously with the help of `make android-ports`)
## Cause
System's local adb and Nix's adb differ. As adb include of server/client processes, this can cause subtle version errors that cause adb to kill mismatching server processes.
## Solution
Always use respective `make` commands, e.g. `make android-ports`, `make android-devices`, etc.
Alternatively, run adb commands only from `make shell TARGET=android` shell. Don't forget the `TARGET=android` env var setting - otherwise `adb` will still be selected from the system's default location. You can double-check this by running `which adb`.
# Hot Reloading Crashes
## APP Crashes on reloading changes
### Cause
Status-mobile uses `shadow-cljs` for hot reloading changes and uses its own [reloader](https://github.com/status-im/status-mobile/blob/develop/src/status_im/reloader.cljs) for updating them in the running app. If react-native's fast refresh is also enabled then it creates conflicts and crashes the app.
### Solution
Open react native's [In-App Developer Menu](https://reactnative.dev/docs/debugging#accessing-the-in-app-developer-menu) and press "Disable Fast Refresh" or "Disable Hot Reloading"
## App Crashes after few reloads
### Cause
For x86 CPU architecture Android Devices, Hermes is creating the issue and the app crashes after a few reloads.
([Original Issue](https://github.com/status-im/status-mobile/issues/14031))
<details>
<summary>How to Find CPU architecture</summary>
CPU architecture of android device can be found using
- `adb shell uname -m` or
- `adb shell getprop ro.product.cpu.abilist`
</details>
### Solution
Disable Hermes while building the app
`make run-android DISABLE_HERMES=true`
+19
View File
@@ -91,11 +91,30 @@ These guidelines make db.cljs namespaces the place to go when making changes to
- If manual QA is not needed but all tests don't pass, you can ping @churik or @Serhy to confirm that failed E2E tests are not unrelated. - If manual QA is not needed but all tests don't pass, you can ping @churik or @Serhy to confirm that failed E2E tests are not unrelated.
## Enabling debug logs
Calls to `log/debug` will not be printed to the console by default. It can be enabled under "Advanced settings" in the app:
![Enable Debug Logs](./log-settings.png)
## Translations ## Translations
The app relies on system locale to select a language from the [list of supported languages](https://github.com/status-im/status-mobile/blob/bda73867471cf2bb8a68b1cc27c9f94b92d9a58b/src/status_im/i18n_resources.cljs#L9). It falls back to English in cash the system locale is not supported. The app relies on system locale to select a language from the [list of supported languages](https://github.com/status-im/status-mobile/blob/bda73867471cf2bb8a68b1cc27c9f94b92d9a58b/src/status_im/i18n_resources.cljs#L9). It falls back to English in cash the system locale is not supported.
We use Lokalise App to manage [translations](https://translate.status.im/). In case you need to add/remove a key to translations, you only need to change `en.json`. Missing keys fallback to `en.json`. The actual translations will be added by Lokalise. We use Lokalise App to manage [translations](https://translate.status.im/). In case you need to add/remove a key to translations, you only need to change `en.json`. Missing keys fallback to `en.json`. The actual translations will be added by Lokalise.
## re-frisk
re-frisk is a state visualization tool written by our very own Andrey (@flexsurfer). To start re-frisk, execute the following command:
```bash
$ yarn shadow-cljs run re-frisk-remote.core/start
```
or you can also use make:
```bash
$ make run-re-frisk
```
A server will be started at http://localhost:4567. It might show "not connected" at first. Don't worry and just start using the app. The events and state will populate.
## Merging approved PRs ## Merging approved PRs
We don't Github's UI to merge. Instead `./scripts/merge-pr.sh` is used to sign and merge PR to `develop`. You first need to enable [GPG signing on you commits](https://github.com/status-im/status-mobile/blob/develop/STARTING_GUIDE.md#configure-gpg-keys-for-signing-commits). We don't Github's UI to merge. Instead `./scripts/merge-pr.sh` is used to sign and merge PR to `develop`. You first need to enable [GPG signing on you commits](https://github.com/status-im/status-mobile/blob/develop/STARTING_GUIDE.md#configure-gpg-keys-for-signing-commits).
-55
View File
@@ -1,55 +0,0 @@
# Component Tests
The component tests are using React Native Testing Library - https://callstack.github.io/react-native-testing-library/
and Jest - https://jestjs.io/
It is highly recommended to read some advice from Kent C.Dodds on how to write tests and use these tools correctly.
https://kentcdodds.com/blog/common-mistakes-with-react-testing-library
https://www.youtube.com/watch?v=ahrvE062Kv4
Both of these links are showing it for React-Testing-Library (not Native) however the approach is for the most part considered the same.
## Running the tests
To run these tests there are two methods.
`make component-test`
setups and runs the test suite once.
`make component-test-watch`
setups and runs the test suite and watches for code changes will then retrigger the test suite.
## Writing Tests
New test files will need their namespace added to either the file "src/quo/core_spec.cljs" or "src/status_im2/core_spec.cljs. These locations may update overtime but it is dependent on the entrypoint in shadow-cljs config discussed below.
### Best practices
For the moment we will keep best practices for tests in our other guidelines document:
To that point these guidelines will follow the conventions of Jest and React Native Testing Library recommendations and Status mobile will just stack their preferences on top.
### Utilities
There is a file of utility functions defined in "src/test_helpers/component.cljs" and "src/test_helpers/component.clj". It will be great to use these utilities and to add any common testing tools to these files as it should make writing tests easier and faster.
## Configuration
Status Mobile has a bespoke tech stack, as such there is more complexities to configuring the tests.
### Shadow-CLJS
the configuration for compiling our tests are defined in the "shadow-cljs.edn" file.
The three main parts of this are
`:target :npm-module`
Needed for the configuration we are using
`:entries`
a vector of entry points for the test files.
and the `ns-regexp` to specify what tests to find. Since we have multiple forms of tests we decided that "component-spec" is the least likely to detect the wrong file type.
It's worth knowing that our tests are compiled to JS and then run in the temporary folder `component-tests`.
### Jest
There is also further configuration for Jest in "test/jest". There is a jest config file which has some mostly standard configuration pieces, where the tests live, what environment variables are set etc. This is documented by Jest here: https://jestjs.io/docs/configuration
There is also a setup file which is used to set some global and default values. Additionally this file is used to mock some of the react native (among other) dependencies
-136
View File
@@ -1,136 +0,0 @@
# Debugging
## Inspecting re-frame with re-frisk
`re-frisk` is a state visualization tool written by our very own Andrey (@flexsurfer). With its help you can inspect the current state of app-db, watch event, etc.
![re-frisk](images/debugging/re-frisk.png)
To start `re-frisk`, execute the following command:
```bash
$ yarn shadow-cljs run re-frisk-remote.core/start
```
or you can also use make:
```bash
$ make run-re-frisk
```
A server will be started at http://localhost:4567. It might show "not connected" at first. Don't worry and just start using the app. The events and state will populate.
More details about re-frisk are on the [project page](https://github.com/flexsurfer/re-frisk).
## Enabling debug logs
Calls to `log/debug` will not be printed to the console by default. It can be enabled under "Advanced settings" in the app:
![Enable Debug Logs](images/debugging/log-settings.png)
## Checking status-go logs
While status mobile works it saves logs from `status-go` to `geth.log` file.
### Checking logs from physical device
To obtain `geth.log` from physical device you need to shake it and in an opened menu select "Share logs".
![Share logs](images/debugging/share-logs.jpeg)
### Checking logs from iOS Simulator
When developing with iOS simulator it is more convenient to see the `geth.log` updates in real-time.
To do this:
- open Activity Monitor
- find the "StatusIm" app and doubleclick it
- in the opened window select "Open files and ports" and find the full path to `geth.log` (note that it won't appear until you login to Status app)
![geth.log path](images/debugging/geth-path.png)
## Inspecting database content
Encrypted database can be found using commands:
```
cd ~/Library/Developer/CoreSimulator/Devices
find ./ -name accounts.sql
```
To get unencrypted database you need to export it first:
- open the status app in simulator
- on login screen enter the correct password without logging in
- using repl execute statement to export db:
```
(re-frame.core/dispatch [:multiaccounts.login.ui/export-db-submitted])
```
- save generated `export.db` file
Now you can locate the `export.db` and open it with preferred db viewer.
**Android:**
```sh
adb root
adb pull /storage/emulated/0/Android/data/im.status.ethereum.debug/files/Download/export.db /path/to/store/export.db
```
If you're using a release build, change the path to `/storage/emulated/0/Android/data/im.status.ethereum/files/Download`
**iOS**
```
cd ~/Library/Developer/CoreSimulator/Devices
find ./ -name export.db
```
## Tips
### From @ilmotta:
Something I find extremely convenient for Android is to use `adb` to tail logs. I don't use macOS so I don't know if the iOS simulator offers a CLI interface with the same capabilities.
But here's what I use for example:
```
adb shell tail -n 10 -f /storage/emulated/0/Android/data/im.status.ethereum.debug/files/Download/geth.log | grep 'waku.relay'
```
Also to inspect logs in a more flexible manner, instead of the strict output from `make run-metro`, I prefer `adb logcat`. Combined with enabling status-mobile logs in debug by default plus filtering the logs to only what I care during development, I find this helps me inspect the app without running re-frisk because with the debug log level I can already see which events are dispatched (one of the features I like the most from re-frisk).
```
adb logcat | grep 'ReactNativeJS\|StatusModule\|GoLog'
```
### From @clauxx (visual debugging):
When building/fixing/refactoring components, it can be annoying to set-up the component for instant visual feedback (i.e. finding it in the UI when fixing/refactoring; finding a place for it when building from scratch). Very often if the location of the screen containing your component nested deeply in the app, you might have to do a lot of repeated navigation, nevermind logging in every time the app reloads (even with fast refresh disabled this happens quite often).
To alleviate this discomfort and make the development cycle more *pleasant*, you can use one of the following options (*_both of which involve the ... REPL ༼ つ ╹ ╹ ༽つ, so make sure you have that set-up with your IDE/editor_*)
#### REPL-ing to a screen
This one is straightforward, just evaluate a navigation dispatch form from anywhere:
```cljs
(comment (rf/dispatch [:navigate-to :your-favorite-buggy-screen]))
```
> TIP: you can run this from an untracked user namespace `(ns user)`, from which you can experiment or interact with the REPL. This is where I usually keep my development navigation forms.
#### REPL-ing a component
This is also straighforward, but there are some small differences. Just like above, we only have to evaluate a dispatch form, as follows:
```cljs
;; example debugging a quo component, although it could be any other component e.g. from the `status-im2` ns.
(comment (re-frame/dispatch [:dev/preview-component
[quo/slide-button
{:track-icon :face-id
:track-text "preview component example"
:customization-color :blue
:on-complete identity}]]))
```
When evaluated, a full-screen bottom sheet will appear with your component inside. You can make changes to the props or the component internals and re-evaluate the changed forms, after which the component will be re-mounted without running a reload (unless you save the file). Other times it's quicker to just hit save and the component will be reloaded as usual (except for the props you evaluated, which have to be re-evaluated when changed).
> TIP: You can have multiple versions of the component as separate comments to check for the component variations
> TIP: You can leave `comment` blocks at the end of component files (other than quo, since can be previewed in other ways) with usages of components, which other developers can use for visualisation/testing.
@@ -18,7 +18,7 @@ While neat in theory, it has some serious downsides:
As a result of that, more dynamic/state requiring things (like the live tx detail in `/send` command messages) were very hard to do, As a result of that, more dynamic/state requiring things (like the live tx detail in `/send` command messages) were very hard to do,
so instead of "eating our own dogfood", we decided to side-step the API and implement such things as hard-coded logic in the app, while partly so instead of "eating our own dogfood", we decided to side-step the API and implement such things as hard-coded logic in the app, while partly
retaining the js code for "easier" things (like parameter declaration). retaining the js code for "easier" things (like parameter declaration).
Needles to say, such efforts produced code of very poor quality, riddling our app with hard-coded "magic" everywhere in the codebase, completely Needles to say, such efforts produced code of very poor quality, riddling our app with hard-coded "magic" everywhere in the codebase, completly
defeating the point of "dogfooding" while still requiring more effort and being much more error prone (no way to unit test jail logic) because defeating the point of "dogfooding" while still requiring more effort and being much more error prone (no way to unit test jail logic) because
of the need to asynchronously communicate with jail for leftover logic in command messages (the parts not hardcoded in app). of the need to asynchronously communicate with jail for leftover logic in command messages (the parts not hardcoded in app).
+1 -1
View File
@@ -13,7 +13,7 @@ accepted
There was a generally dissatisfaction with our PR flow process from multiple stakeholders, including devs, QA and design. These largely centered around size, speed of integration and quality of PRs. There was a generally dissatisfaction with our PR flow process from multiple stakeholders, including devs, QA and design. These largely centered around size, speed of integration and quality of PRs.
For more details, please see pain points in the meeting notes held end of February here: https://notes.status.im/C5pj8g7gQOu9Wo8PtDZsMw?edit# as well as the preceding Discuss thread: https://discuss.status.im/t/better-pull-requests-process/1044 For more details, please see pain points in the meeting notes held end of February here: https://notes.status.im/C5pj8g7gQOu9Wo8PtDZsMw?edit# as well as the preceeding Discuss thread: https://discuss.status.im/t/better-pull-requests-process/1044
Also see conversations in Core Dev Call #12 and #13: https://github.com/status-im/pm/ Also see conversations in Core Dev Call #12 and #13: https://github.com/status-im/pm/
+1 -1
View File
@@ -45,4 +45,4 @@ The `State` field in the Pivotal story is used to track the progress of a Pivota
| 5 points | 2 - 3 days | | 5 points | 2 - 3 days |
| 8 points | ~1 week | | 8 points | ~1 week |
We should avoid 8 point stories by breaking them down into smaller stories as much as possible. We should avoid 8 point stories by breaking them down into smaller stories as much as possible.
+3 -3
View File
@@ -18,7 +18,7 @@ The whitepaper also proposes that the deposit is only forfeited to the recipient
Considering: Considering:
- the absence of efficient ways to perform anonymous transactions (zk-snarks could be used in the future for that) - the absence of efficient ways to perform anonymous transactions (zk-snarks could be used in the future for that)
- the impossibility to prove that a recipient has made an actual reply and not some kind of automated reply (captcha solution was proposed, but wouldn't be practical until we can use a solution such as swarm feeds that allow users to make free updates to their captcha without on-chain transactions) - the impossibility to prove that a recipient has made an actual reply and not some kind of automated reply (captcha solution was proposed, but wouldn't be pratical until we can use a solution such as swarm feeds that allow users to make free updates to their captcha without on-chain transactions)
- the limited time to develop the feature - the limited time to develop the feature
We opted for a solution that: We opted for a solution that:
@@ -28,8 +28,8 @@ We opted for a solution that:
## Manifests ## Manifests
Since TtT related information aren't stored on chain, they need to be stored somewhere else. Since TtT related informations aren't stored on chain, they need to be stored somewhere else.
For the first iteration of TtT we opted for IPFS, which is already used across the app for other forms of content, through Infura IPFS gateway. For the first iteration of TtT we opted for IPFS, which is already used accross the app for other forms of content, through Infura IPFS gateway.
On IPFS we store what we call a ttt manifest, which is a json file with the following format: On IPFS we store what we call a ttt manifest, which is a json file with the following format:
-30
View File
@@ -1,30 +0,0 @@
# 0014. Team-structure
| Date | Tags |
|---|---|
| 2023-06-16 | wallet team |
## Status
Proposed
## Context:
In order to try out vertical team, which is a structure that is wanted by the company, we will be creating a wallet team within the mobile team.
Some member of the mobile team will join the current wallet team, which is composed by developers from desktop and lead by @alaibe, on a voluntary basis.
The responsibilities of the team are to implement the new wallet UI, with the support of the current wallet team, which will be assisting with the status-go work.
## Decision
The team members for the initial wallet team are:
- @rasom
- @OmarBasem
- @vkjr
- @J-Son89
- @briansztamfater
- @smohamedjavid
- @ulisesmac
- @erikseppanen
- @mmilad75
- @tumanov-alex
-46
View File
@@ -1,46 +0,0 @@
# 0015. Team-structure
| Date | Tags |
|---|---|
| 2023-06-16 | changes in team structure |
## Status
Proposed/partially implemented
## Context:
Currently, there is only a single team lead in the mobile development team, and after a meeting with the design team, it has been identified that the mobile app lacks polishness. One of the main issues identified is a lack of oversight in certain areas. To address this problem, it has been decided to create an additional role within the team. For each section of the mobile app (communities, syncing & onboarding, activity center & shell, wallet, messaging), a person will be selected to fulfill the responsibilities outlined below.
## Decision
The decision is to create an additional role within the mobile development team for each section. The individuals selected for these roles will have the following responsibilities:
- Ensure GitHub issues are created for new features/designs of the section.
- Ensure issues are adequately described and linked as best as possible.
- Ensure issues have a grooming session where other developers can provide their feedback before working on the set of issues.
- Ensure all relevant parties are invited, such as designers, QA, Product Owner, leads, etc., as needed (including the designer who created the feature).
- Ensure there is consensus among the developers working on the section about the decided strategy approach. Ideally, this consensus should be documented.
- Ensure UI quality by organizing designer reviews and guaranteeing pixel perfection.
- Ensure overall implementation is satisfactory based on the predefined requirements.
- Ensure alignment between desktop, web, and mobile versions for the respective section in collaboration with the mobile developers and design team.
- Act as a point of contact for the design team with respect to the section.
- Ensure that someone goes through the designs once they are created with the respective designer.
- Assist the design team with technical feasibility analysis and address any product concerns.
- Facilitate the growth of the next team member into the role.
The people identified for each sections are as follow:
- Messaging @flexsurfer, followed by @alwx
- Syncing & Onboarding @siddarthkay
- Communities @ilmotta, followed by @ajayesivan
- Activity Center & Shell @J-Son89, followed by @Parveshdhull
- Wallet (once the vertical team is created) @J-Son89, followed by @briansztamfater
This will be a rotating post, every 4 months it will go to the next in line.
The wallet team might have longer times for rotation, as stability might be more important. That's still to be decided.
# Follow-up Actions
- Find suitable next in line for Messaging, Onboarding, Communities
@@ -1,31 +0,0 @@
### How should the paste button behave when clipboard is empty?
This question first came up as a review comment to this PR
https://github.com/status-im/status-mobile/pull/16852
There were 2 considerations :
- Either keep the paste button disabled when there is nothing in the clipboard OR
- Always keep the paste button enabled
There were positives and negatives for both approaches.
Positives of keeping paste button disabled when there is nothing in clipboard would require us to
check the value of clipboard as soon as the component is mounted (i.e when the user first sees
the screen). In iOS this means a native permissions dialog would appear requesting for permissions
to paste from the clipboard.
Negatives of this approach is that as soon as any user navigates to this screen they are greeted with
this popup which can be annoying sometimes.
Positives of keeping paste button always enabled is that we can trigger a request to the clipboard on
tap of the paste button which would trigger the native permissions dialog requesting for permissions
to paste from the clipboard.
In this case seeing this dialog is okay because the user has initiated a paste action.
Negatives of this approach is that in the event the clipboard is empty the user will still see the
system dialog and on approving nothing will be pasted (because the clipboard was empty).
This behaviour can be confusing.
On consulting the Design Team via discord it was concluded that out of the two approaches
having the paste button always enabled is a better UX overall.

Before

Width:  |  Height:  |  Size: 231 KiB

After

Width:  |  Height:  |  Size: 231 KiB

-15
View File
@@ -1,15 +0,0 @@
# new icons
## Export icons
![](images/export-icons/export-icons.gif)
1. Export from figma 2 pngs 2x and 3x put them in `./resources/images/icons2`
2. if necessary, rename file so that filename contains only lower case chars, e.g. `"Icon-Name@2x.png"` should be renamed to `"icon_name@2x.png"`.
3. In the app `icon_name.png` still can be accessed as `icon-name`, so in order to use can add the next code:
```clojure
;; icon_name.png
[vector-icons/icon :icon-name {:color ...}]
```
2x@2x
4. If you want platform specific icon use `.android` or `.ios` suffixes. Example `icon_name@2x.android.png`.:w
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

-40
View File
@@ -1,40 +0,0 @@
# How to catch crash on ios use xcode
## Overview
Sometimes, we can't reproduce crash with local dev build, probably because your built version differs from the one QA team used.
The QA team mostly used the PR build version. In this guide we will try to make a build as close as possible to the PR build for iOS.
You may notice various configuration files starting with .env (such as .env, .env.e2e, .env.jenkins) in the project.
The usage of these files and environment variables injected at build time on CI will not be covered in this guide.
This guide covers how to configure Xcode to capture a crash stack trace with a physical iOS device. This allows debugging crashes by inspecting the stack trace.
I will use [issue #17255](https://github.com/status-im/status-mobile/issues/17255) as an example to reproduce and analyze a crash.
## Prerequisites
- A physical ios device (simulator is not considered in this doc)
- Xcode installed
## Steps
1. Prepare Status Mobile
1. Open Terminal, cd to project root
2. Run `make run-clojure` in one tab
3. Run `make run-metro` in a second tab
4. Run `make pod-install` in a third tab
2. Configure Xcode Project
1. Open Xcode
2. Open a project or file, navigate to folder `path_to_root_directory_of_status_mobile/ios`
3. Set Scheme `StatusImPR` as current scheme ![](images/how-to-catch-crash-on-ios/choose-scheme-StatusImPR.png)
4. Edit scheme ![](images/how-to-catch-crash-on-ios/edit-scheme.png)
5. Change `Info` ![](images/how-to-catch-crash-on-ios/config-release.png)
6. Change `Diagnostics` ![](images/how-to-catch-crash-on-ios/change-diagnostics.png)
7. Set automatically manage signing ![](images/how-to-catch-crash-on-ios/automatically-manage-signing.png)
3. Update Code
1. Edit `src/status_im2/setup/dev.cljs`, comment out lines 47-52 ![](images/how-to-catch-crash-on-ios/edit-dev.png)
2. Edit `shadow-cljs.edn`, comment out `re-frisk-remote.preload`, otherwise it will try to connect `localhost:4567` on physical device which could slow down performance ![](images/how-to-catch-crash-on-ios/edit-shadow-cljs.png)
4. Reproduce Crash And Analyze
1. Choose your physical ios device as target device and Run
2. Follow reproduce steps from [issue #17255](https://github.com/status-im/status-mobile/issues/17255) mentioned and xcode will halt at crash point ![](images/how-to-catch-crash-on-ios/located-stack-trace.png)
3. Inspect stack trace to identify root cause. From the stack trace, we can locate the crash happened in `api/geth_backend.go:1048`(createTempDBFile) clearly! ![](images/how-to-catch-crash-on-ios/located-go-code.png)
## Links
- [changes](https://github.com/status-im/status-mobile/commit/4306d419de15e737e8ded3a749cc5e8d6a06e627) to source code
-103
View File
@@ -1,103 +0,0 @@
How to Launch E2E
===
## Overview for how automated test structured for Status app
As a part of CI for Status mobile app and in order to ensure there are no regressions appear after the changes in code (bug fix, new/updated feature) we are using automated tests (e2e tests).
- Automated tests written on Python 3.9 and pytest.
- Appium (server) and Selenium WebDriver (protocol) are the base of test automation framework.
TestRail is a test case management system tool where we have test cases.
Each of the test case gets a priority (Critical/High/Medium)
**SauceLabs** - is a cloud based mobile application test platform. We are using Android emulators (Android 10.0) for test script execution there. We have 16 session be running at the same time max.
For now we support e2e for Android only.
## What's happening when any e2e job is running
Whenever we need to push set of test scripts we create 16 parallel sessions (max, but depending on amount of cases that are included in job) and each thread: 1) uploads Android .apk file to SauceLabs -> 2) runs through the test steps -> 3) receives results whether test failed on particular step or succeeded with no errors -> 3) Parse test results and push them as a Github comment (if the suite ran against respective PR) and into TestRail.
We push **whole automation test suite (currently 155, amount is changing)** against each nightly build (if the nightly builds job succeeded). Results of the test run are saved in TestRail.
And also we push set of autotests whenever PR with successful builds got moved in to `E2E Tests` column from [Pipeline for QA dashboard ](https://github.com/status-im/status-react/projects/7).
In that case we save results in TestRail as well and push a comment with test results in a respective PR.
For example: https://github.com/status-im/status-react/pull/9147#issuecomment-540008770
![](images/how-to-launch-e2e/how-to-launch-e2e-1.png)
The test_send_stt_from_wallet opens link in TestRail https://ethstatus.testrail.net/index.php?/tests/view/890885 where performed steps could be found
List of all runs performed by test jobs could be found here https://ethstatus.testrail.net/index.php?/runs/overview/14
**For credentials for TestRail to see results ping Chu in DM**:
Opening any test run navigates you to list of test cases with results:
![](images/how-to-launch-e2e/how-to-launch-e2e-2.png)
## What about launching e2e manually
To manage e2e there are several jobs in https://ci.status.im/job/status-mobile/job/e2e :
1) [nightly](https://ci.status.im/job/status-mobile/job/e2e/job/status-app-nightly/) - running automatically after building nightly apk e2e build. QA running it manually for results of e2e when testing release.
2) [upgrade](https://ci.status.im/job/status-mobile/job/e2e/job/status-app-upgrade/) - running manually by QA in release testing for smoke upgrade tests.
3) [prs](https://ci.status.im/job/status-mobile/job/e2e/job/status-app-prs/) - running **only automatically** when PR moves into `e2e column`
4) [prs-rerun](https://ci.status.im/job/status-mobile/job/e2e/job/status-app-prs-rerun/) - for manual run, can be run on request by anyone. **If you need to launch e2e against your build, use this job.**
Params to specify:
- apk: [url_to_apk_build_here]
- pr_id: pull request number (e.g. 1234)
- branch: branch name from which the test are taken (in most of cases `develop`)
- keyword expression: tests by area (let's say `ens` or `chat`, they can be combined`ens or chat or send_tx`. All keywords can be found in testrail, ping Chu for details)
- test_marks: tests by priorities (by default: `critical or high or medium`, which corresponds the whole suite; to launch the same suite as in PRs, use `critical or high`)
- testrail_case_id: here is the list of test cases which you may find in test rail (4-digit value)
For easier access you can hit `Rerun tests` in GH comment and testrail_case_id/ apk_name/ pr_id will be filled automatically. For making sure that tests are being rerun on most recent e2e build it is recommended to paste link to the last e2e build in apk_name field. The list of PR builds can be found in Jenkins Builds block on PR page.
![](images/how-to-launch-e2e/how-to-launch-e2e-3.png)
And then hit Build.
Once the job starts it picks up specified tests, runs them against provided apk and sends results to pull request.
Even we have 16 parallel sessions for testing its a time consuming operation (whole test suite we have automated at the moment takes ~140 minutes to finish).
So for PRs we pick only set of `critical or high` (you can also use this in TEST_MARKS param for job)
tests (otherwise some PRs could wait their turn of the scheduled Jenkins job till the next day).
## Analysing test results (and why test fails to pass)
After automated test run finished test results could be found in GH comment (if the test suite ran against PR) and TestRail. There are two states of the test: Passed and Failed. Test failure happens when certain condition of test step has not met or automated test can not proceed execution because it can not find the respective element on screen it expects should be there.
Several examples of when test fails to succeed:
- Test clicked on element which should load new screen (or pop-up) and awaits some element on this screen. But test did not wait enough allowing the new screen to appear and so it fails with “Could not find element XYZ” (this case is more app issue in our opinion rather then test issue, but we just can not spend our and dev time with too specific random places which happens once causing app lags in different moments)
- Test sent transaction to address but it was not mined in time (we have a limit to wait until balance is changed on recipient side up to ~6 mins now). We classify this as False Fail, because its not the app issue but more network issue.
- Test infrastructure issues, - anything related to infrastructure including SauceLabs side issues (apk failed to install - rare case, or LTE connection was set by default instead WiFi or unexpected pop-up appeared preventing test to going further)
- Failure due to changed feature which has not been taken into account in some test after code merge (for instance: some element on screen has been removed, and we want to locate another element on this screen via XPath which is different now)
- **Valid issue in the automated test scripts** - that's what we're looking for
Example: here is the test results https://github.com/status-im/status-react/pull/13015#issuecomment-1016495043 where one test failed.
1. Open the test in TestRail and open session recorded for this test in SauceLabs
![](images/how-to-launch-e2e/how-to-launch-e2e-4.png)
In TestRail you may find all the steps performed by the test.
In SauceLabs testrun page you may find useful: video of the session, step logs, logcat.log of the session
2. Analyze step where test was failed
For particular example it was failed on `Recover access(password:qwerty, keycard:False)` and unexpected error appeared.
## Limits for e2e tests coverage
Not all features of the app could be covered by e2e at the moment:
- Colours or place of an element on UI.
- Real ETH/token transactions. Thats the main reason we have separate .apk build for automation needs - it defaults to Goerli network. Also it has enabled keycard test menu, ENS names and chat commands are also on Goerli network (the same in PR builds, but not in nightlies / release)
- Autologin/Biometric related actions (autologin available when device meets certain conditions like the it has set unlock password and device is not rooted: all emulators are rooted in SauceLabs)
## Brief flow for test to be automated
Whenever there is a need to have a new test:
1) Create a test scenario in TestRail.
2) If certain item could be checked in scope of existing test case we update existing one (otherwise we may have thousands of test cases which is overkill to manage in TestRail as well as in automated test scripts). And also complex autotests increase probability to not catch regressions by stopping test execution (due to valid bug or changed feature) keeping the rest test steps uncovered. So here we need to balance when it makes sense to update existing test case with more checks.
3) Then we create test script based on the test case, ensure test passes for the build and pushing the changes to repo.
-227
View File
@@ -1,227 +0,0 @@
# Setup your Editor/IDE
You can use any Clojure enabled editor. Here are instructions for developing the status-mobile app using:
* IntelliJ IDEA and Cursive
* VS Code and Calva
* Emacs/Cider
(Please add instructions for your favorite editor.)
## Table of Contents
- [Using Cursive](#using-cursive)
- [Install Cursive](#install-cursive)
- [Getting Cursive to understand `status-mobile`](#getting-cursive-to-understand-status-mobile)
- [I get a lot of `cannot be resolved`](#i-get-a-lot-of-cannot-be-resolved)
- [REPL!](#repl)
- [Connecting to REPL to IntelliJ](#connecting-to-repl-to-intellij)
- [Connecting REPL and IntelliJ to `status-mobile`](#connecting-repl-and-intellij-to-status-mobile)
- [Visual Studio Code](#visual-studio-code)
- [Set up the REPL](#set-up-the-repl)
- [Auto-format files on save](#auto-format-files-on-save)
- [Using Emacs with CIDER](#using-emacs-with-cider)
## Using Cursive
### Install Cursive
See https://cursive-ide.com/userguide/index.html
### Getting Cursive to understand `status-mobile`
- Add this file to the root of the `status-mobile` project dir
- https://gist.github.com/Samyoul/f71a0593ba7a12d24dd0d5ef986ebbec
- Right click and "add as leiningen project"
<img src="images/ide-setup/1_fake_project_file.png" width=75% />
## I get a lot of `cannot be resolved`
Are you getting problems where you get a lot of `cannot be resolved` on everything?
<img src="images/ide-setup/2_resolve.jpeg" width=75% />
See https://cursive-ide.com/userguide/macros.html
- opt+enter (on macOS)
- resolve defview as fn and letsubs as let
- move selection on resolve and hit enter
- and select defn for defview and let for letsubs
### REPL!
#### Connecting to REPL to IntelliJ
I had a number of problems connecting to REPL, the solution is as follows:
At the top of IntelliJ IDEA click on the `Add Configuration...` option:
<img src="images/ide-setup/3_REPL_1.png" width=75% />
This will load the following menu:
<img src="images/ide-setup/4_REPL_2.png" width=75% />
Click on the `+` icon in the top left corner of the menu.
Select `Clojure REPL > Remote`
<img src="images/ide-setup/5_REPL_3.png" width=75% />
Which will load the following menu
<img src="images/ide-setup/6_REPL_4.png" width=75% />
Enter the below options:
- Name = status-mobile
- Display Name = status-mobile
- Connection type = nREPL
- Connection details
- Host = 127.0.0.1
- Port = 7888
<img src="images/ide-setup/7_REPL_5.png" width=75% />
Press `OK`
Now the below option will be visible.
Press the green run button
<img src="images/ide-setup/8_REPL_6.png" width=75% />
You should now see a dialog with the following message:
```shell
Connecting to remote nREPL server...
Clojure 1.10.1
```
To confirm you have a working connection with REPL enter the following command in the input box below the output:
```shell
(prn 1)
```
Which should output
```shell
(prn 1)
1
=> nil
```
See below:
<img src="images/ide-setup/9_REPL_7.png" width=75% />
#### Connecting REPL and IntelliJ to `status-mobile`
**The important next step is telling REPL the context in which to interact with the code.**
Do the following:
Ensure you have 3 terminals running the following
- `make run-clojure`
- `make run-metro`
- `make run-ios` / `make run-android`
[See the STARTING GUIDE for details](STARTING_GUIDE.md#development)
Next go back to the REPL input and enter the following commands:
```clojure
(shadow/watch :mobile)
(shadow/repl :mobile)
```
See Below
<img src="images/ide-setup/10_REPL_8.png" width="75%" />
Which should switch the clj file type target to cljs as shown above
Finally you are ready to test REPL.
Create a sample function to evaluate something simple like `(prn "I'm working")`, move your cursor to one of the outer parentheses. Right or `control` click and select the `REPL` option. From there select `Sync files in REPL` and then `Send '...' to REPL'`.
<img src="images/ide-setup/11_REPL_9.png" width="75%" />
Alternatively you can use the shortcut commands `⇧⌘M` to sync your files and `⇧⌘P` to send the statement to REPL. You may also need to switch the REPL namespace to match the current file, which can be done manually from the dialogue box or using the `⇧⌘N` shortcut key.
Following the above should give you the below result:
<img src="images/ide-setup/12_REPL_10.png" width="75%" />
🎉 Tada! Working! 🎉
---
For additional details on issues you may face when setting up REPL with Cursive [see this document](https://notes.status.im/9Gr7kqF8SzC_SmYK0eB7uQ?view#Connecting-Cursive--IntelliJ-IDEA-to-REPL-Problems)
## Visual Studio Code
### Set up the REPL
1. Install Calva extension.
2. Open the `status-mobile` folder.
3. Start [Status development](starting-guide.md#development) (Starting the
`run-clojure` and `run-metro` jobs in split view in the VS Code integrated
terminal works great).
4. Run the VS Code command: **Calva: Connect to a running REPL Server in the
project**.
- Select the project type `shadow-cljs`.
- Accept the suggested connection `host:port`.
- Select to connect to the `:mobile` build.
Open any `.cljs` file in the project and evaluate forms in it. See
https://calva.io/try-first/ for some starter tips and links. Confirm that your
REPL is connected to the app by evaluating:
```clojure
(js/alert "Hello from Status App!")
```
🎉 Tada! You are ready to use the REPL to improve Status.im! 🎉
Consider bookmarking [calva.io](https://calva.io/) for quick access to the Calva
documentation.
### Auto-format files on save
We format Clojure code with [zprint](https://github.com/kkinnear/zprint). We
recommend configuring VSCode to auto-format Clojure files on every save,
otherwise you'll need to constantly rely on the much slower `make lint-fix`
command.
1. Create a file `~/.zprintrc` and enable the `:search-config?` option. This is
necessary so the VSCode extension finds the project's `.zprintrc`.
```bash
echo "{:search-config? true}" > ~/.zprintrc
```
2. Install the extension
[vscode-clj-zprint](https://github.com/rflagreca/vscode-clj-zprint). By the
way, did you know this extension is written in ClojureScript?
3. Copy the recommended settings from our repository in
[.vscode/settings.example.json](/.vscode/settings.example.json) and merge it
with your workspace settings in `.vscode/settings.json`.
The extension `vscode-clj-zprint` is only available for VSCode. If you are using
VSCodium, you'll need to build the `vsix` (extension) yourself (it's easy, only
`yarn` and `vsce` are required).
## Using Emacs with CIDER
1. Install Emacs/Cider/etc. (there is a lot of variability in how to manage things in emacs, so please google for help with this)
2. Add a local ~/.shadow-cljs/config.edn file like below (corresponding to the version numbers of the packages you are using):
```clojure
{:dependencies
[[nrepl/nrepl "0.9.0"]
[cider/cider-nrepl "0.28.4"]
[cider/piggieback "0.5.2"]]}
```

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Before

Width:  |  Height:  |  Size: 439 KiB

After

Width:  |  Height:  |  Size: 439 KiB

Some files were not shown because too many files have changed in this diff Show More