[#11117] Move PNs to status-go
This commit is contained in:
parent
9a51a46869
commit
3685f6a500
|
@ -70,7 +70,7 @@
|
|||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity"/>
|
||||
<service android:name="im.status.ethereum.module.ForegroundService"></service>
|
||||
<service android:name="im.status.ethereum.pushnotifications.ForegroundService"></service>
|
||||
<service android:name="im.status.ethereum.module.LocalNotificationsService" />
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
|
|
|
@ -80,7 +80,6 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
|
|||
private static StatusModule module;
|
||||
private ReactApplicationContext reactContext;
|
||||
private boolean rootedDevice;
|
||||
private NewMessageSignalHandler newMessageSignalHandler;
|
||||
private boolean background;
|
||||
|
||||
StatusModule(ReactApplicationContext reactContext, boolean rootedDevice) {
|
||||
|
@ -112,19 +111,6 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
|
|||
Log.d(TAG, "******************* ON HOST DESTROY *************************");
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void enableNotifications() {
|
||||
this.newMessageSignalHandler = new NewMessageSignalHandler(reactContext);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void disableNotifications() {
|
||||
if (newMessageSignalHandler != null) {
|
||||
newMessageSignalHandler.stop();
|
||||
newMessageSignalHandler = null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkAvailability() {
|
||||
// We wait at least 10s for getCurrentActivity to return a value,
|
||||
// otherwise we give up
|
||||
|
@ -153,35 +139,10 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
|
|||
}
|
||||
|
||||
public void handleSignal(final String jsonEventString) {
|
||||
try {
|
||||
final JSONObject jsonEvent = new JSONObject(jsonEventString);
|
||||
String eventType = jsonEvent.getString("type");
|
||||
Log.d(TAG, "Signal event: " + jsonEventString);
|
||||
// NOTE: the newMessageSignalHandler is only instanciated if the user
|
||||
// enabled notifications in the app
|
||||
if (this.background && newMessageSignalHandler != null) {
|
||||
if (eventType.equals("messages.new")) {
|
||||
newMessageSignalHandler.handleNewMessageSignal(jsonEvent);
|
||||
}
|
||||
}
|
||||
|
||||
if(eventType.equals("local-notifications")) {
|
||||
Context ctx = this.getReactApplicationContext();
|
||||
Intent intent = new Intent(ctx, LocalNotificationsService.class);
|
||||
Bundle bundle = new Bundle();
|
||||
|
||||
bundle.putString("event", jsonEventString);
|
||||
intent.putExtras(bundle);
|
||||
|
||||
ctx.startService(intent);
|
||||
}
|
||||
|
||||
WritableMap params = Arguments.createMap();
|
||||
params.putString("jsonEvent", jsonEventString);
|
||||
this.getReactApplicationContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("gethEvent", params);
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, "JSON conversion failed: " + e.getMessage());
|
||||
}
|
||||
Log.d(TAG, "Signal event");
|
||||
WritableMap params = Arguments.createMap();
|
||||
params.putString("jsonEvent", jsonEventString);
|
||||
this.getReactApplicationContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("gethEvent", params);
|
||||
}
|
||||
|
||||
private File getLogsFile() {
|
||||
|
@ -442,7 +403,6 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
|
|||
@ReactMethod
|
||||
public void logout() {
|
||||
Log.d(TAG, "logout");
|
||||
disableNotifications();
|
||||
String result = Statusgo.logout();
|
||||
if (result.startsWith("{\"error\":\"\"")) {
|
||||
Log.d(TAG, "Logout result: " + result);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package im.status.ethereum.module;
|
||||
package im.status.ethereum.pushnotifications;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
@ -13,6 +13,7 @@ import androidx.core.app.NotificationCompat;
|
|||
import androidx.core.app.NotificationManagerCompat;
|
||||
|
||||
import android.os.Build;
|
||||
import im.status.ethereum.module.R;
|
||||
|
||||
public class ForegroundService extends Service {
|
||||
private static final String CHANNEL_ID = "status-service";
|
|
@ -1,4 +1,4 @@
|
|||
package im.status.ethereum.module;
|
||||
package im.status.ethereum.pushnotifications;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.ContentResolver;
|
||||
|
@ -33,10 +33,12 @@ import androidx.core.app.NotificationManagerCompat;
|
|||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.net.Uri;
|
||||
import android.media.AudioAttributes;
|
||||
|
||||
import android.util.Log;
|
||||
import im.status.ethereum.module.R;
|
||||
|
||||
public class NewMessageSignalHandler {
|
||||
//NOTE: currently we only show notifications for 1-1 chats, in the future we
|
||||
|
@ -57,6 +59,8 @@ public class NewMessageSignalHandler {
|
|||
private Context context;
|
||||
private Intent serviceIntent;
|
||||
private Boolean shouldRefreshNotifications;
|
||||
private int ONE_TO_ONE_CHAT_TYPE = 1;
|
||||
private int PRIVATE_GROUP_CHAT_TYPE = 3;
|
||||
|
||||
//NOTE: we use a dynamically created BroadcastReceiver here so that we can capture
|
||||
//intents from notifications and act on them. For instance when tapping/dismissing
|
||||
|
@ -68,8 +72,9 @@ public class NewMessageSignalHandler {
|
|||
if (intent.getAction() == ACTION_TAP_NOTIFICATION ||
|
||||
intent.getAction() == ACTION_DELETE_NOTIFICATION) {
|
||||
String chatId = intent.getExtras().getString("im.status.ethereum.chatId");
|
||||
int chatType = intent.getExtras().getInt("im.status.ethereum.chatType");
|
||||
if (intent.getAction() == ACTION_TAP_NOTIFICATION) {
|
||||
context.startActivity(getOpenAppIntent(chatId));
|
||||
context.startActivity(getOpenAppIntent(chatId, chatType));
|
||||
}
|
||||
removeChat(chatId);
|
||||
// clean up the group notifications when there is no
|
||||
|
@ -122,9 +127,15 @@ public class NewMessageSignalHandler {
|
|||
//NOTE: this method takes a chatId and returns an intent that will open the app in that chat
|
||||
//Once we support other kind of notifications we will need to adapt it. The simplest method
|
||||
//is probably to pass the universal link as param instead of the chatId.
|
||||
public Intent getOpenAppIntent(String chatId) {
|
||||
public Intent getOpenAppIntent(String chatId, int chatType) {
|
||||
Intent intent = getOpenAppIntent();
|
||||
intent.setData(Uri.parse("status-im://p/" + chatId));
|
||||
String path = "";
|
||||
if (chatType == ONE_TO_ONE_CHAT_TYPE) {
|
||||
path = "p/";
|
||||
} else if (chatType == PRIVATE_GROUP_CHAT_TYPE) {
|
||||
path = "g/args?a2=";
|
||||
}
|
||||
intent.setData(Uri.parse("status-im://" + path + chatId));
|
||||
return intent;
|
||||
}
|
||||
|
||||
|
@ -175,15 +186,17 @@ public class NewMessageSignalHandler {
|
|||
this.chats.remove(chatId);
|
||||
}
|
||||
|
||||
private PendingIntent createOnDismissedIntent(Context context, int notificationId, String chatId) {
|
||||
private PendingIntent createOnDismissedIntent(Context context, int notificationId, String chatId, int chatType) {
|
||||
Intent intent = new Intent(ACTION_DELETE_NOTIFICATION);
|
||||
intent.putExtra("im.status.ethereum.chatId", chatId);
|
||||
intent.putExtra("im.status.ethereum.chatType", chatType);
|
||||
return PendingIntent.getBroadcast(context.getApplicationContext(), notificationId, intent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
}
|
||||
|
||||
private PendingIntent createOnTapIntent(Context context, int notificationId, String chatId) {
|
||||
private PendingIntent createOnTapIntent(Context context, int notificationId, String chatId, int chatType) {
|
||||
Intent intent = new Intent(ACTION_TAP_NOTIFICATION);
|
||||
intent.putExtra("im.status.ethereum.chatId", chatId);
|
||||
intent.putExtra("im.status.ethereum.chatType", chatType);
|
||||
return PendingIntent.getBroadcast(context.getApplicationContext(), notificationId, intent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
}
|
||||
|
||||
|
@ -203,8 +216,8 @@ public class NewMessageSignalHandler {
|
|||
.setStyle(messagingStyle)
|
||||
.setGroup(GROUP_STATUS_MESSAGES)
|
||||
.setGroupSummary(true)
|
||||
.setContentIntent(createOnTapIntent(context, notificationId, chat.getId()))
|
||||
.setDeleteIntent(createOnDismissedIntent(context, notificationId, chat.getId()))
|
||||
.setContentIntent(createOnTapIntent(context, notificationId, chat.getId(), chat.getType()))
|
||||
.setDeleteIntent(createOnDismissedIntent(context, notificationId, chat.getId(), chat.getType()))
|
||||
.setNumber(messages.size())
|
||||
.setAutoCancel(true);
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
|
@ -224,31 +237,13 @@ public class NewMessageSignalHandler {
|
|||
}
|
||||
}
|
||||
|
||||
void handleNewMessageSignal(JSONObject newMessageSignal) {
|
||||
try {
|
||||
JSONArray chatsNewMessagesData = newMessageSignal.getJSONObject("event").getJSONArray("chats");
|
||||
for (int i = 0; i < chatsNewMessagesData.length(); i++) {
|
||||
try {
|
||||
upsertChat(chatsNewMessagesData.getJSONObject(i));
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, "JSON conversion failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
JSONArray messagesNewMessagesData = newMessageSignal.getJSONObject("event").getJSONArray("messages");
|
||||
for (int i = 0; i < messagesNewMessagesData.length(); i++) {
|
||||
try {
|
||||
upsertMessage(messagesNewMessagesData.getJSONObject(i));
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, "JSON conversion failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
void handleNewMessage (Bundle data) {
|
||||
upsertChat(data);
|
||||
upsertMessage(data);
|
||||
|
||||
if(shouldRefreshNotifications) {
|
||||
refreshNotifications();
|
||||
shouldRefreshNotifications = false;
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, "JSON conversion failed: " + e.getMessage());
|
||||
if(shouldRefreshNotifications) {
|
||||
refreshNotifications();
|
||||
shouldRefreshNotifications = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -268,69 +263,37 @@ public class NewMessageSignalHandler {
|
|||
return person;
|
||||
}
|
||||
|
||||
private void upsertChat(JSONObject chatData) {
|
||||
try {
|
||||
// NOTE: this is an exemple of chatData
|
||||
// {"chatId":"contact-discovery-3622","filterId":"c0239d63f830e8b25f4bf7183c8d207f355a925b89514a17068cae4898e7f193",
|
||||
// "symKeyId":"","oneToOne":true,"identity":"046599511623d7385b926ce709ac57d518dac10d451a81f75cd32c7fb4b1c...",
|
||||
// "topic":"0xc446561b","discovery":false,"negotiated":false,"listen":true}
|
||||
int oneToOne = chatData.getInt("chatType");
|
||||
// NOTE: for now we only notify one to one chats
|
||||
// TODO: also notifiy on mentions, keywords and group chats
|
||||
// TODO: one would have to pass the ens name and keywords to notify on when instanciating the class as well
|
||||
// as have a method to add new ones after the handler is instanciated
|
||||
if (oneToOne == 1) {
|
||||
//JSONArray messagesData = chatNewMessagesData.getJSONArray("messages");
|
||||
private void upsertChat(Bundle data) {
|
||||
String id = data.getString("chatId");
|
||||
int type = Integer.parseInt(data.getString("chatType"));
|
||||
StatusChat chat = chats.get(id);
|
||||
|
||||
// there is no proper id for oneToOne chat in chatData so we peek into first message sig
|
||||
// TODO: won't work for sync becaus it could be our own message
|
||||
String id = chatData.getString("id");
|
||||
StatusChat chat = chats.get(id);
|
||||
// if the chat was not already there, we create one
|
||||
if (chat == null) {
|
||||
chat = new StatusChat(id, type);
|
||||
}
|
||||
|
||||
chats.put(id, chat);
|
||||
}
|
||||
|
||||
// if the chat was not already there, we create one
|
||||
if (chat == null) {
|
||||
chat = new StatusChat(id, true);
|
||||
}
|
||||
private void upsertMessage(Bundle data) {
|
||||
String chatId = data.getString("chatId");
|
||||
StatusChat chat = chats.get(chatId);
|
||||
if (chat == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
chats.put(id, chat);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, "JSON conversion failed: " + e.getMessage());
|
||||
StatusMessage message = createMessage(data);
|
||||
if (message != null) {
|
||||
chat.appendMessage(message);
|
||||
chats.put(chatId, chat);
|
||||
shouldRefreshNotifications = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void upsertMessage(JSONObject messageData) {
|
||||
try {
|
||||
String chatId = messageData.getString("localChatId");
|
||||
StatusChat chat = chats.get(chatId);
|
||||
if (chat == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
StatusMessage message = createMessage(messageData);
|
||||
if (message != null) {
|
||||
chat.appendMessage(message);
|
||||
chats.put(chatId, chat);
|
||||
shouldRefreshNotifications = true;
|
||||
}
|
||||
|
||||
}
|
||||
catch (JSONException e) {
|
||||
Log.e(TAG, "JSON conversion failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private StatusMessage createMessage(JSONObject messageData) {
|
||||
try {
|
||||
Person author = getPerson(messageData.getString("from"), messageData.getString("identicon"), messageData.getString("alias"));
|
||||
return new StatusMessage(author, messageData.getLong("whisperTimestamp"), messageData.getString("text"));
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, "JSON conversion failed: " + e.getMessage());
|
||||
}
|
||||
return null;
|
||||
private StatusMessage createMessage(Bundle data) {
|
||||
Person author = getPerson(data.getString("from"), data.getString("identicon"), data.getString("alias"));
|
||||
return new StatusMessage(author, data.getLong("whisperTimestamp"), data.getString("text"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,11 +301,11 @@ class StatusChat {
|
|||
private ArrayList<StatusMessage> messages;
|
||||
private String id;
|
||||
private String name;
|
||||
private Boolean oneToOne;
|
||||
private int type;
|
||||
|
||||
StatusChat(String id, Boolean oneToOne) {
|
||||
StatusChat(String id, int type) {
|
||||
this.id = id;
|
||||
this.oneToOne = oneToOne;
|
||||
this.type = type;
|
||||
this.messages = new ArrayList<StatusMessage>();
|
||||
this.name = name;
|
||||
}
|
||||
|
@ -351,6 +314,10 @@ class StatusChat {
|
|||
return id;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
|
||||
//TODO this should be improved as it would rename the chat
|
|
@ -26,6 +26,7 @@ import com.facebook.react.bridge.ReadableArray;
|
|||
import com.facebook.react.bridge.WritableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import android.util.Log;
|
||||
|
||||
import im.status.ethereum.pushnotifications.PushNotificationJsDelivery;
|
||||
|
||||
|
@ -35,9 +36,12 @@ public class PushNotification extends ReactContextBaseJavaModule implements Acti
|
|||
private final SecureRandom mRandomNumberGenerator = new SecureRandom();
|
||||
private PushNotificationHelper pushNotificationHelper;
|
||||
private PushNotificationJsDelivery delivery;
|
||||
private ReactApplicationContext reactContext;
|
||||
private NewMessageSignalHandler newMessageSignalHandler;
|
||||
|
||||
public PushNotification(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
this.reactContext = reactContext;
|
||||
reactContext.addActivityEventListener(this);
|
||||
Application applicationContext = (Application) reactContext.getApplicationContext();
|
||||
|
||||
|
@ -105,6 +109,28 @@ public class PushNotification extends ReactContextBaseJavaModule implements Acti
|
|||
if (bundle.getString("id") == null) {
|
||||
bundle.putString("id", String.valueOf(mRandomNumberGenerator.nextInt()));
|
||||
}
|
||||
pushNotificationHelper.sendToNotificationCentre(bundle);
|
||||
|
||||
String type = bundle.getString("type");
|
||||
if (type != null && type.equals("message")) {
|
||||
if (this.newMessageSignalHandler != null) {
|
||||
newMessageSignalHandler.handleNewMessage(bundle);
|
||||
}
|
||||
} else {
|
||||
pushNotificationHelper.sendToNotificationCentre(bundle);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void enableNotifications() {
|
||||
this.newMessageSignalHandler = new NewMessageSignalHandler(reactContext);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void disableNotifications() {
|
||||
if (newMessageSignalHandler != null) {
|
||||
newMessageSignalHandler.stop();
|
||||
newMessageSignalHandler = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -48,6 +48,11 @@
|
|||
([cofx chat-id]
|
||||
(active-chat? (get-chat cofx chat-id))))
|
||||
|
||||
(defn foreground-chat?
|
||||
[{{:keys [current-chat-id view-id]} :db} chat-id]
|
||||
(and (= current-chat-id chat-id)
|
||||
(= view-id :chat)))
|
||||
|
||||
(defn group-chat?
|
||||
([chat]
|
||||
(and (multi-user-chat? chat)
|
||||
|
|
|
@ -35,14 +35,6 @@
|
|||
config
|
||||
#(callback (types/json->clj %))))
|
||||
|
||||
(defn enable-notifications []
|
||||
(log/debug "[native-module] enable-notifications")
|
||||
(.enableNotifications ^js (status)))
|
||||
|
||||
(defn disable-notifications []
|
||||
(log/debug "[native-module] disable-notifications")
|
||||
(.disableNotifications ^js (status)))
|
||||
|
||||
(defn save-account-and-login
|
||||
"NOTE: beware, the password has to be sha3 hashed"
|
||||
[key-uid multiaccount-data hashed-password settings config accounts-data]
|
||||
|
|
|
@ -15,3 +15,9 @@
|
|||
#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)))
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||
["@react-native-community/push-notification-ios" :default pn-ios]
|
||||
[status-im.notifications.android :as pn-android]
|
||||
[status-im.native-module.core :as status]
|
||||
[status-im.notifications.local :as local]
|
||||
[quo.platform :as platform]
|
||||
[status-im.utils.config :as config]
|
||||
|
@ -70,21 +69,21 @@
|
|||
(do
|
||||
(pn-android/create-channel {:channel-id "status-im-notifications"
|
||||
:channel-name "Status push notifications"})
|
||||
(status/enable-notifications))
|
||||
(pn-android/enable-notifications))
|
||||
(enable-ios-notifications))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::disable
|
||||
(fn [_]
|
||||
(if platform/android?
|
||||
(status/disable-notifications)
|
||||
(pn-android/disable-notifications)
|
||||
(disable-ios-notifications))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::logout-disable
|
||||
(fn [_]
|
||||
(if platform/android?
|
||||
(status/disable-notifications)
|
||||
(pn-android/disable-notifications)
|
||||
(.abandonPermissions ^js pn-ios))))
|
||||
|
||||
(fx/defn handle-enable-notifications-event
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
(ns status-im.notifications.local
|
||||
(:require [taoensso.timbre :as log]
|
||||
[clojure.string :as cstr]
|
||||
[status-im.utils.fx :as fx]
|
||||
[status-im.ethereum.decode :as decode]
|
||||
["@react-native-community/push-notification-ios" :default pn-ios]
|
||||
|
@ -14,7 +13,11 @@
|
|||
[quo.platform :as platform]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.ui.components.react :as react]
|
||||
[cljs-bean.core :as bean]))
|
||||
[cljs-bean.core :as bean]
|
||||
[status-im.ui.screens.chat.components.reply :as reply]
|
||||
[clojure.string :as clojure.string]
|
||||
[status-im.chat.models :as chat.models]
|
||||
[status-im.constants :as constants]))
|
||||
|
||||
(def default-erc20-token
|
||||
{:symbol :ERC20
|
||||
|
@ -24,23 +27,31 @@
|
|||
(def notification-event-ios "localNotification")
|
||||
(def notification-event-android "remoteNotificationReceived")
|
||||
|
||||
(defn local-push-ios [{:keys [title message user-info]}]
|
||||
(.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-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 [{:keys [title message icon user-info channel-id]
|
||||
:or {channel-id "status-im-notifications"}}]
|
||||
(pn-android/present-local-notification (merge {:channelId channel-id
|
||||
:title title
|
||||
:message message
|
||||
:showBadge false}
|
||||
(when user-info
|
||||
{:userInfo (bean/->js user-info)})
|
||||
(when icon
|
||||
{:largeIconUrl (:uri (react/resolve-asset-source icon))}))))
|
||||
(defn local-push-android
|
||||
[{:keys [title message icon user-info channel-id type]
|
||||
:as notification
|
||||
:or {channel-id "status-im-notifications"}}]
|
||||
(pn-android/present-local-notification
|
||||
(merge {:channelId channel-id
|
||||
:title title
|
||||
:message message
|
||||
:showBadge false}
|
||||
(when user-info
|
||||
{:userInfo (bean/->js user-info)})
|
||||
(when icon
|
||||
{:largeIconUrl (:uri (react/resolve-asset-source icon))})
|
||||
(when (= type "message")
|
||||
notification))))
|
||||
|
||||
(defn handle-notification-press [{{deep-link :deepLink} :userInfo
|
||||
interaction :userInteraction}]
|
||||
|
@ -61,13 +72,14 @@
|
|||
(when (and data (.-dataJSON data))
|
||||
(handle-notification-press (types/json->clj (.-dataJSON data))))))))
|
||||
|
||||
(defn create-notification [{{:keys [state from to fromAccount toAccount value erc20 contract network]}
|
||||
:body
|
||||
:as notification}]
|
||||
(defn create-transfer-notification
|
||||
[{{:keys [state from to fromAccount toAccount value erc20 contract network]}
|
||||
:body
|
||||
:as notification}]
|
||||
(let [chain (ethereum/chain-id->chain-keyword network)
|
||||
token (if erc20
|
||||
(get-in tokens/all-tokens-normalized [(keyword chain)
|
||||
(cstr/lower-case contract)]
|
||||
(get-in tokens/all-tokens-normalized
|
||||
[(keyword chain) (clojure.string/lower-case contract)]
|
||||
default-erc20-token)
|
||||
(tokens/native-currency (keyword chain)))
|
||||
amount (money/wei->ether (decode/uint value))
|
||||
|
@ -95,15 +107,83 @@
|
|||
:user-info notification
|
||||
:message description}))
|
||||
|
||||
(defn show-message-pn?
|
||||
[{{:keys [app-state multiaccount]} :db :as cofx}
|
||||
{{:keys [message chat]} :body}]
|
||||
(let [chat-id (get chat :id)
|
||||
chat-type (get chat :chatType)]
|
||||
(and
|
||||
(or (= app-state "background")
|
||||
(not (chat.models/foreground-chat? cofx chat-id)))
|
||||
(or (contains? #{constants/one-to-one-chat-type
|
||||
constants/private-group-chat-type}
|
||||
chat-type)
|
||||
(contains? (set (get message :mentions))
|
||||
(get multiaccount :public-key))))))
|
||||
|
||||
(defn create-message-notification
|
||||
([cofx notification]
|
||||
(when (or (nil? cofx)
|
||||
(show-message-pn? cofx notification))
|
||||
(create-message-notification notification)))
|
||||
([{{:keys [message contact chat]} :body}]
|
||||
(let [chat-type (get chat :chatType)
|
||||
chat-id (get chat :id)
|
||||
contact-name @(re-frame/subscribe
|
||||
[:contacts/contact-name-by-identity (get contact :id)])
|
||||
group-chat? (not= chat-type constants/one-to-one-chat-type)
|
||||
title (clojure.string/join
|
||||
" "
|
||||
(cond-> [contact-name]
|
||||
group-chat?
|
||||
(conj
|
||||
;; TODO(rasom): to be translated
|
||||
"in")
|
||||
|
||||
group-chat?
|
||||
(conj
|
||||
(str (when (contains? #{constants/public-chat-type
|
||||
constants/community-chat-type}
|
||||
chat-type)
|
||||
"#")
|
||||
(get chat :name)))))]
|
||||
{:type "message"
|
||||
:chatType (str (get chat :chatType))
|
||||
:from title
|
||||
:chatId chat-id
|
||||
:alias title
|
||||
:identicon (get contact :identicon)
|
||||
:whisperTimestamp (get message :whisperTimestamp)
|
||||
:text (reply/get-quoted-text-with-mentions (:parsedText message))})))
|
||||
|
||||
(defn create-notification
|
||||
([notification]
|
||||
(create-notification nil notification))
|
||||
([cofx {:keys [bodyType] :as notification}]
|
||||
(assoc
|
||||
(case bodyType
|
||||
"message" (create-message-notification cofx notification)
|
||||
"transaction" (create-transfer-notification notification)
|
||||
nil)
|
||||
:body-type bodyType)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::local-push-ios
|
||||
(fn [evt]
|
||||
(-> evt create-notification local-push-ios)))
|
||||
|
||||
(fx/defn local-notification-android
|
||||
{:events [::local-notification-android]}
|
||||
[cofx event]
|
||||
(some->> event
|
||||
(create-notification cofx)
|
||||
local-push-android))
|
||||
|
||||
(fx/defn process
|
||||
[_ evt]
|
||||
(when platform/ios?
|
||||
{::local-push-ios evt}))
|
||||
[cofx evt]
|
||||
(if platform/ios?
|
||||
{::local-push-ios evt}
|
||||
(local-notification-android cofx evt)))
|
||||
|
||||
(defn handle []
|
||||
(fn [^js message]
|
||||
|
@ -112,7 +192,7 @@
|
|||
(fn [on-success on-error]
|
||||
(try
|
||||
(when (= "local-notifications" (:type evt))
|
||||
(-> (:event evt) create-notification local-push-android))
|
||||
(re-frame/dispatch [::local-notification-android (:event evt)]))
|
||||
(on-success)
|
||||
(catch :default e
|
||||
(log/warn "failed to handle background notification" e)
|
||||
|
|
|
@ -95,5 +95,6 @@
|
|||
{:events [::on-scan-success]}
|
||||
[{:keys [db]} uri]
|
||||
{::router/handle-uri {:chain (ethereum/chain-keyword db)
|
||||
:chats (get db :chats)
|
||||
:uri uri
|
||||
:cb #(re-frame/dispatch [::match-scanned-value %])}})
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
[cljs.spec.alpha :as spec]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im.utils.db :as utils.db]
|
||||
[status-im.utils.http :as http]))
|
||||
[status-im.utils.http :as http]
|
||||
[status-im.chat.models :as chat.models]))
|
||||
|
||||
(def ethereum-scheme "ethereum:")
|
||||
|
||||
|
@ -91,20 +92,30 @@
|
|||
{:type :public-chat
|
||||
:error :invalid-topic}))
|
||||
|
||||
(defn match-group-chat [{:strs [a a1 a2]}]
|
||||
(defn match-group-chat [chats {:strs [a a1 a2]}]
|
||||
(let [[admin-pk encoded-chat-name chat-id] [a a1 a2]
|
||||
chat-id-parts (when (not (string/blank? chat-id)) (string/split chat-id #"-"))
|
||||
chat-name (when (not (string/blank? encoded-chat-name)) (js/decodeURI encoded-chat-name))]
|
||||
(if (and (not (string/blank? chat-id)) (not (string/blank? admin-pk)) (not (string/blank? chat-name))
|
||||
(> (count chat-id-parts) 1)
|
||||
(not (string/blank? (first chat-id-parts)))
|
||||
(utils.db/valid-public-key? admin-pk)
|
||||
(utils.db/valid-public-key? (last chat-id-parts)))
|
||||
{:type :group-chat
|
||||
:chat-id chat-id
|
||||
:invitation-admin admin-pk
|
||||
:chat-name chat-name}
|
||||
{:error :invalid-group-chat-data})))
|
||||
(cond (and (not (string/blank? chat-id)) (not (string/blank? admin-pk)) (not (string/blank? chat-name))
|
||||
(> (count chat-id-parts) 1)
|
||||
(not (string/blank? (first chat-id-parts)))
|
||||
(utils.db/valid-public-key? admin-pk)
|
||||
(utils.db/valid-public-key? (last chat-id-parts)))
|
||||
{:type :group-chat
|
||||
:chat-id chat-id
|
||||
:invitation-admin admin-pk
|
||||
:chat-name chat-name}
|
||||
|
||||
(and (not (string/blank? chat-id))
|
||||
(chat.models/group-chat? (get chats chat-id)))
|
||||
(let [{:keys [chat-name invitation-admin]} (get chats chat-id)]
|
||||
{:type :group-chat
|
||||
:chat-id chat-id
|
||||
:invitation-admin invitation-admin
|
||||
:chat-name chat-name})
|
||||
|
||||
:else
|
||||
{:error :invalid-group-chat-data})))
|
||||
|
||||
(defn match-private-chat-async [chain {:keys [chat-id]} cb]
|
||||
(match-contact-async chain
|
||||
|
@ -165,7 +176,7 @@
|
|||
{:type :wallet-account
|
||||
:account (when account (string/lower-case account))})
|
||||
|
||||
(defn handle-uri [chain uri cb]
|
||||
(defn handle-uri [chain chats uri cb]
|
||||
(let [{:keys [handler route-params query-params]} (match-uri uri)]
|
||||
(log/info "[router] uri " uri " matched " handler " with " route-params)
|
||||
(cond
|
||||
|
@ -185,7 +196,7 @@
|
|||
(match-private-chat-async chain route-params cb)
|
||||
|
||||
(= handler :group-chat)
|
||||
(cb (match-group-chat query-params))
|
||||
(cb (match-group-chat chats query-params))
|
||||
|
||||
(spec/valid? :global/public-key uri)
|
||||
(match-contact-async chain {:user-id uri} cb)
|
||||
|
@ -205,5 +216,5 @@
|
|||
|
||||
(re-frame/reg-fx
|
||||
::handle-uri
|
||||
(fn [{:keys [chain uri cb]}]
|
||||
(handle-uri chain uri cb)))
|
||||
(fn [{:keys [chain chats uri cb]}]
|
||||
(handle-uri chain chats uri cb)))
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
(def error {:error :invalid-group-chat-data})
|
||||
|
||||
(deftest match-group-chat-query
|
||||
(are [query-params expected] (= (router/match-group-chat query-params)
|
||||
(are [query-params expected] (= (router/match-group-chat {} query-params)
|
||||
expected)
|
||||
nil error
|
||||
{} error
|
||||
|
@ -78,4 +78,4 @@
|
|||
{"a" public-key "a1" chat-name "a2" chat-id} {:type :group-chat
|
||||
:chat-id chat-id
|
||||
:invitation-admin public-key
|
||||
:chat-name chat-name}))
|
||||
:chat-name chat-name}))
|
||||
|
|
|
@ -97,5 +97,6 @@
|
|||
{:events [:contact/qr-code-scanned]}
|
||||
[{:keys [db]} data opts]
|
||||
{::router/handle-uri {:chain (ethereum/chain-keyword db)
|
||||
:chats (get db :chats)
|
||||
:uri data
|
||||
:cb #(re-frame/dispatch [::qr-code-handled % opts])}})
|
||||
|
|
|
@ -6,5 +6,5 @@
|
|||
(handlers/register-handler-fx
|
||||
:handle-universal-link
|
||||
(fn [cofx [_ url]]
|
||||
(log/debug "universal links: event received for " url)
|
||||
(log/info "universal links: event received for " url)
|
||||
(universal-links/handle-url cofx url)))
|
||||
|
|
|
@ -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.69.3",
|
||||
"commit-sha1": "e18050b87f75b09cd8ad8451a7d7e0fa2e498654",
|
||||
"src-sha256": "01s1s91afy2bwlx928b62fw4fc6mvsphz2py1sfc0fl9r7dw1lkz"
|
||||
"version": "v0.70.0",
|
||||
"commit-sha1": "d862b042ae78c8cdf38a33a7a824698ae5aa8089",
|
||||
"src-sha256": "1g1kyn2nz2vjzh6qvs57k7yhy6zkw4s6jnhnxpvapzxndyg8q5h4"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue