diff --git a/.re-natal b/.re-natal index 62a72a72d9..64a2da627f 100644 --- a/.re-natal +++ b/.re-natal @@ -54,7 +54,8 @@ "rn-snoopy/stream/bars", "rn-snoopy/stream/filter", "rn-snoopy/stream/buffer", - "react-native/Libraries/vendor/emitter/EventEmitter" + "react-native/Libraries/vendor/emitter/EventEmitter", + "react-native-background-timer" ], "imageDirs": [ "resources/images" diff --git a/android/app/build.gradle b/android/app/build.gradle index 9383131cf9..17025a076a 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -186,6 +186,7 @@ android { } dependencies { + implementation project(':react-native-background-timer') implementation project(':react-native-svg') implementation 'com.android.support:multidex:1.0.2' implementation project(':react-native-http-bridge') diff --git a/android/app/src/main/java/im/status/ethereum/MainApplication.java b/android/app/src/main/java/im/status/ethereum/MainApplication.java index 2f7b4b8893..0a25b56427 100644 --- a/android/app/src/main/java/im/status/ethereum/MainApplication.java +++ b/android/app/src/main/java/im/status/ethereum/MainApplication.java @@ -7,6 +7,7 @@ import com.bitgo.randombytes.RandomBytesPackage; import org.devio.rn.splashscreen.SplashScreenReactPackage; import com.centaurwarchief.smslistener.SmsListenerPackage; import com.facebook.react.ReactApplication; +import com.ocetnik.timer.BackgroundTimerPackage; import com.horcrux.svg.SvgPackage; import com.evollu.react.fcm.FIRMessagingPackage; import com.lugg.ReactNativeConfig.ReactNativeConfigPackage; @@ -58,6 +59,7 @@ public class MainApplication extends MultiDexApplication implements ReactApplica Function callRPC = statusPackage.getCallRPC(); List packages = new ArrayList(Arrays.asList( new MainReactPackage(), + new BackgroundTimerPackage(), new SvgPackage(), new FIRMessagingPackage(), new HttpServerReactPackage(), diff --git a/android/settings.gradle b/android/settings.gradle index 8f76510db6..2aab9f61e2 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,4 +1,6 @@ rootProject.name = 'StatusIm' +include ':react-native-background-timer' +project(':react-native-background-timer').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-background-timer/android') include ':react-native-svg' project(':react-native-svg').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-svg/android') include ':react-native-fcm' diff --git a/ios/Podfile b/ios/Podfile index 715eb01f4f..1d7ece1d93 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -18,7 +18,11 @@ target 'StatusIm' do # Pods for StatusIm pod 'Instabug', '~> 7.0' pod 'FirebaseMessaging' - + + pod 'React', :path => '../node_modules/react-native' + pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga' + pod 'react-native-background-timer', :path => '../node_modules/react-native-background-timer' + target 'StatusImTests' do inherit! :search_paths # Pods for testing diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 6602e7b1f1..a70112e372 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -20,10 +20,28 @@ PODS: - GoogleToolboxForMac/Defines (= 2.1.1) - Instabug (7.2.6) - Protobuf (3.3.0) + - React (0.51.0): + - React/Core (= 0.51.0) + - react-native-background-timer (2.0.0): + - React + - React/Core (0.51.0): + - yoga (= 0.51.0.React) + - yoga (0.51.0.React) DEPENDENCIES: - FirebaseMessaging - Instabug (~> 7.0) + - React (from `../node_modules/react-native`) + - react-native-background-timer (from `../node_modules/react-native-background-timer`) + - yoga (from `../node_modules/react-native/ReactCommon/yoga`) + +EXTERNAL SOURCES: + React: + :path: ../node_modules/react-native + react-native-background-timer: + :path: ../node_modules/react-native-background-timer + yoga: + :path: ../node_modules/react-native/ReactCommon/yoga SPEC CHECKSUMS: FirebaseAnalytics: 4d7040fefc3cd8b291cde35f12cf063d7963f15d @@ -33,7 +51,10 @@ SPEC CHECKSUMS: GoogleToolboxForMac: 8e329f1b599f2512c6b10676d45736bcc2cbbeb0 Instabug: 49d4fbf1bf14e2f9074dfb7774ca5611bae993b4 Protobuf: d582fecf68201eac3d79ed61369ef45734394b9c + React: 352f02f1db6e4744f9a758527e13e3fdefbbd6ba + react-native-background-timer: 10063c04bf85d7f8811dff8c74399f0aa715245f + yoga: b5d96400ca8b2936965a7a6516da7c1177f432a3 -PODFILE CHECKSUM: 99245e16fcfd88ea22cee996e71ce86ab3a43138 +PODFILE CHECKSUM: 2fb09df3e1ea33a8eef1757e72a6577bd5d547c1 COCOAPODS: 1.3.1 diff --git a/package-lock.json b/package-lock.json index 6b6ab9cb4e..136b64c270 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7750,6 +7750,11 @@ "prop-types": "15.6.0" } }, + "react-native-background-timer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/react-native-background-timer/-/react-native-background-timer-2.0.0.tgz", + "integrity": "sha512-vLNJIedXQZN4p3ChFsAgVHacnJqQMnLl+wBsnZuliRkmsjEHo8kQOA9fnLih/OoiDi1O3eHQvXC5L8f+RYiKgw==" + }, "react-native-camera": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/react-native-camera/-/react-native-camera-0.10.0.tgz", diff --git a/package.json b/package.json index 6f7c2df352..ed1155ba29 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "react-native-action-button": "2.8.1", "react-native-android-sms-listener": "github:adrian-tiberius/react-native-android-sms-listener#listener-bugfix", "react-native-autolink": "1.1.1", + "react-native-background-timer": "2.0.0", "react-native-camera": "0.10.0", "react-native-config": "0.9.0", "react-native-contacts": "1.0.3", diff --git a/react-native/src/status_im/react_native/js_dependencies.cljs b/react-native/src/status_im/react_native/js_dependencies.cljs index 86107e04e6..1dfe076fb9 100644 --- a/react-native/src/status_im/react_native/js_dependencies.cljs +++ b/react-native/src/status_im/react_native/js_dependencies.cljs @@ -36,3 +36,4 @@ (def snoopy-bars (js/require "rn-snoopy/stream/bars")) (def snoopy-buffer (js/require "rn-snoopy/stream/buffer")) (def EventEmmiter (js/require "react-native/Libraries/vendor/emitter/EventEmitter")) +(def background-timer (.-default (js/require "react-native-background-timer"))) diff --git a/src/status_im/chat/views/input/input.cljs b/src/status_im/chat/views/input/input.cljs index 4e39d98149..40635794fe 100644 --- a/src/status_im/chat/views/input/input.cljs +++ b/src/status_im/chat/views/input/input.cljs @@ -18,7 +18,8 @@ [status-im.ui.components.react :as react] [status-im.ui.components.icons.vector-icons :as vi] [status-im.i18n :as i18n] - [status-im.utils.platform :as platform])) + [status-im.utils.platform :as platform] + [status-im.utils.utils :as utils])) (defn command-view [first? command] [react/touchable-highlight {:on-press #(dispatch [:select-chat-input-command command nil])} @@ -88,8 +89,8 @@ (.-height))] (set-layout-height-fn h))) :on-selection-change #(let [s (-> (.-nativeEvent %) - (.-selection)) - end (.-end s)] + (.-selection)) + end (.-end s)] (dispatch [:update-text-selection end])) :style (style/input-view height single-line-input?) :placeholder-text-color style/color-input-helper-placeholder @@ -162,7 +163,7 @@ (when-not (or (str/blank? @seq-arg-input-text) (get-in @command [:command :hide-send-button])) (dispatch [:send-seq-argument])) - (js/setTimeout + (utils/set-timeout #(dispatch [:chat-input-focus :seq-input-ref]) 100))} (get-options type))]))))) @@ -228,7 +229,7 @@ (do (when-not (str/blank? seq-arg-input-text) (dispatch [:send-seq-argument])) - (js/setTimeout + (utils/set-timeout (fn [] (dispatch [:chat-input-focus :seq-input-ref])) 100)) (dispatch [:send-current-message]))} diff --git a/src/status_im/core.cljs b/src/status_im/core.cljs index fa001e9143..cbbfd437a7 100644 --- a/src/status_im/core.cljs +++ b/src/status_im/core.cljs @@ -9,7 +9,7 @@ [goog.object :as object])) (when js/goog.DEBUG - (object/set js/console "ignoredYellowBox" #js ["re-frame: overwriting" "Setting a timer"])) + (object/set js/console "ignoredYellowBox" #js ["re-frame: overwriting"])) (defn init [app-root] (log/set-level! config/log-level) diff --git a/src/status_im/native_module/impl/module.cljs b/src/status_im/native_module/impl/module.cljs index 3b85d78942..171e16ab20 100644 --- a/src/status_im/native_module/impl/module.cljs +++ b/src/status_im/native_module/impl/module.cljs @@ -4,12 +4,12 @@ (:require [status-im.ui.components.react :as r] [re-frame.core :refer [dispatch]] [taoensso.timbre :as log] - [cljs.core.async :as async :refer [pending-message to)] diff --git a/src/status_im/ui/components/carousel/carousel.cljs b/src/status_im/ui/components/carousel/carousel.cljs index 3b82c4aefb..cd93ec250c 100644 --- a/src/status_im/ui/components/carousel/carousel.cljs +++ b/src/status_im/ui/components/carousel/carousel.cljs @@ -3,7 +3,8 @@ [status-im.ui.components.react :as react] [status-im.ui.components.carousel.styles :as st] [taoensso.timbre :as log] - [status-im.react-native.js-dependencies :as rn-dependencies])) + [status-im.react-native.js-dependencies :as rn-dependencies] + [status-im.utils.utils :as utils])) (defn window-page-width [] @@ -88,7 +89,7 @@ (log/debug "go-to-page: props-page-width=" page-width "; gap=" gap "; page-position=" page-position "; page: " page) (reagent.core/set-state component {:scrolling? true}) - (js/setTimeout #(reagent.core/set-state component {:scrolling? false}) 200) + (utils/set-timeout #(reagent.core/set-state component {:scrolling? false}) 200) (scroll-to component page-position 0) (reagent.core/set-state component {:activePage page}) (when (:onPageChange props) diff --git a/src/status_im/ui/components/react.cljs b/src/status_im/ui/components/react.cljs index 95b6c2712b..bcba3a640d 100644 --- a/src/status_im/ui/components/react.cljs +++ b/src/status_im/ui/components/react.cljs @@ -196,7 +196,7 @@ (if (or (nil? timeout) (> 100 timeout)) (reset! loading false) - (js/setTimeout (fn [] + (u/set-timeout (fn [] (reset! loading false)) timeout)))} (if (and (not enabled?) @loading) diff --git a/src/status_im/ui/screens/accounts/login/events.cljs b/src/status_im/ui/screens/accounts/login/events.cljs index 3ccbb3077f..b4ab5598f6 100644 --- a/src/status_im/ui/screens/accounts/login/events.cljs +++ b/src/status_im/ui/screens/accounts/login/events.cljs @@ -8,7 +8,8 @@ [status-im.data-store.core :as data-store] [status-im.native-module.core :as status] [status-im.constants :refer [console-chat-id]] - [status-im.utils.config :as config])) + [status-im.utils.config :as config] + [status-im.utils.utils :as utils])) ;;;; FX @@ -31,7 +32,7 @@ ;; if we don't add delay when running app without status-go ;; "null is not an object (evaluating 'realm.schema')" error appears (if config/stub-status-go? - (js/setTimeout + (utils/set-timeout (fn [] (data-store/change-account address new-account? #(dispatch [:change-account-handler % address new-account?]))) diff --git a/src/status_im/ui/screens/discover/events.cljs b/src/status_im/ui/screens/discover/events.cljs index 2cc7041aa4..c84a1fa95e 100644 --- a/src/status_im/ui/screens/discover/events.cljs +++ b/src/status_im/ui/screens/discover/events.cljs @@ -3,7 +3,8 @@ [status-im.protocol.core :as protocol] [status-im.ui.screens.discover.navigation] [status-im.utils.handlers :as handlers] - [clojure.string :as string])) + [clojure.string :as string] + [status-im.utils.utils :as utils])) (def request-discoveries-interval-s 600) (def maximum-number-of-discoveries 1000) @@ -117,8 +118,14 @@ (handlers/register-handler-fx :init-discoveries [(re-frame/inject-cofx :data-store/discoveries)] - (fn [{:keys [data-store/discoveries db]} _] - {:db (assoc db :discoveries discoveries) + (fn [{:keys [data-store/discoveries db] {:keys [request-discoveries-timer]} :db} _] + (when request-discoveries-timer + (utils/clear-interval request-discoveries-timer)) + {:db (assoc db + :discoveries discoveries + :request-discoveries-timer + (utils/set-interval #(re-frame/dispatch [:request-discoveries]) + (* request-discoveries-interval-s 1000))) :dispatch [:request-discoveries]})) (handlers/register-handler-fx @@ -126,18 +133,11 @@ [(re-frame/inject-cofx :random-id)] (fn [{{:keys [current-public-key web3] :contacts/keys [contacts]} :db - random-id :random-id} [this-event]] - ;; this event calls itself at regular intervals - ;; TODO (yenda): this was previously using setInterval explicitly, with - ;; dispatch-later it is using it implicitly. setInterval is - ;; problematic for such long period of time and will cause a warning - ;; for Android in latest versions of react-nativexb + random-id :random-id} _] {::request-discoveries {:current-public-key current-public-key :web3 web3 :identities (handlers/identities contacts) - :message-id random-id} - :dispatch-later [{:ms (* request-discoveries-interval-s 1000) - :dispatch [this-event]}]})) + :message-id random-id}})) (handlers/register-handler-fx :discoveries-send-portions diff --git a/src/status_im/ui/screens/wallet/request/views.cljs b/src/status_im/ui/screens/wallet/request/views.cljs index ee1d15b89c..0290031bad 100644 --- a/src/status_im/ui/screens/wallet/request/views.cljs +++ b/src/status_im/ui/screens/wallet/request/views.cljs @@ -15,7 +15,8 @@ [status-im.ui.screens.wallet.styles :as wallet.styles] [status-im.utils.ethereum.core :as ethereum] [status-im.utils.ethereum.eip681 :as eip681] - [status-im.utils.ethereum.tokens :as tokens])) + [status-im.utils.ethereum.tokens :as tokens] + [status-im.utils.utils :as utils])) (defn toolbar-view [] [toolbar/toolbar {:style wallet.styles/toolbar} @@ -63,7 +64,7 @@ [qr-code amount symbol]]]] [components/amount-selector {:error amount-error - :input-options {:on-focus (fn [] (when @scroll (js/setTimeout #(.scrollToEnd @scroll) 100))) + :input-options {:on-focus (fn [] (when @scroll (utils/set-timeout #(.scrollToEnd @scroll) 100))) :on-change-text #(re-frame/dispatch [:wallet.request/set-and-validate-amount %])}}] [components/asset-selector {:type :request :symbol symbol}]]] diff --git a/src/status_im/ui/screens/wallet/send/events.cljs b/src/status_im/ui/screens/wallet/send/events.cljs index cf6e198b56..42b63c0092 100644 --- a/src/status_im/ui/screens/wallet/send/events.cljs +++ b/src/status_im/ui/screens/wallet/send/events.cljs @@ -46,7 +46,7 @@ ::show-transaction-error (fn [message] ;; (andrey) we need this timeout because modal window conflicts with alert - (js/setTimeout #(utils/show-popup (i18n/label :t/transaction-failed) message) 1000))) + (utils/set-timeout #(utils/show-popup (i18n/label :t/transaction-failed) message) 1000))) (re-frame/reg-fx :discard-transaction diff --git a/src/status_im/ui/screens/wallet/send/views.cljs b/src/status_im/ui/screens/wallet/send/views.cljs index 608a554fad..fbf6fa6ad1 100644 --- a/src/status_im/ui/screens/wallet/send/views.cljs +++ b/src/status_im/ui/screens/wallet/send/views.cljs @@ -182,7 +182,7 @@ (when-not sufficient-funds? (i18n/label :t/wallet-insufficient-funds))) :input-options {:default-value (str (money/to-fixed (money/wei->ether amount))) :max-length 21 - :on-focus (fn [] (when @scroll (js/setTimeout #(.scrollToEnd @scroll) 100))) + :on-focus (fn [] (when @scroll (utils/set-timeout #(.scrollToEnd @scroll) 100))) :on-change-text #(re-frame/dispatch [:wallet.send/set-and-validate-amount %])}}] [advanced-options advanced? transaction modal?]]] (if signing? diff --git a/src/status_im/utils/async.cljs b/src/status_im/utils/async.cljs index 849d467d23..248f52faa4 100644 --- a/src/status_im/utils/async.cljs +++ b/src/status_im/utils/async.cljs @@ -1,6 +1,12 @@ (ns status-im.utils.async "Utility namespace containing `core.async` helper constructs" - (:require [cljs.core.async :as async])) + (:require [cljs.core.async :as async] + [status-im.utils.utils :as utils])) + +(defn timeout [ms] + (let [c (async/chan)] + (utils/set-timeout (fn [] (async/close! c)) ms) + c)) (defn chunked-pipe! "Connects input channel to the output channel with time-based chunking. @@ -16,7 +22,7 @@ (if flush? (do (async/put! output-ch acc) (recur [] false)) - (let [[v ch] (async/alts! [input-ch (async/timeout flush-time)])] + (let [[v ch] (async/alts! [input-ch (timeout flush-time)])] (if (= ch input-ch) (if v (recur (conj acc v) (and (seq acc) flush?)) diff --git a/src/status_im/utils/pre_receiver.cljs b/src/status_im/utils/pre_receiver.cljs index a46b0d2ec8..2133dc99d6 100644 --- a/src/status_im/utils/pre_receiver.cljs +++ b/src/status_im/utils/pre_receiver.cljs @@ -1,6 +1,7 @@ (ns status-im.utils.pre-receiver (:require [cljs.core.async :as async] - [taoensso.timbre :as log])) + [taoensso.timbre :as log] + [status-im.utils.async :as async-utils])) ;; See status-im.test.utils.pre-receiver for justification. @@ -25,7 +26,7 @@ (async/go-loop [] (let [{:keys [message-id clock-value] :as msg} (async/