diff --git a/src/mocks/js_dependencies.cljs b/src/mocks/js_dependencies.cljs index 2712704b92..71ba47bc80 100644 --- a/src/mocks/js_dependencies.cljs +++ b/src/mocks/js_dependencies.cljs @@ -323,7 +323,11 @@ (def react-native-permissions #js {:default #js {}}) -(def push-notification-ios #js {:default #js {:abandonPermissions identity}}) +(def push-notification-ios + #js + {:default #js + {:abandonPermissions identity + :removeAllDeliveredNotifications identity}}) (def rn-emoji-keyboard #js {:EmojiKeyboard #js {}}) diff --git a/src/native_module/core.cljs b/src/native_module/core.cljs index 855484bed7..9967a33d2f 100644 --- a/src/native_module/core.cljs +++ b/src/native_module/core.cljs @@ -3,7 +3,6 @@ [utils.validators :as validators] [taoensso.timbre :as log] [react-native.platform :as platform] - [react-native.core :as rn] [utils.transforms :as types] [clojure.string :as string])) @@ -14,7 +13,7 @@ (defn init [handler] - (.addListener ^js rn/device-event-emitter "gethEvent" #(handler (.-jsonEvent ^js %)))) + (.addListener ^js (.-DeviceEventEmitter ^js react-native) "gethEvent" #(handler (.-jsonEvent ^js %)))) (defn clear-web-data [] diff --git a/src/native_module/push_notifications.cljs b/src/native_module/push_notifications.cljs new file mode 100644 index 0000000000..40ba15dee4 --- /dev/null +++ b/src/native_module/push_notifications.cljs @@ -0,0 +1,42 @@ +(ns native-module.push-notifications + (:require ["react-native" :as react-native] + [taoensso.timbre :as log])) + +(defn push-notification + [] + (when (exists? (.-NativeModules react-native)) + (.-PushNotification ^js (.-NativeModules react-native)))) + +(defn present-local-notification + [opts] + (.presentLocalNotification ^js (push-notification) (clj->js opts))) + +(defn clear-message-notifications + [chat-id] + (.clearMessageNotifications ^js (push-notification) chat-id)) + +(defn clear-all-message-notifications + [] + (.clearAllMessageNotifications ^js (push-notification))) + +(defn create-channel + [{:keys [channel-id channel-name]}] + (.createChannel ^js (push-notification) + #js {:channelId channel-id :channelName channel-name} + #(log/info "Notifications create channel:" %))) + +(defn enable-notifications + [] + (.enableNotifications ^js (push-notification))) + +(defn disable-notifications + [] + (.disableNotifications ^js (push-notification))) + +(defn add-listener + [event callback] + (.addListener ^js (.-DeviceEventEmitter ^js react-native) + event + (fn [^js data] + (when (and data (.-dataJSON data) callback) + (callback (.-dataJSON data)))))) diff --git a/src/react_native/push_notification_ios.cljs b/src/react_native/push_notification_ios.cljs new file mode 100644 index 0000000000..5031592779 --- /dev/null +++ b/src/react_native/push_notification_ios.cljs @@ -0,0 +1,24 @@ +(ns react-native.push-notification-ios + (:require ["@react-native-community/push-notification-ios" :default pn-ios])) + +(defn present-local-notification + [title message user-info] + (.presentLocalNotification ^js pn-ios #js {:alertBody message :alertTitle title :userInfo user-info})) + +(defn add-listener + [event callback] + (.addEventListener ^js pn-ios event callback)) + +(defn request-permissions + [] + (-> (.requestPermissions ^js pn-ios) + (.then #()) + (.catch #()))) + +(defn abandon-permissions + [] + (.abandonPermissions ^js pn-ios)) + +(defn remove-all-delivered-notifications + [] + (.removeAllDeliveredNotifications ^js pn-ios)) diff --git a/src/status_im/chat/models/loading.cljs b/src/status_im/chat/models/loading.cljs index 1995bb0a4b..edfc2282fb 100644 --- a/src/status_im/chat/models/loading.cljs +++ b/src/status_im/chat/models/loading.cljs @@ -83,24 +83,26 @@ (rf/defn handle-mark-all-read {:events [:chat.ui/mark-all-read-pressed :chat/mark-all-as-read]} [{db :db} chat-id] - {:db (mark-chat-all-read db chat-id) - :clear-message-notifications [[chat-id] - (get-in db [:profile/profile :remote-push-notifications-enabled?])] - :json-rpc/call [{:method "wakuext_markAllRead" - :params [chat-id] - :on-success #(re-frame/dispatch [::mark-all-read-successful])}]}) + {:db (mark-chat-all-read db chat-id) + :effects/push-notifications-clear-message-notifications [chat-id] + :json-rpc/call [{:method "wakuext_markAllRead" + :params [chat-id] + :on-success + #(re-frame/dispatch + [::mark-all-read-successful])}]}) (rf/defn handle-mark-mark-all-read-in-community {:events [:chat.ui/mark-all-read-in-community-pressed]} [{db :db} community-id] (let [community-chat-ids (map #(str community-id %) (keys (get-in db [:communities community-id :chats])))] - {:clear-message-notifications [community-chat-ids - (get-in db [:profile/profile :remote-push-notifications-enabled?])] - :json-rpc/call [{:method "wakuext_markAllReadInCommunity" - :params [community-id] - :on-success #(re-frame/dispatch - [::mark-all-read-in-community-successful %])}]})) + {:effects/push-notifications-clear-message-notifications community-chat-ids + :json-rpc/call [{:method "wakuext_markAllReadInCommunity" + :params [community-id] + :on-success + #(re-frame/dispatch + [::mark-all-read-in-community-successful + %])}]})) (rf/defn messages-loaded "Loads more messages for current chat" diff --git a/src/status_im/communities/core.cljs b/src/status_im/communities/core.cljs index 09627e3a55..6f37100690 100644 --- a/src/status_im/communities/core.cljs +++ b/src/status_im/communities/core.cljs @@ -271,18 +271,20 @@ [{:keys [db]} community-id] (let [community-chat-ids (map #(str community-id %) (keys (get-in db [:communities community-id :chats])))] - {:clear-message-notifications [community-chat-ids - (get-in db [:profile/profile :remote-push-notifications-enabled?])] - :dispatch [:shell/close-switcher-card community-id] - :json-rpc/call [{:method "wakuext_leaveCommunity" - :params [community-id] - :js-response true - :on-success #(re-frame/dispatch [::left %]) - :on-error (fn [response] - (log/error "failed to leave community" - community-id - response) - (re-frame/dispatch [::failed-to-leave]))}]})) + {:effects/push-notifications-clear-message-notifications community-chat-ids + :dispatch [:shell/close-switcher-card community-id] + :json-rpc/call [{:method "wakuext_leaveCommunity" + :params [community-id] + :js-response true + :on-success #(re-frame/dispatch [::left + %]) + :on-error (fn [response] + (log/error + "failed to leave community" + community-id + response) + (re-frame/dispatch + [::failed-to-leave]))}]})) (rf/defn status-tag-pressed {:events [:communities/status-tag-pressed]} diff --git a/src/status_im/contact/block.cljs b/src/status_im/contact/block.cljs index 487b76e573..4cb4ec6ceb 100644 --- a/src/status_im/contact/block.cljs +++ b/src/status_im/contact/block.cljs @@ -41,17 +41,20 @@ (map #(->> (chats-store/<-rpc %) (clean-up-chat public-key)) (types/js->clj chats-js)))] - (apply rf/merge - cofx - {:db (-> db - (update :chats dissoc public-key) - (update :chats-home-list disj public-key) - (assoc-in [:contacts/contacts public-key :added?] false)) - :dispatch [:shell/close-switcher-card public-key] - :clear-message-notifications - [[public-key] (get-in db [:profile/profile :remote-push-notifications-enabled?])]} - (activity-center/notifications-fetch-unread-count) - fxs))) + (apply + rf/merge + cofx + {:db (-> + db + (update :chats dissoc public-key) + (update :chats-home-list disj public-key) + (assoc-in [:contacts/contacts public-key + :added?] + false)) + :dispatch [:shell/close-switcher-card public-key] + :effects/push-notifications-clear-message-notifications [public-key]} + (activity-center/notifications-fetch-unread-count) + fxs))) (rf/defn block-contact {:events [:contact.ui/block-contact-confirmed]} diff --git a/src/status_im/events.cljs b/src/status_im/events.cljs index 71c5d42e29..c0e5d7eab2 100644 --- a/src/status_im/events.cljs +++ b/src/status_im/events.cljs @@ -60,7 +60,8 @@ status-im2.contexts.chat.home.events status-im2.contexts.communities.home.events status-im.ui.components.invite.events - [status-im2.common.biometric.events :as biometric])) + [status-im2.common.biometric.events :as biometric] + status-im.ui.screens.notifications-settings.events)) (re-frame/reg-fx :dismiss-keyboard diff --git a/src/status_im/multiaccounts/create/core.cljs b/src/status_im/multiaccounts/create/core.cljs index 2967824d79..cfabd634aa 100644 --- a/src/status_im/multiaccounts/create/core.cljs +++ b/src/status_im/multiaccounts/create/core.cljs @@ -165,7 +165,6 @@ :dapps-address (:address wallet-account) :latest-derived-path 0 :signing-phrase signing-phrase - :send-push-notifications? true :backup-enabled? true :installation-id (random-guid-generator) ;; default mailserver (history node) setting diff --git a/src/status_im/multiaccounts/logout/core.cljs b/src/status_im/multiaccounts/logout/core.cljs index ed931d7cf1..dcec2f0442 100644 --- a/src/status_im/multiaccounts/logout/core.cljs +++ b/src/status_im/multiaccounts/logout/core.cljs @@ -2,7 +2,6 @@ (:require [native-module.core :as native-module] [re-frame.core :as re-frame] [status-im.multiaccounts.core :as multiaccounts] - [status-im.notifications.core :as notifications] [status-im.wallet.core :as wallet] [status-im2.common.keychain.events :as keychain] [status-im2.db :as db] @@ -46,14 +45,13 @@ (rf/defn logout {:events [:logout :multiaccounts.logout.ui/logout-confirmed :multiaccounts.update.callback/save-settings-success]} - [cofx] + [_] ;; we need to disable notifications before starting the logout process - (rf/merge cofx - {:dispatch-later [{:ms 100 - :dispatch [::logout-method - {:auth-method keychain/auth-method-none - :logout? true}]}]} - (notifications/logout-disable))) + {:effects/push-notifications-disable nil + :dispatch-later [{:ms 100 + :dispatch [::logout-method + {:auth-method keychain/auth-method-none + :logout? true}]}]}) (rf/defn show-logout-confirmation {:events [:multiaccounts.logout.ui/logout-pressed]} diff --git a/src/status_im/notifications/android.cljs b/src/status_im/notifications/android.cljs deleted file mode 100644 index 6e892465af..0000000000 --- a/src/status_im/notifications/android.cljs +++ /dev/null @@ -1,37 +0,0 @@ -(ns status-im.notifications.android - (:require ["react-native" :as react-native] - [quo.platform :as platform] - [taoensso.timbre :as log])) - -(defn pn-android - [] - (when platform/android? - (.-PushNotification ^js (.-NativeModules react-native)))) - -(defn present-local-notification - [opts] - (.presentLocalNotification ^js (pn-android) (clj->js opts))) - -(defn clear-message-notifications - [chat-id] - (.clearMessageNotifications ^js (pn-android) chat-id)) - -(defn clear-all-message-notifications - [] - (.clearAllMessageNotifications ^js (pn-android))) - -(defn create-channel - [{:keys [channel-id channel-name]}] - (.createChannel ^js (pn-android) - #js - {:channelId channel-id - :channelName channel-name} - #(log/info "Notifications create channel:" %))) - -(defn enable-notifications - [] - (.enableNotifications ^js (pn-android))) - -(defn disable-notifications - [] - (.disableNotifications ^js (pn-android))) diff --git a/src/status_im/notifications/core.cljs b/src/status_im/notifications/core.cljs deleted file mode 100644 index bc05268d2d..0000000000 --- a/src/status_im/notifications/core.cljs +++ /dev/null @@ -1,313 +0,0 @@ -(ns status-im.notifications.core - (:require ["@react-native-community/push-notification-ios" :default pn-ios] - [quo.platform :as platform] - [re-frame.core :as re-frame] - [status-im.multiaccounts.update.core :as multiaccounts.update] - [status-im.notifications.android :as pn-android] - [status-im.notifications.local :as local] - [status-im2.config :as config] - [utils.re-frame :as rf] - [taoensso.timbre :as log])) - -(def server-type-default 1) -(def server-type-custom 2) - -(def apn-token-type 1) -(def firebase-token-type 2) -(def listeners-added? (atom nil)) -(defn server<-rpc - [{:keys [type publicKey registered]}] - {:public-key publicKey - :type type - :registered registered}) - -(defn add-event-listeners - [] - (when-not @listeners-added? - (reset! listeners-added? true) - (.addEventListener - ^js pn-ios - "register" - (fn [token] - (re-frame/dispatch [:notifications/registered-for-push-notifications token]))) - (.addEventListener - ^js pn-ios - "registrationError" - (fn [error] - (re-frame/dispatch [:notifications/switch-error true error]))))) - -(defn enable-ios-notifications - [] - (add-event-listeners) - (-> (.requestPermissions ^js pn-ios) - (.then #()) - (.catch #()))) - -(defn disable-ios-notifications - [] - (.abandonPermissions ^js pn-ios) - (re-frame/dispatch [:notifications/unregistered-from-push-notifications])) - -(defn enable-android-notifications - [] - (pn-android/create-channel - {:channel-id "status-im-notifications" - :channel-name "Status push notifications"}) - (pn-android/enable-notifications)) - -(defn disable-android-notifications - [] - (pn-android/disable-notifications)) - -;; FIXME: Repalce with request permission from audio messages PR lib -(re-frame/reg-fx - ::request-permission - identity) - -(rf/defn request-permission - {:events [::request-permission]} - [_] - {::request-permission true}) - -(re-frame/reg-fx - ::local-notification - (fn [props] - (if platform/ios? - (local/local-push-ios props) - (local/local-push-android props)))) - -(re-frame/reg-fx - ::enable - (fn [] - (if platform/android? - (enable-android-notifications) - (enable-ios-notifications)))) - -(re-frame/reg-fx - ::disable - (fn [_] - (if platform/android? - (disable-android-notifications) - (disable-ios-notifications)))) - -(re-frame/reg-fx - ::logout-disable - (fn [_] - (if platform/android? - (pn-android/disable-notifications) - (.abandonPermissions ^js pn-ios)))) - -(re-frame/reg-fx - :clear-message-notifications - (fn [[chat-ids] remote-push-notifications-enabled?] - (if remote-push-notifications-enabled? - (if platform/android? - (pn-android/clear-all-message-notifications) - (.removeAllDeliveredNotifications ^js pn-ios)) - (when platform/android? - (doseq [chat-id chat-ids] - (pn-android/clear-message-notifications chat-id)))))) - -(rf/defn handle-enable-notifications-event - {:events [:notifications/registered-for-push-notifications]} - [cofx token] - {:json-rpc/call [{:method "wakuext_registerForPushNotifications" - :params [token (if platform/ios? config/apn-topic) - (if platform/ios? apn-token-type firebase-token-type)] - :on-success #(log/info "[push-notifications] register-success" %) - :on-error #(re-frame/dispatch [:notifications/switch-error true %])}]}) - -(rf/defn handle-disable-notifications-event - {:events [:notifications/unregistered-from-push-notifications]} - [cofx] - {:json-rpc/call [{:method "wakuext_unregisterFromPushNotifications" - :params [] - :on-success #(log/info "[push-notifications] unregister-success" %) - :on-error #(re-frame/dispatch [:notifications/switch-error false %])}]}) - -(rf/defn logout-disable - [cofx] - (merge {::logout-disable nil} - {:json-rpc/call [{:method "wakuext_unregisterFromPushNotifications" - :params [] - :on-success #(log/info "[push-notifications] unregister-success" %) - :on-error #(log/info "[push-notifications] unregister-error" %)}]})) - -(rf/defn notification-switch-error - {:events [:notifications/switch-error]} - [cofx enabled?] - (multiaccounts.update/multiaccount-update - cofx - :remote-push-notifications-enabled? - (not enabled?) - {})) - -(rf/defn notification-switch - {:events [::switch]} - [{:keys [db] :as cofx} enabled? remote-push-notifications?] - (rf/merge cofx - (if enabled? - {::enable remote-push-notifications?} - {::disable nil}) - (multiaccounts.update/multiaccount-update - :remote-push-notifications-enabled? - (and remote-push-notifications? enabled?) - {}) - (multiaccounts.update/multiaccount-update - :notifications-enabled? - (and (not remote-push-notifications?) enabled?) - {}))) - -(rf/defn notification-non-contacts-error - {:events [::non-contacts-update-error]} - [cofx enabled?] - (multiaccounts.update/optimistic cofx - :push-notifications-from-contacts-only? - (not (boolean enabled?)))) - -(rf/defn notification-block-mentions-error - {:events [::block-mentions-update-error]} - [cofx enabled?] - (multiaccounts.update/optimistic cofx :push-notifications-block-mentions? (not (boolean enabled?)))) - -(rf/defn notification-non-contacts - {:events [::switch-non-contacts]} - [{:keys [db] :as cofx} enabled?] - (let [method (if enabled? - "wakuext_enablePushNotificationsFromContactsOnly" - "wakuext_disablePushNotificationsFromContactsOnly")] - (rf/merge - cofx - {:json-rpc/call [{:method method - :params [] - :on-success #(log/info "[push-notifications] contacts-notification-success" %) - :on-error #(re-frame/dispatch [::non-contacts-update-error enabled? %])}]} - - (multiaccounts.update/optimistic :push-notifications-from-contacts-only? (boolean enabled?))))) - -(rf/defn notification-block-mentions - {:events [::switch-block-mentions]} - [{:keys [db] :as cofx} enabled?] - (let [method (if enabled? - "wakuext_enablePushNotificationsBlockMentions" - "wakuext_disablePushNotificationsBlockMentions")] - (log/info "USING METHOD" method enabled?) - (rf/merge cofx - {:json-rpc/call [{:method method - :params [] - :on-success #(log/info "[push-notifications] block-mentions-success" %) - :on-error #(re-frame/dispatch [::block-mentions-update-error enabled? - %])}]} - - (multiaccounts.update/optimistic :push-notifications-block-mentions? (boolean enabled?))))) - -(rf/defn switch-push-notifications-server-enabled - {:events [::switch-push-notifications-server-enabled]} - [{:keys [db] :as cofx} enabled?] - (let [method (if enabled? - "wakuext_startPushNotificationsServer" - "wakuext_stopPushNotificationsServer")] - (rf/merge - cofx - {:json-rpc/call [{:method method - :params [] - :on-success #(log/info "[push-notifications] switch-server-enabled successful" %) - :on-error #(re-frame/dispatch [::push-notifications-server-update-error - enabled? %])}]} - - (multiaccounts.update/optimistic :push-notifications-server-enabled? (boolean enabled?))))) - -(rf/defn switch-send-notifications - {:events [::switch-send-push-notifications]} - [{:keys [db] :as cofx} enabled?] - (let [method (if enabled? - "wakuext_enableSendingNotifications" - "wakuext_disableSendingNotifications")] - (rf/merge cofx - {:json-rpc/call [{:method method - :params [] - :on-success - #(log/info "[push-notifications] switch-send-notifications successful" - %) - :on-error #(re-frame/dispatch [::push-notifications-send-update-error - enabled? %])}]} - - (multiaccounts.update/optimistic :send-push-notifications? (boolean enabled?))))) - -(rf/defn handle-add-server-error - {:events [::push-notifications-add-server-error]} - [_ public-key error] - (log/error "failed to add server" public-key error)) - -(rf/defn add-server - {:events [::add-server]} - [{:keys [db] :as cofx} public-key] - (rf/merge cofx - {:json-rpc/call [{:method "wakuext_addPushNotificationsServer" - :params [public-key] - :on-success - #(do - (log/info "[push-notifications] switch-send-notifications successful" - %) - (re-frame/dispatch [::fetch-servers])) - :on-error #(re-frame/dispatch [::push-notifications-add-server-error - public-key %])}]})) - -(rf/defn handle-servers-fetched - {:events [::servers-fetched]} - [{:keys [db]} servers] - {:db (assoc db :push-notifications/servers (map server<-rpc servers))}) - -(rf/defn fetch-push-notifications-servers - {:events [::fetch-servers]} - [cofx] - {:json-rpc/call [{:method "wakuext_getPushNotificationsServers" - :params [] - :on-success #(do - (log/info "[push-notifications] servers fetched" %) - (re-frame/dispatch [::servers-fetched %]))}]}) - -;; Wallet transactions - -(rf/defn handle-preferences-load - {:events [::preferences-loaded]} - [{:keys [db]} preferences] - {:db (assoc db :push-notifications/preferences preferences)}) - -(rf/defn load-notification-preferences - {:events [::load-notification-preferences]} - [_] - {:json-rpc/call [{:method "localnotifications_notificationPreferences" - :params [] - :on-success #(re-frame/dispatch [::preferences-loaded %])}]}) - -(defn preference= - [x y] - (and (= (:service x) (:service y)) - (= (:event x) (:event y)) - (= (:identifier x) (:identifier y)))) - -(defn- update-preference - [all new-preference] - (conj (filter (comp not (partial preference= new-preference)) - all) - new-preference)) - -(rf/defn switch-transaction-notifications - {:events [::switch-transaction-notifications]} - [{:keys [db] :as cofx} enabled?] - {:db (update db - :push-notifications/preferences - update-preference - {:enabled (not enabled?) - :service "wallet" - :event "transaction" - :identifier "all"}) - :json-rpc/call [{:method "localnotifications_switchWalletNotifications" - :params [(not enabled?)] - :on-success #(log/info - "[push-notifications] switch-transaction-notifications successful" - %) - :on-error #(log/error - "[push-notifications] switch-transaction-notifications error" - %)}]}) diff --git a/src/status_im/notifications/local.cljs b/src/status_im/notifications/local.cljs deleted file mode 100644 index 8aa31d7d11..0000000000 --- a/src/status_im/notifications/local.cljs +++ /dev/null @@ -1,150 +0,0 @@ -(ns status-im.notifications.local - (:require ["@react-native-community/push-notification-ios" :default pn-ios] - [cljs-bean.core :as bean] - [clojure.string :as string] - [quo.platform :as platform] - [re-frame.core :as re-frame] - [react-native.async-storage :as async-storage] - [status-im.ethereum.decode :as decode] - [status-im.ethereum.tokens :as tokens] - [utils.i18n :as i18n] - [status-im.notifications.android :as pn-android] - [utils.re-frame :as rf] - [utils.money :as money] - [status-im.utils.deprecated-types :as types] - [status-im.utils.utils :as utils] - [react-native.core :as rn])) - -(def default-erc20-token - {:symbol :ERC20 - :decimals 18 - :name "ERC20"}) - -(def notification-event-ios "localNotification") -(def notification-event-android "remoteNotificationReceived") - -(defn local-push-ios - [{:keys [title message user-info body-type]}] - (when (not= body-type "message") - (.presentLocalNotification - pn-ios - #js - {:alertBody message - :alertTitle title - ;; NOTE: Use a special type to hide in Obj-C code other notifications - :userInfo (bean/->js (merge user-info - {:notificationType "local-notification"}))}))) - -(defn local-push-android - [notification] - (pn-android/present-local-notification notification)) - -(defn handle-notification-press - [{{deep-link :deepLink} :userInfo - interaction :userInteraction}] - (async-storage/set-item! (str :chat-id) nil) - (when (and deep-link - (or platform/ios? - (and platform/android? interaction))) - (re-frame/dispatch [:universal-links/handle-url deep-link]))) - -(defn listen-notifications - [] - (if platform/ios? - (.addEventListener ^js pn-ios - notification-event-ios - (fn [notification] - (handle-notification-press {:userInfo (bean/bean (.getData ^js - notification))}))) - (.addListener ^js rn/device-event-emitter - notification-event-android - (fn [^js data] - (when (and data (.-dataJSON data)) - (handle-notification-press (types/json->clj (.-dataJSON data)))))))) - -(defn create-transfer-notification - [{db :db} - {{:keys [state from to fromAccount toAccount value erc20 contract network]} - :body - :as notification}] - (let [token (if erc20 - (get-in db - [:wallet/all-tokens (string/lower-case contract)] - default-erc20-token) - (tokens/native-currency network)) - amount (money/wei->ether (decode/uint value)) - to (or (:name toAccount) (utils/get-shortened-address to)) - from (or (:name fromAccount) (utils/get-shortened-address from)) - title (case state - "inbound" (i18n/label :t/push-inbound-transaction - {:value amount - :currency (:symbol token)}) - "outbound" (i18n/label :t/push-outbound-transaction - {:value amount - :currency (:symbol token)}) - "failed" (i18n/label :t/push-failed-transaction - {:value amount - :currency (:symbol token)}) - nil) - description (case state - "inbound" (i18n/label :t/push-inbound-transaction-body - {:from from - :to to}) - "outbound" (i18n/label :t/push-outbound-transaction-body - {:from from - :to to}) - "failed" (i18n/label :t/push-failed-transaction-body - {:value amount - :currency (:symbol token) - :to to}) - nil)] - {:title title - :icon (get-in token [:icon :source]) - :deepLink (:deepLink notification) - :user-info notification - :message description})) - -(defn foreground-chat? - [{{:keys [current-chat-id view-id]} :db} chat-id] - (and (= current-chat-id chat-id) - (= view-id :chat))) - -(defn show-message-pn? - [{{:keys [app-state profile/profile]} :db :as cofx} - notification] - (let [chat-id (get-in notification [:body :chat :id]) - notification-author (get-in notification [:notificationAuthor :id])] - (and - (not= notification-author (:public-key profile)) - (or (= app-state "background") - (not (foreground-chat? cofx chat-id)))))) - -(defn create-notification - ([notification] - (create-notification nil notification)) - ([cofx {:keys [bodyType] :as notification}] - (assoc - (case bodyType - "message" (when (show-message-pn? cofx notification) notification) - "transaction" (create-transfer-notification cofx notification) - nil) - :body-type - bodyType))) - -(re-frame/reg-fx - ::local-push-ios - (fn [evt] - (-> evt create-notification local-push-ios))) - -(rf/defn local-notification-android - {:events [::local-notification-android]} - [cofx event] - (some->> event - (create-notification cofx) - local-push-android)) - -(rf/defn process - [cofx evt] - (if platform/ios? - {::local-push-ios evt} - (local-notification-android cofx evt))) diff --git a/src/status_im/notifications/wallet.cljs b/src/status_im/notifications/wallet.cljs new file mode 100644 index 0000000000..d629751d61 --- /dev/null +++ b/src/status_im/notifications/wallet.cljs @@ -0,0 +1,83 @@ +(ns status-im.notifications.wallet + (:require [utils.re-frame :as rf] + [taoensso.timbre :as log] + [clojure.string :as string] + [status-im.ethereum.tokens :as tokens] + [utils.money :as money] + [status-im.ethereum.decode :as decode] + [status-im.utils.utils :as utils] + [utils.i18n :as i18n])) + +(def default-erc20-token + {:symbol :ERC20 + :decimals 18 + :name "ERC20"}) + +(defn preference= + [x y] + (and (= (:service x) (:service y)) + (= (:event x) (:event y)) + (= (:identifier x) (:identifier y)))) + +(defn- update-preference + [all new-preference] + (conj (filter (comp not (partial preference= new-preference)) + all) + new-preference)) + +(rf/defn switch-transaction-notifications + {:events [:push-notifications.wallet/switch-transactions]} + [{:keys [db]} enabled?] + {:db (update db + :push-notifications/preferences + update-preference + {:enabled? enabled? + :service "wallet" + :event "transaction" + :identifier "all"}) + :json-rpc/call [{:method "localnotifications_switchWalletNotifications" + :params [enabled?] + :on-success #(log/info "[push-notifications] switch-transaction successful" %) + :on-error #(log/error "[push-notifications] switch-transaction error" %)}]}) + +(defn create-transfer-notification + [{db :db} + {{:keys [state from to fromAccount toAccount value erc20 contract network]} + :body + :as notification}] + (let [token (if erc20 + (get-in db + [:wallet/all-tokens (string/lower-case contract)] + default-erc20-token) + (tokens/native-currency network)) + amount (money/wei->ether (decode/uint value)) + to (or (:name toAccount) (utils/get-shortened-address to)) + from (or (:name fromAccount) (utils/get-shortened-address from)) + title (case state + "inbound" (i18n/label :t/push-inbound-transaction + {:value amount + :currency (:symbol token)}) + "outbound" (i18n/label :t/push-outbound-transaction + {:value amount + :currency (:symbol token)}) + "failed" (i18n/label :t/push-failed-transaction + {:value amount + :currency (:symbol token)}) + nil) + description (case state + "inbound" (i18n/label :t/push-inbound-transaction-body + {:from from + :to to}) + "outbound" (i18n/label :t/push-outbound-transaction-body + {:from from + :to to}) + "failed" (i18n/label :t/push-failed-transaction-body + {:value amount + :currency (:symbol token) + :to to}) + nil)] + {:title title + :icon (get-in token [:icon :source]) + :deepLink (:deepLink notification) + :user-info notification + :message description})) diff --git a/src/status_im/signals/core.cljs b/src/status_im/signals/core.cljs index fe62586a2a..ff080b02fc 100644 --- a/src/status_im/signals/core.cljs +++ b/src/status_im/signals/core.cljs @@ -2,7 +2,7 @@ (:require [status-im.chat.models.message :as models.message] [status-im.ethereum.subscriptions :as ethereum.subscriptions] [status-im.mailserver.core :as mailserver] - [status-im.notifications.local :as local-notifications] + [status-im2.contexts.push-notifications.local.events :as local-notifications] [status-im.transport.message.core :as transport.message] [status-im.visibility-status-updates.core :as visibility-status-updates] [utils.re-frame :as rf] diff --git a/src/status_im/ui/screens/notifications_settings/events.cljs b/src/status_im/ui/screens/notifications_settings/events.cljs new file mode 100644 index 0000000000..5add06a57c --- /dev/null +++ b/src/status_im/ui/screens/notifications_settings/events.cljs @@ -0,0 +1,55 @@ +(ns status-im.ui.screens.notifications-settings.events + (:require [status-im.multiaccounts.update.core :as multiaccounts.update] + [utils.re-frame :as rf] + [taoensso.timbre :as log])) + +(rf/defn notification-non-contacts-error + {:events [:push-notifications/non-contacts-update-error]} + [cofx enabled?] + (multiaccounts.update/optimistic cofx + :push-notifications-from-contacts-only? + (not (boolean enabled?)))) + +(rf/defn notification-block-mentions-error + {:events [:push-notifications/block-mentions-update-error]} + [cofx enabled?] + (multiaccounts.update/optimistic cofx :push-notifications-block-mentions? (not (boolean enabled?)))) + +(rf/defn notification-non-contacts + {:events [:push-notifications/switch-non-contacts]} + [{:keys [db] :as cofx} enabled?] + (let [method (if enabled? + "wakuext_enablePushNotificationsFromContactsOnly" + "wakuext_disablePushNotificationsFromContactsOnly")] + (rf/merge + cofx + {:json-rpc/call [{:method method + :params [] + :on-success #(log/info "[push-notifications] contacts-notification-success" %) + :on-error #(log/info "[push-notifications] contacts-notification-error" %)}]} + (multiaccounts.update/optimistic :push-notifications-from-contacts-only? (boolean enabled?))))) + +(rf/defn notification-block-mentions + {:events [:push-notifications/switch-block-mentions]} + [{:keys [db] :as cofx} enabled?] + (let [method (if enabled? + "wakuext_enablePushNotificationsBlockMentions" + "wakuext_disablePushNotificationsBlockMentions")] + (rf/merge cofx + {:json-rpc/call [{:method method + :params [] + :on-success #(log/info "[push-notifications] block-mentions-success" %) + :on-error #(rf/dispatch + [:push-notifications/block-mentions-update-error enabled? + %])}]} + + (multiaccounts.update/optimistic :push-notifications-block-mentions? (boolean enabled?))))) + +(rf/defn notification-switch + {:events [:push-notifications/switch]} + [{:keys [db] :as cofx} enabled?] + (rf/merge cofx + (if enabled? + {:effects/push-notifications-enable nil} + {:effects/push-notifications-disable nil}) + (multiaccounts.update/multiaccount-update :notifications-enabled? enabled? {}))) diff --git a/src/status_im/ui/screens/notifications_settings/views.cljs b/src/status_im/ui/screens/notifications_settings/views.cljs index e02c79f516..3b500b3dac 100644 --- a/src/status_im/ui/screens/notifications_settings/views.cljs +++ b/src/status_im/ui/screens/notifications_settings/views.cljs @@ -1,19 +1,15 @@ (ns status-im.ui.screens.notifications-settings.views - (:require-macros [status-im.utils.views :refer [defview letsubs]]) (:require [quo.core :as quo] [quo.design-system.colors :as quo-colors] [quo.platform :as platform] - [re-frame.core :as re-frame] - [reagent.core :as reagent] [utils.i18n :as i18n] - [status-im.notifications.core :as notifications] - [status-im.ui.components.react :as react])) - -(defonce server (reagent/atom "")) + [status-im.ui.components.react :as react] + [utils.re-frame :as rf])) (defn local-notifications [] - (let [{:keys [enabled]} @(re-frame/subscribe [:notifications/wallet-transactions])] + (let [{:keys [enabled?]} (rf/sub [:push-notifications/wallet-transactions]) + {:keys [notifications-enabled?]} (rf/sub [:profile/profile])] [:<> [quo/separator {:color (:ui-02 @quo-colors/theme) @@ -23,25 +19,24 @@ {:size :small :title (i18n/label :t/notifications-transactions) :accessibility-label :notifications-button - :active enabled - :on-press #(re-frame/dispatch - [::notifications/switch-transaction-notifications enabled]) + :active (and notifications-enabled? enabled?) + :on-press #(rf/dispatch [:push-notifications.wallet/switch-transactions + (not enabled?)]) :accessory :switch}]])) (defn notifications-settings-ios [] - (let [{:keys [remote-push-notifications-enabled? + (let [{:keys [notifications-enabled? push-notifications-block-mentions? push-notifications-from-contacts-only?]} - @(re-frame/subscribe [:profile/profile])] + (rf/sub [:profile/profile])] [:<> [quo/list-item {:size :small :title (i18n/label :t/show-notifications) :accessibility-label :notifications-button - :active remote-push-notifications-enabled? - :on-press #(re-frame/dispatch [::notifications/switch - (not remote-push-notifications-enabled?) true]) + :active notifications-enabled? + :on-press #(rf/dispatch [:push-notifications/switch (not notifications-enabled?)]) :accessory :switch}] [quo/separator {:color (:ui-02 @quo-colors/theme) @@ -51,35 +46,34 @@ {:size :small :title (i18n/label :t/notifications-non-contacts) :accessibility-label :notifications-button - :active (and remote-push-notifications-enabled? + :active (and notifications-enabled? (not push-notifications-from-contacts-only?)) - :on-press #(re-frame/dispatch - [::notifications/switch-non-contacts + :on-press #(rf/dispatch + [:push-notifications/switch-non-contacts (not push-notifications-from-contacts-only?)]) :accessory :switch}] [quo/list-item {:size :small :title (i18n/label :t/allow-mention-notifications) :accessibility-label :notifications-button - :active (and remote-push-notifications-enabled? + :active (and notifications-enabled? (not push-notifications-block-mentions?)) - :on-press #(re-frame/dispatch - [::notifications/switch-block-mentions + :on-press #(rf/dispatch + [:push-notifications/switch-block-mentions (not push-notifications-block-mentions?)]) :accessory :switch}] [local-notifications]])) (defn notifications-settings-android [] - (let [{:keys [notifications-enabled?]} @(re-frame/subscribe [:profile/profile])] + (let [{:keys [notifications-enabled?]} (rf/sub [:profile/profile])] [:<> [quo/list-item {:title (i18n/label :t/local-notifications) :accessibility-label :local-notifications-settings-button :subtitle (i18n/label :t/local-notifications-subtitle) :active notifications-enabled? - :on-press #(re-frame/dispatch - [::notifications/switch (not notifications-enabled?) false]) + :on-press #(rf/dispatch [:push-notifications/switch (not notifications-enabled?)]) :accessory :switch}] [local-notifications]])) @@ -91,81 +85,3 @@ (if platform/ios? [notifications-settings-ios] [notifications-settings-android])]) - -(defn notifications-advanced-settings - [] - (let [{:keys [remote-push-notifications-enabled? - send-push-notifications? - push-notifications-server-enabled?]} - @(re-frame/subscribe [:profile/profile])] - [react/scroll-view - {:style {:flex 1} - :content-container-style {:padding-vertical 8}} - [quo/list-item - {:size :small - :title (i18n/label :t/send-push-notifications) - :accessibility-label :send-push-notifications-button - :active send-push-notifications? - :on-press #(re-frame/dispatch - [::notifications/switch-send-push-notifications - (not send-push-notifications?)]) - :accessory :switch}] - [quo/list-footer - (i18n/label :t/send-push-notifications-description)] - [quo/separator {:style {:margin-vertical 8}}] - [quo/list-item - {:size :small - :title (i18n/label :t/push-notifications-server-enabled) - :accessibility-label :send-push-notifications-button - :active (and remote-push-notifications-enabled? - push-notifications-server-enabled?) - :on-press #(re-frame/dispatch - [::notifications/switch-push-notifications-server-enabled - (not push-notifications-server-enabled?)]) - :accessory :switch}] - [quo/list-item - {:size :small - :title (i18n/label :t/push-notifications-servers) - :accessibility-label :send-push-notifications-button - :chevron true - :on-press #(re-frame/dispatch - [:navigate-to :notifications-servers])}]])) - -(defn server-view - [{:keys [public-key type registered]}] - [quo/list-item - {:size :small - :title (str (subs public-key 0 8) - " " - (if (= type notifications/server-type-custom) - (i18n/label :t/custom) - (i18n/label :t/default)) - " " - (if registered - (i18n/label :t/registered) - (i18n/label :t/not-registered)))}]) - -(defview notifications-servers - [] - (letsubs [servers [:push-notifications/servers]] - {:component-did-mount #(re-frame/dispatch [::notifications/fetch-servers])} - [react/scroll-view - {:style {:flex 1} - :content-container-style {:padding-vertical 8}} - (map server-view servers) - [react/keyboard-avoiding-view {} - [react/view {:style {:padding-horizontal 20}} - [quo/text-input - {:label (i18n/label :t/server) - :placeholder (i18n/label :t/specify-server-public-key) - :value @server - :on-change-text #(reset! server %) - :auto-focus true}]] - [quo/button - {:type :secondary - :after :main-icon/next - :disabled (empty? @server) - :on-press #(do - (re-frame/dispatch [::notifications/add-server @server]) - (reset! server ""))} - (i18n/label :t/save)]]])) diff --git a/src/status_im/ui/screens/screens.cljs b/src/status_im/ui/screens/screens.cljs index 688bff28b8..9a9a0525e8 100644 --- a/src/status_im/ui/screens/screens.cljs +++ b/src/status_im/ui/screens/screens.cljs @@ -312,10 +312,6 @@ :options {:topBar {:title {:text (i18n/label :t/notification-settings)}} :insets {:top? true}} :component notifications-settings/notifications-settings} - {:name :notifications-servers - :options {:topBar {:title {:text (i18n/label :t/notifications-servers)}} - :insets {:top? true}} - :component notifications-settings/notifications-servers} {:name :sync-settings :options {:topBar {:title {:text (i18n/label :t/sync-settings)}} :insets {:top? true}} @@ -475,17 +471,6 @@ :top? true}} :component notifications-settings/notifications-settings} - ;;TODO WHY MODAL? - ;[Profile] Notifications Advanced settings - {:name :notifications-advanced-settings - :options {:topBar {:title {:text (i18n/label :t/notification-settings)}} - :popGesture false - :hardwareBackButton {:dismissModalOnPress false - :popStackOnPress false} - :insets {:bottom? true - :top? true}} - :component notifications-settings/notifications-advanced-settings} - ;[Wallet] Prepare Transaction {:name :prepare-send-transaction :on-dissmiss [:wallet/cancel-transaction-command] diff --git a/src/status_im2/contexts/chat/events.cljs b/src/status_im2/contexts/chat/events.cljs index 0cf31d7c46..d87e26e04a 100644 --- a/src/status_im2/contexts/chat/events.cljs +++ b/src/status_im2/contexts/chat/events.cljs @@ -109,9 +109,7 @@ (update :chats #(apply dissoc % removed-chats)) (update :chats-home-list set/difference removed-chats)) :fx [(when (not-empty removed-chats) - [:clear-message-notifications - [removed-chats - (get-in db [:profile/profile :remote-push-notifications-enabled?])]]) + [:effects/push-notifications-clear-message-notifications removed-chats]) [:dispatch [:chat/leave-removed-chat]]]})) (re-frame/reg-event-fx :chat/ensure-chats ensure-chats) @@ -286,9 +284,9 @@ {:events [:chat.ui/remove-chat]} [{:keys [db now] :as cofx} chat-id] (rf/merge cofx - {:clear-message-notifications - [[chat-id] (get-in db [:profile/profile :remote-push-notifications-enabled?])] - :dispatch [:shell/close-switcher-card chat-id]} + {:effects/push-notifications-clear-message-notifications [chat-id] + :dispatch [:shell/close-switcher-card + chat-id]} (deactivate-chat chat-id) (offload-messages chat-id))) diff --git a/src/status_im2/contexts/onboarding/enable_notifications/view.cljs b/src/status_im2/contexts/onboarding/enable_notifications/view.cljs index b59324d775..ad960b281c 100644 --- a/src/status_im2/contexts/onboarding/enable_notifications/view.cljs +++ b/src/status_im2/contexts/onboarding/enable_notifications/view.cljs @@ -3,7 +3,6 @@ [react-native.core :as rn] [react-native.platform :as platform] [react-native.safe-area :as safe-area] - [status-im.notifications.core :as notifications] [status-im2.contexts.onboarding.enable-notifications.style :as style] [status-im2.contexts.shell.jump-to.utils :as shell.utils] [utils.i18n :as i18n] @@ -25,7 +24,7 @@ [quo/button {:on-press (fn [] (shell.utils/change-selected-stack-id :communities-stack true nil) - (rf/dispatch [::notifications/switch true platform/ios?]) + (rf/dispatch [:push-notifications/switch true platform/ios?]) (rf/dispatch [:navigate-to-within-stack [:welcome :enable-notifications]])) :type :primary diff --git a/src/status_im2/contexts/profile/login/events.cljs b/src/status_im2/contexts/profile/login/events.cljs index 86b3cfddb6..849db5819e 100644 --- a/src/status_im2/contexts/profile/login/events.cljs +++ b/src/status_im2/contexts/profile/login/events.cljs @@ -9,7 +9,6 @@ [status-im2.common.biometric.events :as biometric] [status-im2.contexts.profile.config :as profile.config] [taoensso.timbre :as log] - [status-im.notifications.core :as notifications] [status-im2.config :as config] [status-im.data-store.settings :as data-store.settings] [status-im.communities.core :as communities] @@ -25,7 +24,8 @@ [status-im.data-store.visibility-status-updates :as visibility-status-updates-store] [status-im.data-store.switcher-cards :as switcher-cards-store] [status-im.browser.core :as browser] - [status-im.group-chats.core :as group-chats])) + [status-im.group-chats.core :as group-chats] + [status-im2.contexts.push-notifications.events :as notifications])) (re-frame/reg-fx ::login @@ -77,7 +77,7 @@ :networks/current-network current-network :networks/networks (merge networks config/default-networks-by-id) :profile/profile (merge profile settings))} - (notifications/load-notification-preferences) + (notifications/load-preferences) (data-store.chats/fetch-chats-preview {:on-success #(do (re-frame/dispatch [:chats-list/load-success %]) @@ -98,12 +98,10 @@ {:events [:profile.login/get-chats-callback]} [{:keys [db] :as cofx}] (let [{:networks/keys [current-network networks]} db - notifications-enabled? (get-in db [:profile/profile :notifications-enabled?]) - current-network-config (get networks current-network) - network-id (str (get-in networks - [current-network :config :NetworkId])) - remote-push-notifications-enabled? - (get-in db [:profile/profile :remote-push-notifications-enabled?])] + {:keys [notifications-enabled?]} (:profile/profile db) + current-network-config (get networks current-network) + network-id (str (get-in networks + [current-network :config :NetworkId]))] (rf/merge cofx (cond-> {:wallet/initialize-transactions-management-enabled nil :wallet/initialize-wallet @@ -114,8 +112,8 @@ accounts tokens custom-tokens favourites]))] :check-eip1559-activation {:network-id network-id} :chat/open-last-chat (get-in db [:profile/profile :key-uid])} - (or notifications-enabled? remote-push-notifications-enabled?) - (assoc ::notifications/enable remote-push-notifications-enabled?)) + notifications-enabled? + (assoc :effects/push-notifications-enable nil)) (transport/start-messenger) (contacts/initialize-contacts) (browser/initialize-browser) diff --git a/src/status_im2/contexts/push_notifications/effects.cljs b/src/status_im2/contexts/push_notifications/effects.cljs new file mode 100644 index 0000000000..e0c026892b --- /dev/null +++ b/src/status_im2/contexts/push_notifications/effects.cljs @@ -0,0 +1,59 @@ +(ns status-im2.contexts.push-notifications.effects + (:require [react-native.push-notification-ios :as pn-ios] + [utils.re-frame :as rf] + [native-module.push-notifications :as native-module.pn] + [react-native.platform :as platform])) + +(def ios-listeners-added? (atom nil)) + +(defn enable-ios-notifications + [] + (when-not @ios-listeners-added? + (reset! ios-listeners-added? true) + (pn-ios/add-listener + "register" + (fn [token] + (rf/dispatch [:push-notifications/registered-for-push-notifications token]))) + (pn-ios/add-listener + "registrationError" + (fn [error] + (rf/dispatch [:push-notifications/switch-error true error])))) + (pn-ios/request-permissions)) + +(defn disable-ios-notifications + [] + (pn-ios/abandon-permissions) + (rf/dispatch [:push-notifications/unregistered-from-push-notifications])) + +(defn enable-android-notifications + [] + (native-module.pn/create-channel + {:channel-id "status-im-notifications" + :channel-name "Status push notifications"}) + (native-module.pn/enable-notifications)) + +(defn disable-android-notifications + [] + (native-module.pn/disable-notifications)) + +(rf/reg-fx + :effects/push-notifications-enable + (fn [] + (if platform/android? + (enable-android-notifications) + (enable-ios-notifications)))) + +(rf/reg-fx + :effects/push-notifications-disable + (fn [] + (if platform/android? + (disable-android-notifications) + (disable-ios-notifications)))) + +(rf/reg-fx + :effects/push-notifications-clear-message-notifications + (fn [chat-ids] + (if platform/android? + (doseq [chat-id chat-ids] + (native-module.pn/clear-message-notifications chat-id)) + (pn-ios/remove-all-delivered-notifications)))) diff --git a/src/status_im2/contexts/push_notifications/events.cljs b/src/status_im2/contexts/push_notifications/events.cljs new file mode 100644 index 0000000000..8564602f97 --- /dev/null +++ b/src/status_im2/contexts/push_notifications/events.cljs @@ -0,0 +1,60 @@ +(ns status-im2.contexts.push-notifications.events + (:require [react-native.push-notification-ios :as pn-ios] + [native-module.push-notifications :as native-module.pn] + [status-im2.config :as config] + [utils.re-frame :as rf] + [taoensso.timbre :as log] + [react-native.platform :as platform] + [react-native.async-storage :as async-storage] + [utils.transforms :as transforms] + [cljs-bean.core :as bean] + status-im2.contexts.push-notifications.effects)) + +(def server-type-default 1) +(def server-type-custom 2) + +(def apn-token-type 1) +(def firebase-token-type 2) + +(defn handle-notification-press + [{{deep-link :deepLink} :userInfo + interaction :userInteraction}] + (async-storage/set-item! (str :chat-id) nil) + (when (and deep-link (or platform/ios? (and platform/android? interaction))) + (rf/dispatch [:universal-links/handle-url deep-link]))) + +(defn listen-notifications + [] + (if platform/ios? + (pn-ios/add-listener "localNotification" + #(handle-notification-press {:userInfo (bean/bean (.getData ^js %))})) + (native-module.pn/add-listener "remoteNotificationReceived" + #(handle-notification-press (transforms/json->clj %))))) + +(rf/defn handle-enable-notifications-event + {:events [:push-notifications/registered-for-push-notifications]} + [_ token] + {:json-rpc/call [{:method "wakuext_registerForPushNotifications" + :params [token (if platform/ios? config/apn-topic) + (if platform/ios? apn-token-type firebase-token-type)] + :on-success #(log/info "[push-notifications] register-success" %) + :on-error #(log/info "[push-notifications] register-error" %)}]}) + +(rf/defn handle-disable-notifications-event + {:events [:push-notifications/unregistered-from-push-notifications]} + [_] + {:json-rpc/call [{:method "wakuext_unregisterFromPushNotifications" + :params [] + :on-success #(log/info "[push-notifications] unregister-success" %) + :on-error #(log/info "[push-notifications] unregister-error" %)}]}) + +(rf/defn handle-preferences-load + {:events [:push-notifications/preferences-loaded]} + [{:keys [db]} preferences] + {:db (assoc db :push-notifications/preferences preferences)}) + +(rf/defn load-preferences + [_] + {:json-rpc/call [{:method "localnotifications_notificationPreferences" + :params [] + :on-success #(rf/dispatch [:push-notifications/preferences-loaded %])}]}) diff --git a/src/status_im2/contexts/push_notifications/local/effects.cljs b/src/status_im2/contexts/push_notifications/local/effects.cljs new file mode 100644 index 0000000000..aa1b0dd60c --- /dev/null +++ b/src/status_im2/contexts/push_notifications/local/effects.cljs @@ -0,0 +1,18 @@ +(ns status-im2.contexts.push-notifications.local.effects + (:require [react-native.push-notification-ios :as pn-ios] + [cljs-bean.core :as bean] + [native-module.push-notifications :as native-module.pn] + [utils.re-frame :as rf])) + +(rf/reg-fx :effects/push-notifications-local-present-ios + (fn [{:keys [title message user-info body-type]}] + (when (not= body-type "message") + (pn-ios/present-local-notification title + message + (bean/->js (merge user-info + {:notificationType + "local-notification"})))))) + +(rf/reg-fx :effects/push-notifications-local-present-android + (fn [notification] + (native-module.pn/present-local-notification notification))) diff --git a/src/status_im2/contexts/push_notifications/local/events.cljs b/src/status_im2/contexts/push_notifications/local/events.cljs new file mode 100644 index 0000000000..5ed3fb3a61 --- /dev/null +++ b/src/status_im2/contexts/push_notifications/local/events.cljs @@ -0,0 +1,36 @@ +(ns status-im2.contexts.push-notifications.local.events + (:require [quo.platform :as platform] + [utils.re-frame :as rf] + [status-im.notifications.wallet :as notifications.wallet] + status-im2.contexts.push-notifications.local.effects)) + +(defn foreground-chat? + [{{:keys [current-chat-id view-id]} :db} chat-id] + (and (= current-chat-id chat-id) + (= view-id :chat))) + +(defn show-message-pn? + [{{:keys [app-state profile/profile]} :db :as cofx} + notification] + (let [chat-id (get-in notification [:body :chat :id]) + notification-author (get-in notification [:notificationAuthor :id])] + (and + (not= notification-author (:public-key profile)) + (or (= app-state "background") + (not (foreground-chat? cofx chat-id)))))) + +(defn create-notification + [cofx {:keys [bodyType] :as notification}] + (assoc + (case bodyType + "message" (when (show-message-pn? cofx notification) notification) + "transaction" (notifications.wallet/create-transfer-notification cofx notification) + nil) + :body-type + bodyType)) + +(rf/defn process + [cofx event] + (if platform/ios? + {:effects/push-notifications-local-present-ios (create-notification nil event)} + {:effects/push-notifications-local-present-android (create-notification cofx event)})) diff --git a/src/status_im2/core.cljs b/src/status_im2/core.cljs index f6188fc2bd..9c38b0d2ba 100644 --- a/src/status_im2/core.cljs +++ b/src/status_im2/core.cljs @@ -18,12 +18,12 @@ [status-im2.setup.interceptors :as interceptors] [react-native.async-storage :as async-storage] [native-module.core :as native-module] - [status-im.notifications.local :as notifications] [status-im.utils.universal-links.core :as utils.universal-links] status-im.events status-im2.events status-im2.navigation.core - status-im2.subs.root)) + status-im2.subs.root + [status-im2.contexts.push-notifications.events :as notifications])) ;;;; re-frame RN setup (set! interop/next-tick js/setTimeout) diff --git a/src/status_im2/subs/root.cljs b/src/status_im2/subs/root.cljs index dc0dcc8bde..0f7e2a44e1 100644 --- a/src/status_im2/subs/root.cljs +++ b/src/status_im2/subs/root.cljs @@ -236,7 +236,6 @@ (reg-root-key-sub :delete-profile/keep-keys-on-keycard? :delete-profile/keep-keys-on-keycard?) ;; push notifications -(reg-root-key-sub :push-notifications/servers :push-notifications/servers) (reg-root-key-sub :push-notifications/preferences :push-notifications/preferences) (reg-root-key-sub :buy-crypto/on-ramps :buy-crypto/on-ramps) diff --git a/src/status_im2/subs/wallet/transactions.cljs b/src/status_im2/subs/wallet/transactions.cljs index edceabf4f8..bda2d0d6ce 100644 --- a/src/status_im2/subs/wallet/transactions.cljs +++ b/src/status_im2/subs/wallet/transactions.cljs @@ -2,11 +2,11 @@ (:require [re-frame.core :as re-frame] [status-im.ethereum.transactions.core :as transactions] [utils.i18n :as i18n] - [status-im.notifications.core :as notifications] [utils.datetime :as datetime] [utils.money :as money] [status-im.wallet.db :as wallet.db] - [status-im.wallet.utils :as wallet.utils])) + [status-im.wallet.utils :as wallet.utils] + [status-im.notifications.wallet :as notifications.wallet])) (re-frame/reg-sub :wallet/accounts @@ -236,11 +236,11 @@ (* 100 (/ confirmations transactions/confirmations-count-threshold))))))) (re-frame/reg-sub - :notifications/wallet-transactions + :push-notifications/wallet-transactions :<- [:push-notifications/preferences] (fn [pref] - (first (filter #(notifications/preference= % - {:service "wallet" - :event "transaction" - :identifier "all"}) + (first (filter #(notifications.wallet/preference= % + {:service "wallet" + :event "transaction" + :identifier "all"}) pref)))) diff --git a/src/utils/re_frame.cljs b/src/utils/re_frame.cljs index bff7c1231d..5857473a06 100644 --- a/src/utils/re_frame.cljs +++ b/src/utils/re_frame.cljs @@ -78,3 +78,5 @@ (def sub (comp deref re-frame/subscribe)) (def dispatch re-frame/dispatch) + +(def reg-fx re-frame/reg-fx)