Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
This commit is contained in:
Andrey Shovkoplyas 2020-06-12 10:54:28 +02:00 committed by Andrea Maria Piana
parent f9df0f367f
commit 0675d0d8d7
No known key found for this signature in database
GPG Key ID: AA6CCA6DE0E06424
34 changed files with 550 additions and 83 deletions

1
.env
View File

@ -24,3 +24,4 @@ QR_READ_TEST_MENU=1
ENABLE_ROOT_ALERT=1
ENABLE_REFERRAL_INVITE=1
ENABLE_QUO_PREVIEW=1
APN_TOPIC=im.status.ethereum.pr

View File

@ -23,3 +23,4 @@ KEYCARD_TEST_MENU=1
QR_READ_TEST_MENU=1
ENABLE_ROOT_ALERT=0
ENABLE_REFERRAL_INVITE=1
APN_TOPIC=im.status.ethereum.pr

View File

@ -22,3 +22,4 @@ KEYCARD_TEST_MENU=0
ENABLE_ROOT_ALERT=1
ENABLE_REFERRAL_INVITE=1
DISABLE_WALLET_ON_MOBILE_NETWORK=1
APN_TOPIC=im.status.ethereum.pr

View File

@ -328,6 +328,8 @@ PODS:
- React
- RNCMaskedView (0.1.9):
- React
- RNCPushNotificationIOS (1.4.1):
- React
- RNDeviceInfo (5.6.1):
- React
- RNFS (2.16.6):
@ -363,7 +365,7 @@ PODS:
- SQLCipher/standard (3.4.2):
- SQLCipher/common
- SSZipArchive (2.2.3)
- TOCropViewController (2.5.3)
- TOCropViewController (2.5.4)
- TouchID (4.4.1):
- React
- Yoga (1.14.0)
@ -435,6 +437,7 @@ DEPENDENCIES:
- "RNCAsyncStorage (from `../node_modules/@react-native-community/async-storage`)"
- "RNCClipboard (from `../node_modules/@react-native-community/clipboard`)"
- "RNCMaskedView (from `../node_modules/@react-native-community/masked-view`)"
- "RNCPushNotificationIOS (from `../node_modules/@react-native-community/push-notification-ios`)"
- RNDeviceInfo (from `../node_modules/react-native-device-info`)
- RNFS (from `../node_modules/react-native-fs`)
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
@ -554,6 +557,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/@react-native-community/clipboard"
RNCMaskedView:
:path: "../node_modules/@react-native-community/masked-view"
RNCPushNotificationIOS:
:path: "../node_modules/@react-native-community/push-notification-ios"
RNDeviceInfo:
:path: "../node_modules/react-native-device-info"
RNFS:
@ -596,7 +601,7 @@ SPEC CHECKSUMS:
Flipper-RSocket: 64e7431a55835eb953b0bf984ef3b90ae9fdddd7
FlipperKit: afd4259ef9eadeeb2d30250b37d95cb3b6b97a69
Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51
glog: 682164e7ac67e41afd8f7b6a37a96d04caf61cc0
glog: 1f3da668190260b06b429bb211bfbee5cd790c28
OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355
Permission-Camera: afad27bf90337684d4a86f3825112d648c8c4d3b
Permission-Microphone: 0ffabc3fe1c75cfb260525ee3f529383c9f4368c
@ -635,6 +640,7 @@ SPEC CHECKSUMS:
RNCAsyncStorage: d059c3ee71738c39834a627476322a5a8cd5bf36
RNCClipboard: 8148e21ac347c51fd6cd4b683389094c216bb543
RNCMaskedView: 71fc32d971f03b7f03d6ab6b86b730c4ee64f5b6
RNCPushNotificationIOS: c145c6253ea016e5efeff604f2720736b4a596f7
RNDeviceInfo: b6e650fbd234732c759544218657d549b4339038
RNFS: 2bd9eb49dc82fa9676382f0585b992c424cd59df
RNGestureHandler: 8f09cd560f8d533eb36da5a6c5a843af9f056b38
@ -648,11 +654,11 @@ SPEC CHECKSUMS:
RNSVG: 8ba35cbeb385a52fd960fd28db9d7d18b4c2974f
SQLCipher: f9fcf29b2e59ced7defc2a2bdd0ebe79b40d4990
SSZipArchive: 62d4947b08730e4cda640473b0066d209ff033c9
TOCropViewController: 20a14b6a7a098308bf369e7c8d700dc983a974e6
TOCropViewController: 2a1ae1242600b1f2d996fd91a5268b2309a33b5c
TouchID: ba4c656d849cceabc2e4eef722dea5e55959ecf4
Yoga: 3ebccbdd559724312790e7742142d062476b698e
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
PODFILE CHECKSUM: 5faa578ff5cb7a30abc18b9d620df288750a72fe
COCOAPODS: 1.9.1
COCOAPODS: 1.9.3

View File

@ -9,8 +9,9 @@
#import <React/RCTBridgeDelegate.h>
#import <UIKit/UIKit.h>
#import <UserNotifications/UNUserNotificationCenter.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate>
@interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate, UNUserNotificationCenterDelegate>
@property (nonatomic, strong) UIWindow *window;

View File

@ -20,6 +20,9 @@
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <UserNotifications/UserNotifications.h>
#import <RNCPushNotificationIOS.h>
#if DEBUG
#import <FlipperKit/FlipperClient.h>
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
@ -88,6 +91,9 @@ static void InitializeFlipper(UIApplication *application) {
[self.window makeKeyAndVisible];
[RNSplashScreen show];
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
return YES;
}
@ -137,4 +143,33 @@ static void InitializeFlipper(UIApplication *application) {
}
}
// Required to register for notifications
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
[RNCPushNotificationIOS didRegisterUserNotificationSettings:notificationSettings];
}
// Required for the register event.
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
[RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
// Required for the registrationError event.
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
[RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error];
}
// IOS 10+ Required for localNotification event
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)(void))completionHandler
{
[RNCPushNotificationIOS didReceiveNotificationResponse:response];
completionHandler();
}
// IOS 4-10 Required for the localNotification event.
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
[RNCPushNotificationIOS didReceiveLocalNotification:notification];
}
@end

View File

@ -17,6 +17,7 @@
"@react-native-community/hooks": "^2.5.1",
"@react-native-community/masked-view": "^0.1.6",
"@react-native-community/netinfo": "^4.4.0",
"@react-native-community/push-notification-ios": "^1.4.1",
"@react-native-community/slider": "^3.0.0",
"@react-navigation/bottom-tabs": "^5.7.0",
"@react-navigation/native": "^5.7.0",

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 B

View File

@ -190,6 +190,7 @@
#js {:localNotification identity
:requestPermission identity})
(def push-notification-ios #js {})
;; Update i18n_resources.cljs
(defn mock [module]
(case module
@ -219,6 +220,7 @@
"react-native-haptic-feedback" react-native-haptic-feedback
"react-native-device-info" react-native-device-info
"react-native-push-notification" react-native-push-notification
"@react-native-community/push-notification-ios" push-notification-ios
"./fleets.js" default-fleets
"./chats.js" default-chats
"../translations/ar.json" (js/JSON.parse (slurp "./translations/ar.json"))

View File

@ -1,5 +1,6 @@
(ns status-im.chat.models
(:require [re-frame.core :as re-frame]
[taoensso.timbre :as log]
[status-im.multiaccounts.model :as multiaccounts.model]
[status-im.transport.filters.core :as transport.filters]
[status-im.contact.core :as contact.core]
@ -136,15 +137,15 @@
(fx/defn upsert-chat
"Upsert chat when not deleted"
[{:keys [db] :as cofx} {:keys [chat-id] :as chat-props}]
[{:keys [db] :as cofx} {:keys [chat-id] :as chat-props} on-success]
(fx/merge cofx
(ensure-chat chat-props)
#(chats-store/save-chat % (get-in % [:db :chats chat-id]))))
#(chats-store/save-chat % (get-in % [:db :chats chat-id]) on-success)))
(fx/defn handle-save-chat
{:events [::save-chat]}
[{:keys [db] :as cofx} chat-id]
(chats-store/save-chat cofx (get-in db [:chats chat-id])))
[{:keys [db] :as cofx} chat-id on-success]
(chats-store/save-chat cofx (get-in db [:chats chat-id]) on-success))
(fx/defn handle-mark-all-read-successful
{:events [::mark-all-read-successful]}
@ -172,7 +173,8 @@
:public? true
:might-have-join-time-messages? true
:unviewed-messages-count 0
:loaded-unviewed-messages-ids #{}}))
:loaded-unviewed-messages-ids #{}}
nil))
(fx/defn clear-history
"Clears history of the particular chat"
@ -192,7 +194,7 @@
:unviewed-messages-count 0
:deleted-at-clock-value last-message-clock-value}))}
(messages-store/delete-messages-by-chat-id chat-id)
#(chats-store/save-chat % (get-in % [:db :chats chat-id])))))
#(chats-store/save-chat % (get-in % [:db :chats chat-id]) nil))))
(fx/defn deactivate-chat
"Deactivate chat in db, no side effects"
@ -253,7 +255,8 @@
(when (not= (multiaccounts.model/current-public-key cofx) chat-id)
(fx/merge cofx
(upsert-chat {:chat-id chat-id
:is-active true})
:is-active true}
nil)
(transport.filters/load-chat chat-id)
(navigate-to-chat chat-id))))
@ -293,6 +296,29 @@
{:db (assoc db :contacts/identity identity)}
(navigation/navigate-to-cofx :profile nil)))))
(fx/defn mute-chat-failed
{:events [::mute-chat-failed]}
[{:keys [db] :as cofx} chat-id muted? error]
(log/error "mute chat failed" chat-id error)
{:db (assoc-in db [:chats chat-id :muted] (not muted?))})
(fx/defn mute-chat
{:events [::mute-chat-toggled]}
[{:keys [db] :as cofx} chat-id muted?]
(let [method (if muted? "muteChat" "unmuteChat")
chat (get-in db [:chats chat-id])]
;; chat does not exist, create and then mute
(if-not chat
(upsert-chat cofx
{:is-active true
:chat-id chat-id}
#(re-frame/dispatch [::mute-chat-toggled chat-id muted?]))
{:db (assoc-in db [:chats chat-id :muted] muted?)
::json-rpc/call [{:method (json-rpc/call-ext-method (waku/enabled? cofx) method)
:params [chat-id]
:on-error #(re-frame/dispatch [::mute-chat-failed chat-id muted? %])
:on-success #(log/info method "successful" chat-id)}]})))
(fx/defn show-profile
{:events [:chat.ui/show-profile]}
[cofx identity]

View File

@ -15,7 +15,7 @@
cofx {:now "now"
:db {:contacts/contacts {chat-id
{:name contact-name}}}}
response (chat/upsert-chat cofx chat-props)
response (chat/upsert-chat cofx chat-props nil)
actual-chat (get-in response [:db :chats chat-id])]
(testing "it adds the chat to the chats collection"
(is actual-chat))
@ -36,7 +36,7 @@
:extra-prop "some"}
cofx {:db {:chats {chat-id {:is-active true
:name "old-name"}}}}
response (chat/upsert-chat cofx chat-props)
response (chat/upsert-chat cofx chat-props nil)
actual-chat (get-in response [:db :chats chat-id])]
(testing "it adds the chat to the chats collection"
(is actual-chat))

View File

@ -94,10 +94,12 @@
(update :last-message #(when % (messages/<-rpc %)))
(dissoc :chatType :members)))
(fx/defn save-chat [cofx {:keys [chat-id] :as chat}]
(fx/defn save-chat [cofx {:keys [chat-id] :as chat} on-success]
{::json-rpc/call [{:method (json-rpc/call-ext-method (waku/enabled? cofx) "saveChat")
:params [(->rpc chat)]
:on-success #(log/debug "saved chat" chat-id "successfuly")
:on-success #(do
(log/debug "saved chat" chat-id "successfuly")
(when on-success (on-success)))
:on-failure #(log/error "failed to save chat" chat-id %)}]})
(fx/defn fetch-chats-rpc [cofx {:keys [on-success]}]

View File

@ -71,6 +71,8 @@
"shhext_updateMessageOutgoingStatus" {}
"shhext_chatMessages" {}
"shhext_saveChat" {}
"shhext_muteChat" {}
"shhext_unmuteChat" {}
"shhext_contacts" {}
"shhext_prepareContent" {}
"shhext_blockContact" {}
@ -93,6 +95,18 @@
"shhext_sendGroupChatInvitationRequest" {}
"shhext_sendGroupChatInvitationRejection" {}
"shhext_getGroupChatInvitations" {}
"shhext_registerForPushNotifications" {}
"shhext_unregisterFromPushNotifications" {}
"shhext_enablePushNotificationsFromContactsOnly" {}
"shhext_disablePushNotificationsFromContactsOnly" {}
"shhext_startPushNotificationsServer" {}
"shhext_stopPushNotificationsServer" {}
"shhext_disableSendingNotifications" {}
"shhext_enableSendingNotifications" {}
"shhext_addPushNotificationsServer" {}
"shhext_getPushNotificationsServers" {}
"shhext_enablePushNotificationsBlockMentions" {}
"shhext_disablePushNotificationsBlockMentions" {}
"wakuext_post" {}
"wakuext_startMessenger" {}
"wakuext_sendPairInstallation" {}
@ -130,6 +144,8 @@
"wakuext_updateMessageOutgoingStatus" {}
"wakuext_chatMessages" {}
"wakuext_saveChat" {}
"wakuext_muteChat" {}
"wakuext_unmuteChat" {}
"wakuext_contacts" {}
"wakuext_prepareContent" {}
"wakuext_blockContact" {}
@ -152,6 +168,18 @@
"wakuext_sendGroupChatInvitationRequest" {}
"wakuext_sendGroupChatInvitationRejection" {}
"wakuext_getGroupChatInvitations" {}
"wakuext_registerForPushNotifications" {}
"wakuext_unregisterFromPushNotifications" {}
"wakuext_enablePushNotificationsFromContactsOnly" {}
"wakuext_disablePushNotificationsFromContactsOnly" {}
"wakuext_startPushNotificationsServer" {}
"wakuext_stopPushNotificationsServer" {}
"wakuext_disableSendingNotifications" {}
"wakuext_enableSendingNotifications" {}
"wakuext_addPushNotificationsServer" {}
"wakuext_getPushNotificationsServers" {}
"wakuext_enablePushNotificationsBlockMentions" {}
"wakuext_disablePushNotificationsBlockMentions" {}
"status_chats" {}
"wallet_getTransfers" {}
"wallet_getTokensBalances" {}
@ -210,16 +238,20 @@
(str "shhext_" method)))
(defn call
[{:keys [method params on-success] :as arg}]
[{:keys [method params on-success on-error] :as arg}]
(if-let [method-options (json-rpc-api method)]
(let [params (or params [])
{:keys [id on-result subscription?]
:or {on-result identity
id 1}} method-options
on-error (or (on-error-retry call arg)
#(log/warn :json-rpc/error method :error % :params params))]
on-error (or
on-error
(on-error-retry call arg)
#(log/warn :json-rpc/error method :error % :params params))]
(if (nil? method)
(log/error :json-rpc/method-not-found method)
(do
(log/error :json-rpc/method-not-found method)
(on-error :json-rpc/method-not-found))
(status/call-private-rpc
(types/clj->json {:jsonrpc "2.0"
:id id

View File

@ -117,7 +117,8 @@
(fx/merge cofx
(models.chat/deactivate-chat chat-id)
(models.chat/upsert-chat {:chat-id chat-id
:is-active false})
:is-active false}
nil)
(navigation/navigate-to-cofx :home {})))
(defn- valid-name? [name]

View File

@ -3,7 +3,6 @@
[status-im.ethereum.stateofus :as stateofus]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im.native-module.core :as native-module]
[status-im.notifications.core :as notifications]
[status-im.utils.fx :as fx]
[status-im.utils.gfycat.core :as gfycat]
[status-im.utils.identicon :as identicon]
@ -87,17 +86,6 @@
:dev-mode? dev-mode?
{}))
(fx/defn switch-notifications
{:events [:multiaccounts.ui/notifications-switched]}
[cofx notifications-enabled?]
(fx/merge cofx
{(if notifications-enabled?
::notifications/enable
::notifications/disable) nil}
(multiaccounts.update/multiaccount-update
:notifications-enabled? (boolean notifications-enabled?)
{})))
(fx/defn switch-chaos-mode
[{:keys [db] :as cofx} chaos-mode?]
(when (:multiaccount db)

View File

@ -138,8 +138,7 @@
[{:keys [db] :as cofx}]
(fx/merge cofx
{:db (dissoc db :intro-wizard)}
(navigation/navigate-to-cofx (if platform/android?
:notifications-settings :welcome) nil)))
(navigation/navigate-to-cofx :notifications-onboarding nil)))
(fx/defn init-key-generation
[{:keys [db] :as cofx}]
@ -252,6 +251,7 @@
:dapps-address (:address wallet-account)
:latest-derived-path 0
:signing-phrase signing-phrase
:send-push-notifications? true
:installation-id (random-guid-generator)}
constants/default-multiaccount)
;; The address from which we derive any chat

View File

@ -22,7 +22,6 @@
[status-im.utils.identicon :as identicon]
[status-im.utils.keychain.core :as keychain]
[status-im.utils.logging.core :as logging]
[status-im.utils.platform :as platform]
[status-im.utils.security :as security]
[status-im.utils.types :as types]
[status-im.utils.utils :as utils]
@ -88,8 +87,7 @@
{:db (update db :keycard dissoc :flow)}
(if (= :import flow)
(navigation/navigate-to-cofx :intro-stack {:screen :keycard-recovery-success})
(navigation/navigate-to-cofx (if platform/android?
:notifications-settings :welcome) nil))))))
(navigation/navigate-to-cofx :notifications-onboarding nil))))))
(fx/defn initialize-dapp-permissions
{:events [::initialize-dapp-permissions]}
@ -192,8 +190,7 @@
(fn [accounts custom-tokens]
(re-frame/dispatch [::initialize-wallet
accounts custom-tokens]))}
(and platform/android?
notifications-enabled?)
notifications-enabled?
(assoc ::notifications/enable nil))
(acquisition/login)
(initialize-appearance)

View File

@ -6,7 +6,8 @@
[status-im.native-module.core :as status]
[status-im.transport.core :as transport]
[status-im.utils.fx :as fx]
[status-im.utils.keychain.core :as keychain]))
[status-im.utils.keychain.core :as keychain]
[status-im.notifications.core :as notifications]))
(fx/defn logout-method
[{:keys [db] :as cofx} {:keys [auth-method logout?]}]
@ -15,6 +16,7 @@
{::logout nil
:keychain/clear-user-password key-uid
::init/open-multiaccounts #(re-frame/dispatch [::init/initialize-multiaccounts % {:logout? logout?}])}
(notifications/logout-disable)
(keychain/save-auth-method key-uid auth-method)
(transport/stop-whisper)
(chaos-mode/stop-checking)

View File

@ -39,3 +39,10 @@
(multiaccount-update cofx
:mnemonic nil
{}))
(fx/defn optimistic
[{:keys [db] :as cofx} setting setting-value]
(let [current-multiaccount (:multiaccount db)]
{:db (if setting-value
(assoc-in db [:multiaccount setting] setting-value)
(update db :multiaccount dissoc setting))}))

View File

@ -2,7 +2,48 @@
(:require [re-frame.core :as re-frame]
[taoensso.timbre :as log]
[status-im.utils.fx :as fx]
[status-im.native-module.core :as status]))
[status-im.multiaccounts.update.core :as multiaccounts.update]
["@react-native-community/push-notification-ios" :default pn-ios]
[status-im.native-module.core :as status]
[quo.platform :as platform]
[status-im.utils.config :as config]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.waku.core :as waku]))
(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 [::registered-for-push-notifications token])))
(.addEventListener
^js pn-ios
"registrationError"
(fn [error]
(re-frame/dispatch [::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 [::unregistered-from-push-notifications]))
;; FIXME: Repalce with request permission from audio messages PR lib
(re-frame/reg-fx
@ -23,9 +64,164 @@
(re-frame/reg-fx
::enable
(fn [_]
(status/enable-notifications)))
(if platform/android?
(status/enable-notifications)
(enable-ios-notifications))))
(re-frame/reg-fx
::disable
(fn [_]
(status/disable-notifications)))
(if platform/android?
(status/disable-notifications)
(disable-ios-notifications))))
(re-frame/reg-fx
::logout-disable
(fn [_]
(if platform/android?
(status/disable-notifications)
(.abandonPermissions ^js pn-ios))))
(fx/defn handle-enable-notifications-event
{:events [::registered-for-push-notifications]}
[cofx token]
{::json-rpc/call [{:method (json-rpc/call-ext-method (waku/enabled? cofx) "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 [::switch-error true %])}]})
(fx/defn handle-disable-notifications-event
{:events [::unregistered-from-push-notifications]}
[cofx]
{::json-rpc/call [{:method (json-rpc/call-ext-method (waku/enabled? cofx) "unregisterFromPushNotifications")
:params []
:on-success #(log/info "[push-notifications] unregister-success" %)
:on-error #(re-frame/dispatch [::switch-error false %])}]})
(fx/defn logout-disable
[cofx]
(merge {::logout-disable nil}
(when platform/ios?
{::json-rpc/call [{:method (json-rpc/call-ext-method (waku/enabled? cofx) "unregisterFromPushNotifications")
:params []
:on-success #(log/info "[push-notifications] unregister-success" %)
:on-error #(log/info "[push-notifications] unregister-error" %)}]})))
(fx/defn notification-switch-error
{:events [::switch-error]}
[cofx enabled?]
(if platform/android?
(multiaccounts.update/multiaccount-update
:notifications-enabled? (not enabled?)
{})
(multiaccounts.update/optimistic cofx :remote-push-notifications-enabled? (not (boolean enabled?)))))
(fx/defn notification-switch
{:events [::switch]}
[{:keys [db] :as cofx} enabled?]
(fx/merge cofx
(if enabled?
{::enable nil}
{::disable nil})
(if platform/android?
(multiaccounts.update/multiaccount-update
:notifications-enabled? enabled?
{})
(multiaccounts.update/optimistic :remote-push-notifications-enabled? (boolean enabled?)))))
(fx/defn notification-non-contacts-error
{:events [::non-contacts-update-error]}
[cofx enabled?]
(multiaccounts.update/optimistic cofx :push-notifications-from-contacts-only? (not (boolean enabled?))))
(fx/defn notification-block-mentions-error
{:events [::block-mentions-update-error]}
[cofx enabled?]
(multiaccounts.update/optimistic cofx :push-notifications-block-mentions? (not (boolean enabled?))))
(fx/defn notification-non-contacts
{:events [::switch-non-contacts]}
[{:keys [db] :as cofx} enabled?]
(let [method (if enabled?
"enablePushNotificationsFromContactsOnly"
"disablePushNotificationsFromContactsOnly")]
(fx/merge cofx
{::json-rpc/call [{:method (json-rpc/call-ext-method (waku/enabled? cofx) 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?)))))
(fx/defn notification-block-mentions
{:events [::switch-block-mentions]}
[{:keys [db] :as cofx} enabled?]
(let [method (if enabled?
"enablePushNotificationsBlockMentions"
"disablePushNotificationsBlockMentions")]
(log/info "USING METHOD" method enabled?)
(fx/merge cofx
{::json-rpc/call [{:method (json-rpc/call-ext-method (waku/enabled? cofx) 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?)))))
(fx/defn switch-push-notifications-server-enabled
{:events [::switch-push-notifications-server-enabled]}
[{:keys [db] :as cofx} enabled?]
(let [method (if enabled?
"startPushNotificationsServer"
"stopPushNotificationsServer")]
(fx/merge cofx
{::json-rpc/call [{:method (json-rpc/call-ext-method (waku/enabled? cofx) 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?)))))
(fx/defn switch-send-notifications
{:events [::switch-send-push-notifications]}
[{:keys [db] :as cofx} enabled?]
(let [method (if enabled?
"enableSendingNotifications"
"disableSendingNotifications")]
(fx/merge cofx
{::json-rpc/call [{:method (json-rpc/call-ext-method (waku/enabled? cofx) 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?)))))
(fx/defn handle-add-server-error
{:events [::push-notifications-add-server-error]}
[_ public-key error]
(log/error "failed to add server", public-key, error))
(fx/defn add-server
{:events [::add-server]}
[{:keys [db] :as cofx} public-key]
(fx/merge cofx
{::json-rpc/call [{:method (json-rpc/call-ext-method (waku/enabled? cofx) "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 %])}]}))
(fx/defn handle-servers-fetched
{:events [::servers-fetched]}
[{:keys [db]} servers]
{:db (assoc db :push-notifications/servers (map server<-rpc servers))})
(fx/defn fetch-push-notifications-servers
{:events [::fetch-servers]}
[cofx]
{::json-rpc/call [{:method (json-rpc/call-ext-method (waku/enabled? cofx) "getPushNotificationsServers")
:params []
:on-success #(do
(log/info "[push-notifications] servers fetched" %)
(re-frame/dispatch [::servers-fetched %]))}]})

View File

@ -197,6 +197,9 @@
;; delete profile
(reg-root-key-sub :delete-profile/error :delete-profile/error)
;; push notifications
(reg-root-key-sub :push-notifications/servers :push-notifications/servers)
;;GENERAL ==============================================================================================================
(re-frame/reg-sub

View File

@ -124,7 +124,7 @@
:accessibility-label :unviewed-messages-public}]
[badge/message-counter unviewed-messages-count])]))
(defn icon-style []
(def icon-style
{:color colors/black
:width 15
:height 15
@ -134,7 +134,7 @@
(defn home-list-item [home-item]
(let [{:keys [chat-id chat-name color online group-chat
public? timestamp last-message]}
public? timestamp last-message muted]}
home-item
private-group? (and group-chat (not public?))
public-group? (and group-chat public?)]
@ -148,13 +148,16 @@
:padding-right 16
:align-items :center}
(cond
muted
[icons/icon :main-icons/tiny-muted (assoc icon-style :color colors/gray)]
private-group?
[icons/icon :main-icons/tiny-group (icon-style)]
[icons/icon :main-icons/tiny-group icon-style]
public-group?
[icons/icon :main-icons/tiny-public (icon-style)]
[icons/icon :main-icons/tiny-public icon-style]
:else
[icons/icon :main-icons/tiny-new-contact (icon-style)])
[icons/icon :main-icons/tiny-new-contact icon-style])
[quo/text {:weight :medium
:color (when muted :secondary)
:accessibility-label :chat-name-text
:ellipsize-mode :tail
:number-of-lines 1}

View File

@ -1,12 +1,84 @@
(ns status-im.ui.screens.notifications-settings.views
(:require [status-im.ui.components.colors :as colors]
[status-im.ui.components.react :as react]
[status-im.react-native.resources :as resources]
(:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [re-frame.core :as re-frame]
[reagent.core :as reagent]
[status-im.i18n :as i18n]
[quo.core :as quo]
[re-frame.core :as re-frame]
[status-im.i18n :as i18n]))
[quo.design-system.colors :as quo-colors]
[status-im.notifications.core :as notifications]
[status-im.ui.components.colors :as colors]
[status-im.react-native.resources :as resources]
[status-im.ui.components.react :as react]
[status-im.ui.components.topbar :as topbar]))
(defonce server (reagent/atom ""))
(defn notifications-settings []
(let [{:keys [remote-push-notifications-enabled?
send-push-notifications?
push-notifications-block-mentions?
push-notifications-server-enabled?
push-notifications-from-contacts-only?]}
@(re-frame/subscribe [:multiaccount])]
[react/view {:flex 1}
[topbar/topbar {:title :t/notification-settings}]
[react/scroll-view {:style {:flex 1}
:content-container-style {:padding-vertical 8}}
[quo/list-item
{:size :small
:title (i18n/label :t/notifications)
:accessibility-label :notifications-button
:active remote-push-notifications-enabled?
:on-press #(re-frame/dispatch [::notifications/switch (not remote-push-notifications-enabled?)])
:accessory :switch}]
[react/view {:height 1
:background-color (:ui-02 @quo-colors/theme)
:margin-vertical 8}]
[quo/list-header (i18n/label :t/notifications-preferences)]
[quo/list-item
{:size :small
:title (i18n/label :t/notifications-non-contacts)
:accessibility-label :notifications-button
:active (and remote-push-notifications-enabled?
(not push-notifications-from-contacts-only?))
:on-press #(re-frame/dispatch
[::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?
(not push-notifications-block-mentions?))
:on-press #(re-frame/dispatch
[::notifications/switch-block-mentions (not push-notifications-block-mentions?)])
:accessory :switch}]
[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-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 notifications-onboarding []
[react/view {:flex 1 :background-color colors/white
:align-items :center :padding-bottom 16}
[react/text {:style {:margin-top 72 :margin-bottom 16
@ -19,7 +91,7 @@
:style {:width 118
:height 118}}]]
[quo/button {:on-press #(do (re-frame/dispatch
[:multiaccounts.ui/notifications-switched true])
[::notifications/switch true])
(re-frame/dispatch [:navigate-to :welcome]))
:accessibility-label :enable-notifications}
(i18n/label :t/intro-wizard-title6)]
@ -27,3 +99,40 @@
:accessibility-label :maybe-later
:on-press #(re-frame/dispatch [:navigate-to :welcome])}
(i18n/label :t/maybe-later)]])
(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/view {:flex 1}
[topbar/topbar {:title :t/notification-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)]]]]))

View File

@ -2,6 +2,7 @@
(:require [quo.core :as quo]
[re-frame.core :as re-frame]
[status-im.i18n :as i18n]
[status-im.chat.models :as chat.models]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.ui.components.chat-icon.screen :as chat-icon]
[status-im.ui.components.icons.vector-icons :as icons]
@ -14,6 +15,7 @@
[status-im.ui.components.colors :as colors]
[status-im.ui.components.toolbar :as toolbar]
[status-im.ui.components.keyboard-avoid-presentation :as kb-presentation]
[status-im.utils.platform :as platform]
[reagent.core :as reagent]
[clojure.string :as string])
(:require-macros [status-im.utils.views :as views]))
@ -76,15 +78,22 @@
(i18n/label :t/profile-details)]]
[render-detail contact]]))
(defn render-chat-settings [{:keys [names]}]
[quo/list-item
{:title (i18n/label :t/nickname)
:size :small
:accessibility-label :profile-nickname-item
:accessory :text
:accessory-text (or (:nickname names) (i18n/label :t/none))
:on-press #(re-frame/dispatch [:navigate-to :nickname])
:chevron true}])
(defn render-chat-settings [{:keys [public-key names]}]
(let [muted? (:muted @(re-frame/subscribe [:chats/chat public-key]))]
[quo/list-item
{:title (i18n/label :t/nickname)
:size :small
:accessibility-label :profile-nickname-item
:accessory :text
:accessory-text (or (:nickname names) (i18n/label :t/none))
:on-press #(re-frame/dispatch [:navigate-to :nickname])
:chevron true}]
[quo/list-item
{:title (i18n/label :mute-chat)
:active muted?
:accessibility-label :mute-chat
:on-press #(re-frame/dispatch [::chat.models/mute-chat-toggled public-key (not muted?)])
:accessory :switch}]))
(defn chat-settings [contact]
[react/view
@ -195,5 +204,8 @@
:on-press action}]))]
[react/view styles/contact-profile-details-container
[profile-details contact]
[chat-settings contact]]
;; Mute chat is only supported on ios for now
(when platform/ios?
[react/view {}
[chat-settings contact]])]
[block-contact-action contact]]]))))

View File

@ -3,6 +3,7 @@
[reagent.core :as reagent]
[status-im.i18n :as i18n]
[quo.core :as quo]
[status-im.notifications.core :as notifications]
[status-im.ui.components.colors :as colors]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.ui.components.common.common :as components.common]
@ -65,8 +66,8 @@
(defn content []
(let [{:keys [preferred-name
mnemonic
keycard-pairing
notifications-enabled?]}
notifications-enabled?
keycard-pairing]}
@(re-frame/subscribe [:multiaccount])
active-contacts-count @(re-frame/subscribe [:contacts/active-count])
tribute-to-talk @(re-frame/subscribe [:tribute-to-talk/profile])
@ -126,16 +127,23 @@
:accessibility-label :appearance-settings-button
:chevron true
:on-press #(re-frame/dispatch [:navigate-to :appearance])}]
(when (and platform/android?
config/local-notifications?)
(if platform/ios?
[quo/list-item
{:icon :main-icons/notification
:title (i18n/label :t/notifications)
:accessibility-label :notifications-button
:active notifications-enabled?
:on-press #(re-frame/dispatch
[:multiaccounts.ui/notifications-switched (not notifications-enabled?)])
:accessory :switch}])
:accessibility-label :notifications-settings-button
:chevron true
:on-press #(re-frame/dispatch [:navigate-to :notifications])}]
(when (and platform/android?
config/local-notifications?)
[quo/list-item
{:icon :main-icons/notification
:title (i18n/label :t/notifications)
:accessibility-label :notifications-settings-button
:active notifications-enabled?
:on-press #(re-frame/dispatch
[::notifications/switch (not notifications-enabled?)])
:accessory :switch}]))
[quo/list-item
{:icon :main-icons/mobile
:title (i18n/label :t/sync-settings)

View File

@ -23,8 +23,8 @@
[quo.previews.main :as quo.preview]
[status-im.utils.config :as config]
[status-im.ui.screens.chat.image.preview.views :as image-preview]
[status-im.ui.screens.notifications-settings.views :as notifications-settings]
[status-im.ui.screens.profile.contact.views :as contact]))
[status-im.ui.screens.profile.contact.views :as contact]
[status-im.ui.screens.notifications-settings.views :as notifications-settings]))
(defonce main-stack (navigation/create-stack))
(defonce bottom-tabs (navigation/create-bottom-tabs))
@ -114,7 +114,12 @@
{:name :notifications-settings
:back-handler :noop
:insets {:bottom true}
:component notifications-settings/notifications-settings}]
:component notifications-settings/notifications-settings}
{:name :notifications-onboarding
:back-handler :noop
:insets {:bottom true}
:component notifications-settings/notifications-onboarding}]
(when config/quo-preview-enabled?
[{:name :quo-preview
:insets {:top false :bottom false}

View File

@ -37,6 +37,7 @@
[status-im.ui.components.tabbar.styles :as tabbar.styles]
[status-im.ui.screens.routing.core :as navigation]
[status-im.ui.screens.appearance.views :as appearance]
[status-im.ui.screens.notifications-settings.views :as notifications-settings]
[status-im.ui.screens.privacy-and-security-settings.delete-profile :as delete-profile]))
(defonce stack (navigation/create-stack))
@ -83,6 +84,10 @@
:component privacy-and-security/privacy-and-security}
{:name :appearance
:component appearance/appearance}
{:name :notifications
:component notifications-settings/notifications-settings}
{:name :notifications-servers
:component notifications-settings/notifications-servers}
{:name :sync-settings
:component sync-settings/sync-settings}
{:name :advanced-settings

View File

@ -46,6 +46,7 @@
(def log-level
(string/upper-case (get-config :LOG_LEVEL "")))
(def fleet (get-config :FLEET "eth.staging"))
(def apn-topic (get-config :APN_TOPIC "im.status.ethereum"))
(def default-network (get-config :DEFAULT_NETWORK))
(def pow-target (js/parseFloat (get-config :POW_TARGET "0.0001")))
(def pow-time (js/parseInt (get-config :POW_TIME "1")))

View File

@ -2,7 +2,7 @@
"_comment": "DO NOT EDIT THIS FILE BY HAND. USE 'scripts/update-status-go.sh <tag>' instead",
"owner": "status-im",
"repo": "status-go",
"version": "v0.60.2",
"commit-sha1": "57728224d45ce3086e135988ae02e247abbc7b60",
"src-sha256": "1smgazlkgjxqq27ncgxagdi3523vcnmrca7lgj0lbxb4kbqgmmbl"
"version": "v0.61.1",
"commit-sha1": "61b345ff3395e4d031da1c4b497cc431a4ab2177",
"src-sha256": "1dg9w9fdi5isdc72ydxqgin6bg8b7jqkavjs2x8bvl9lhf2mqm3c"
}

View File

@ -461,7 +461,7 @@ class AboutButton(BaseButton):
class PrifileNotificationsButton(BaseButton):
def __init__(self, driver):
super().__init__(driver)
self.locator = self.Locator.accessibility_id("notifications-button")
self.locator = self.Locator.accessibility_id("notifications-settings-button")
class RemovePictureButton(BaseButton):

View File

@ -790,6 +790,18 @@
"not-keycard-text": "The card you used is not a Keycard. You need to purchase a Keycard to use it",
"not-keycard-title": "Not a Keycard",
"notifications": "Notifications",
"notifications-settings": "Notifications",
"notification-settings": "Notification settings",
"notifications-servers": "Notification servers",
"notifications-preferences": "Notification preferences",
"notifications-switch": "Show notifications",
"notifications-non-contacts": "Notifications from non-contacts",
"send-push-notifications": "Send push notifications",
"push-notifications-server-enabled": "Server enabled",
"push-notifications-servers": "Push notification servers",
"allow-mention-notifications": "Show @ mentions",
"server": "Server",
"specify-server-public-key": "Enter server public key",
"notify": "Notify",
"off": "Off",
"offline": "Offline",
@ -960,6 +972,7 @@
"sharing-share": "Share",
"show-less": "Show less",
"show-more": "Show more",
"show-notifications": "Show notifications",
"show-qr": "Show QR code",
"show-transaction-data": "Show transaction data",
"sign-and-send": "Sign and send",
@ -1220,6 +1233,8 @@
"private-notifications-descr": "Status will notify you about new messages. You can edit your notification preferences later in settings.",
"maybe-later": "Maybe later",
"join": "Join",
"registered": "registered",
"not-registered": "not registered",
"audio-recorder-error": "Recorder error",
"audio-recorder": "Recorder",
"audio-recorder-max-ms-reached": "Maximum recording time reached",

View File

@ -1344,6 +1344,13 @@
resolved "https://registry.yarnpkg.com/@react-native-community/netinfo/-/netinfo-4.7.0.tgz#7482d36836cac69d0a0ae25581f65bc472639930"
integrity sha512-a/sDB+AsLEUNmhAUlAaTYeXKyQdFGBUfatqKkX5jluBo2CB3OAuTHfm7rSjcaLB9EmG5iSq3fOTpync2E7EYTA==
"@react-native-community/push-notification-ios@^1.4.1":
version "1.4.1"
resolved "https://registry.yarnpkg.com/@react-native-community/push-notification-ios/-/push-notification-ios-1.4.1.tgz#02b46fb793926f34aa275605ed49f03015e893b3"
integrity sha512-Y+4LS10R+yc17wu54tlDcxgW/SugEAz2dNjmil9I7KUtaZIOc0hTvAE8dUvYTEDvYQ9uYrXI+OqdElTE3FJ3FA==
dependencies:
invariant "^2.2.4"
"@react-native-community/slider@^3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@react-native-community/slider/-/slider-3.0.0.tgz#ffbf78689fc0572fb5c1e2ccb61b2ef074d3dcd2"