notifications: enable local notifications
- only show notifications when app is in background - open the user chat upon tap on notification - remove chat from notifications on tap or dismiss notification - keep the service alive on host destroy - enable local notifications
This commit is contained in:
parent
277f65b94d
commit
5608d649b0
|
@ -17,4 +17,3 @@ SNOOPY=0
|
||||||
RPC_NETWORKS_ONLY=1
|
RPC_NETWORKS_ONLY=1
|
||||||
PARTITIONED_TOPIC=0
|
PARTITIONED_TOPIC=0
|
||||||
MOBILE_UI_FOR_DESKTOP=1
|
MOBILE_UI_FOR_DESKTOP=1
|
||||||
LOCAL_NOTIFICATIONS=0
|
|
||||||
|
|
|
@ -3,6 +3,8 @@ package im.status.ethereum.module;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
@ -25,6 +27,7 @@ import android.graphics.BitmapFactory;
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationChannel;
|
import android.app.NotificationChannel;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
|
||||||
import androidx.core.app.NotificationManagerCompat;
|
import androidx.core.app.NotificationManagerCompat;
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
|
@ -35,7 +38,14 @@ import android.media.AudioAttributes;
|
||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
class NewMessageSignalHandler {
|
public class NewMessageSignalHandler {
|
||||||
|
//NOTE: currently we only show notifications for 1-1 chats, in the future we
|
||||||
|
//will most likely extend to other kind of notifications. The first step will
|
||||||
|
//be to define actions for these notifications, add it to the filter in
|
||||||
|
//`registerBroadcastReceiver` method, and add some action specific code
|
||||||
|
//in notificationActionReceiver.
|
||||||
|
public static final String ACTION_DELETE_NOTIFICATION = "im.status.ethereum.module.DELETE_NOTIFICATION";
|
||||||
|
public static final String ACTION_TAP_NOTIFICATION = "im.status.ethereum.module.TAP_NOTIFICATION";
|
||||||
private static final String GROUP_STATUS_MESSAGES = "im.status.notifications.message";
|
private static final String GROUP_STATUS_MESSAGES = "im.status.notifications.message";
|
||||||
private static final String CHANNEL_NAME = "Status";
|
private static final String CHANNEL_NAME = "Status";
|
||||||
private static final String CHANNEL_DESCRIPTION = "Get notifications on new messages and mentions";
|
private static final String CHANNEL_DESCRIPTION = "Get notifications on new messages and mentions";
|
||||||
|
@ -48,6 +58,64 @@ class NewMessageSignalHandler {
|
||||||
private Intent serviceIntent;
|
private Intent serviceIntent;
|
||||||
private Boolean shouldRefreshNotifications;
|
private Boolean shouldRefreshNotifications;
|
||||||
|
|
||||||
|
//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
|
||||||
|
//a chat notification we want to clear the chat so that next messages don't show
|
||||||
|
//the messages that we have seen again
|
||||||
|
private final BroadcastReceiver notificationActionReceiver = new BroadcastReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
String chatId = intent.getExtras().getString("im.status.ethereum.chatId");
|
||||||
|
if (intent.getAction() == ACTION_TAP_NOTIFICATION) {
|
||||||
|
context.startActivity(getOpenAppIntent(chatId));
|
||||||
|
}
|
||||||
|
removeChat(chatId);
|
||||||
|
// clean up the group notifications when there is no
|
||||||
|
// more unread chats
|
||||||
|
if (chats.size() == 0) {
|
||||||
|
notificationManager.cancelAll();
|
||||||
|
}
|
||||||
|
Log.e(TAG, "intent received: " + intent.getAction());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private void registerBroadcastReceiver() {
|
||||||
|
IntentFilter filter = new IntentFilter();
|
||||||
|
filter.addAction(ACTION_DELETE_NOTIFICATION);
|
||||||
|
filter.addAction(ACTION_TAP_NOTIFICATION);
|
||||||
|
context.registerReceiver(notificationActionReceiver, filter);
|
||||||
|
Log.e(TAG, "Broadcast Receiver registered");
|
||||||
|
}
|
||||||
|
|
||||||
|
//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) {
|
||||||
|
Class intentClass;
|
||||||
|
String packageName = context.getPackageName();
|
||||||
|
Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName);
|
||||||
|
String className = launchIntent.getComponent().getClassName();
|
||||||
|
try {
|
||||||
|
intentClass = Class.forName(className);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Intent intent = new Intent(context, intentClass);
|
||||||
|
intent.addCategory(Intent.CATEGORY_BROWSABLE);
|
||||||
|
intent.setAction(Intent.ACTION_VIEW);
|
||||||
|
//NOTE: you might wonder, why the heck did he decide to set these flags in particular. Well,
|
||||||
|
//the answer is a simple as it can get in the Android native development world. I noticed
|
||||||
|
//that my initial setup was opening the app but wasn't triggering any events on the js side, like
|
||||||
|
//the links do from the browser. So I compared both intents and noticed that the link from
|
||||||
|
//the browser produces an intent with the flag 0x14000000. I found out that it was the following
|
||||||
|
//flags in this link:
|
||||||
|
//https://stackoverflow.com/questions/52390129/android-intent-setflags-issue
|
||||||
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
|
intent.setData(Uri.parse("status-im://chat/private/" + chatId));
|
||||||
|
return intent;
|
||||||
|
}
|
||||||
|
|
||||||
public NewMessageSignalHandler(Context context) {
|
public NewMessageSignalHandler(Context context) {
|
||||||
// NOTE: when instanciated the NewMessageSignalHandler class starts a foreground service
|
// NOTE: when instanciated the NewMessageSignalHandler class starts a foreground service
|
||||||
// to keep the app running in the background in order to receive notifications
|
// to keep the app running in the background in order to receive notifications
|
||||||
|
@ -61,12 +129,17 @@ class NewMessageSignalHandler {
|
||||||
Log.e(TAG, "Starting Foreground Service");
|
Log.e(TAG, "Starting Foreground Service");
|
||||||
Intent serviceIntent = new Intent(context, ForegroundService.class);
|
Intent serviceIntent = new Intent(context, ForegroundService.class);
|
||||||
context.startService(serviceIntent);
|
context.startService(serviceIntent);
|
||||||
|
this.registerBroadcastReceiver();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
Log.e(TAG, "Stopping Foreground Service");
|
Log.e(TAG, "Stopping Foreground Service");
|
||||||
|
//NOTE: we cancel all the current notifications, because the intents can't be used anymore
|
||||||
|
//since the broadcast receiver will be killed as well and won't be able to handle any intent
|
||||||
|
notificationManager.cancelAll();
|
||||||
Intent serviceIntent = new Intent(context, ForegroundService.class);
|
Intent serviceIntent = new Intent(context, ForegroundService.class);
|
||||||
context.stopService(serviceIntent);
|
context.stopService(serviceIntent);
|
||||||
|
context.unregisterReceiver(notificationActionReceiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createNotificationChannel() {
|
private void createNotificationChannel() {
|
||||||
|
@ -77,30 +150,49 @@ class NewMessageSignalHandler {
|
||||||
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);
|
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);
|
||||||
channel.setDescription(CHANNEL_DESCRIPTION);
|
channel.setDescription(CHANNEL_DESCRIPTION);
|
||||||
AudioAttributes audioAttributes = new AudioAttributes.Builder()
|
AudioAttributes audioAttributes = new AudioAttributes.Builder()
|
||||||
.setUsage(AudioAttributes.USAGE_NOTIFICATION)
|
.setUsage(AudioAttributes.USAGE_NOTIFICATION)
|
||||||
.build();
|
.build();
|
||||||
channel.setSound(soundUri, audioAttributes);
|
channel.setSound(soundUri, audioAttributes);
|
||||||
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
|
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
|
||||||
notificationManager.createNotificationChannel(channel);
|
notificationManager.createNotificationChannel(channel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void removeChat(String chatId) {
|
||||||
|
this.chats.remove(chatId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PendingIntent createOnDismissedIntent(Context context, int notificationId, String chatId) {
|
||||||
|
Intent intent = new Intent(ACTION_DELETE_NOTIFICATION);
|
||||||
|
intent.putExtra("im.status.ethereum.chatId", chatId);
|
||||||
|
return PendingIntent.getBroadcast(context.getApplicationContext(), notificationId, intent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PendingIntent createOnTapIntent(Context context, int notificationId, String chatId) {
|
||||||
|
Intent intent = new Intent(ACTION_TAP_NOTIFICATION);
|
||||||
|
intent.putExtra("im.status.ethereum.chatId", chatId);
|
||||||
|
return PendingIntent.getBroadcast(context.getApplicationContext(), notificationId, intent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||||
|
}
|
||||||
|
|
||||||
public void notify(int notificationId, StatusChat chat) {
|
public void notify(int notificationId, StatusChat chat) {
|
||||||
NotificationCompat.MessagingStyle messagingStyle = new NotificationCompat.MessagingStyle("Me");
|
NotificationCompat.MessagingStyle messagingStyle = new NotificationCompat.MessagingStyle("Me");
|
||||||
ArrayList<StatusMessage> messages = chat.getMessages();
|
ArrayList<StatusMessage> messages = chat.getMessages();
|
||||||
for (int i = 0; i < messages.size(); i++) {
|
for (int i = 0; i < messages.size(); i++) {
|
||||||
StatusMessage message = messages.get(i);
|
StatusMessage message = messages.get(i);
|
||||||
messagingStyle.addMessage(message.getText(),
|
messagingStyle.addMessage(message.getText(),
|
||||||
message.getTimestamp(),
|
message.getTimestamp(),
|
||||||
message.getAuthor());
|
message.getAuthor());
|
||||||
}
|
}
|
||||||
|
|
||||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
|
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
|
||||||
.setSmallIcon(R.drawable.ic_stat_notify_status)
|
.setSmallIcon(R.drawable.ic_stat_notify_status)
|
||||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||||
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
|
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
|
||||||
.setStyle(messagingStyle)
|
.setStyle(messagingStyle)
|
||||||
.setGroup(GROUP_STATUS_MESSAGES);
|
.setGroup(GROUP_STATUS_MESSAGES)
|
||||||
|
.setGroupSummary(true)
|
||||||
|
.setContentIntent(createOnTapIntent(context, notificationId, chat.getId()))
|
||||||
|
.setDeleteIntent(createOnDismissedIntent(context, notificationId, chat.getId()))
|
||||||
|
.setAutoCancel(true);
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
builder.setVibrate(new long[0]);
|
builder.setVibrate(new long[0]);
|
||||||
}
|
}
|
||||||
|
@ -109,33 +201,13 @@ class NewMessageSignalHandler {
|
||||||
|
|
||||||
public void refreshNotifications() {
|
public void refreshNotifications() {
|
||||||
NotificationCompat.InboxStyle summaryStyle = new NotificationCompat.InboxStyle();
|
NotificationCompat.InboxStyle summaryStyle = new NotificationCompat.InboxStyle();
|
||||||
String summary = "";
|
|
||||||
int notificationId = 2; // we start at 2 because the service is using 1 and can't use 0
|
int notificationId = 2; // we start at 2 because the service is using 1 and can't use 0
|
||||||
int messageCounter = 0;
|
|
||||||
Iterator<StatusChat> chatIterator = chats.values().iterator();
|
Iterator<StatusChat> chatIterator = chats.values().iterator();
|
||||||
while(chatIterator.hasNext()) {
|
while(chatIterator.hasNext()) {
|
||||||
StatusChat chat = (StatusChat)chatIterator.next();
|
StatusChat chat = (StatusChat)chatIterator.next();
|
||||||
notify(notificationId, chat);
|
notify(notificationId, chat);
|
||||||
notificationId++;
|
notificationId++;
|
||||||
messageCounter += chat.getMessages().size();
|
|
||||||
summaryStyle.addLine(chat.getSummary());
|
|
||||||
summary += chat.getSummary() + "\n";
|
|
||||||
}
|
}
|
||||||
// NOTE: this is necessary for old versions of Android, newer versions are
|
|
||||||
// building this group themselves and I was not able to make any change to
|
|
||||||
// what this group displays
|
|
||||||
NotificationCompat.Builder groupBuilder =
|
|
||||||
new NotificationCompat.Builder(context, CHANNEL_ID)
|
|
||||||
.setContentText(summary)
|
|
||||||
.setSmallIcon(R.drawable.ic_stat_notify_status)
|
|
||||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
|
||||||
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
|
|
||||||
.setContentTitle("You got " + messageCounter + " messages in " + chats.size() + " chats")
|
|
||||||
.setStyle(summaryStyle
|
|
||||||
.setBigContentTitle("You got " + messageCounter + " messages in " + chats.size() + " chats"))
|
|
||||||
.setGroup(GROUP_STATUS_MESSAGES)
|
|
||||||
.setGroupSummary(true);
|
|
||||||
notificationManager.notify(notificationId, groupBuilder.build());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleNewMessageSignal(JSONObject newMessageSignal) {
|
void handleNewMessageSignal(JSONObject newMessageSignal) {
|
||||||
|
@ -207,7 +279,7 @@ class NewMessageSignalHandler {
|
||||||
chat = new StatusChat(id, true);
|
chat = new StatusChat(id, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
chats.put(id, chat);
|
chats.put(id, chat);
|
||||||
}
|
}
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
Log.e(TAG, "JSON conversion failed: " + e.getMessage());
|
Log.e(TAG, "JSON conversion failed: " + e.getMessage());
|
||||||
|
@ -217,34 +289,34 @@ class NewMessageSignalHandler {
|
||||||
|
|
||||||
|
|
||||||
private void upsertMessage(JSONObject messageData) {
|
private void upsertMessage(JSONObject messageData) {
|
||||||
try {
|
try {
|
||||||
String chatId = messageData.getString("localChatId");
|
String chatId = messageData.getString("localChatId");
|
||||||
StatusChat chat = chats.get(chatId);
|
StatusChat chat = chats.get(chatId);
|
||||||
if (chat == null) {
|
if (chat == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusMessage message = createMessage(messageData);
|
StatusMessage message = createMessage(messageData);
|
||||||
if (message != null) {
|
if (message != null) {
|
||||||
chat.appendMessage(message);
|
chat.appendMessage(message);
|
||||||
chats.put(chatId, chat);
|
chats.put(chatId, chat);
|
||||||
shouldRefreshNotifications = true;
|
shouldRefreshNotifications = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (JSONException e) {
|
catch (JSONException e) {
|
||||||
Log.e(TAG, "JSON conversion failed: " + e.getMessage());
|
Log.e(TAG, "JSON conversion failed: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private StatusMessage createMessage(JSONObject messageData) {
|
private StatusMessage createMessage(JSONObject messageData) {
|
||||||
try {
|
try {
|
||||||
Person author = getPerson(messageData.getString("from"), messageData.getString("identicon"), messageData.getString("alias"));
|
Person author = getPerson(messageData.getString("from"), messageData.getString("identicon"), messageData.getString("alias"));
|
||||||
return new StatusMessage(author, messageData.getLong("whisperTimestamp"), messageData.getString("text"));
|
return new StatusMessage(author, messageData.getLong("whisperTimestamp"), messageData.getString("text"));
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
Log.e(TAG, "JSON conversion failed: " + e.getMessage());
|
Log.e(TAG, "JSON conversion failed: " + e.getMessage());
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,22 +339,22 @@ class StatusChat {
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
|
||||||
//TODO this should be improved as it would rename the chat
|
//TODO this should be improved as it would rename the chat
|
||||||
// after our own user if we were posting from another device
|
// after our own user if we were posting from another device
|
||||||
// in 1-1 chats it should be the name of the user whose
|
// in 1-1 chats it should be the name of the user whose
|
||||||
// key is different than ours
|
// key is different than ours
|
||||||
StatusMessage message = getLastMessage();
|
StatusMessage message = getLastMessage();
|
||||||
if (message == null) {
|
if (message == null) {
|
||||||
return "no-name";
|
return "no-name";
|
||||||
}
|
}
|
||||||
return message.getAuthor().getName().toString();
|
return message.getAuthor().getName().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private StatusMessage getLastMessage() {
|
private StatusMessage getLastMessage() {
|
||||||
if (messages.size() > 0) {
|
if (messages.size() > 0) {
|
||||||
return messages.get(messages.size()-1);
|
return messages.get(messages.size()-1);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getTimestamp() {
|
public long getTimestamp() {
|
||||||
|
@ -294,7 +366,7 @@ class StatusChat {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void appendMessage(StatusMessage message) {
|
public void appendMessage(StatusMessage message) {
|
||||||
this.messages.add(message);
|
this.messages.add(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSummary() {
|
public String getSummary() {
|
||||||
|
|
|
@ -69,6 +69,7 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
|
||||||
private ReactApplicationContext reactContext;
|
private ReactApplicationContext reactContext;
|
||||||
private boolean rootedDevice;
|
private boolean rootedDevice;
|
||||||
private NewMessageSignalHandler newMessageSignalHandler;
|
private NewMessageSignalHandler newMessageSignalHandler;
|
||||||
|
private boolean background;
|
||||||
|
|
||||||
StatusModule(ReactApplicationContext reactContext, boolean rootedDevice) {
|
StatusModule(ReactApplicationContext reactContext, boolean rootedDevice) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
|
@ -85,17 +86,18 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
|
||||||
@Override
|
@Override
|
||||||
public void onHostResume() { // Activity `onResume`
|
public void onHostResume() { // Activity `onResume`
|
||||||
module = this;
|
module = this;
|
||||||
|
this.background = false;
|
||||||
Statusgo.setMobileSignalHandler(this);
|
Statusgo.setMobileSignalHandler(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onHostPause() {
|
public void onHostPause() {
|
||||||
|
this.background = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onHostDestroy() {
|
public void onHostDestroy() {
|
||||||
Intent intent = new Intent(getReactApplicationContext(), ForegroundService.class);
|
Log.d(TAG, "******************* ON HOST DESTROY *************************");
|
||||||
getReactApplicationContext().stopService(intent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactMethod
|
@ReactMethod
|
||||||
|
@ -145,7 +147,7 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
|
||||||
Log.d(TAG, "Signal event: " + jsonEventString);
|
Log.d(TAG, "Signal event: " + jsonEventString);
|
||||||
// NOTE: the newMessageSignalHandler is only instanciated if the user
|
// NOTE: the newMessageSignalHandler is only instanciated if the user
|
||||||
// enabled notifications in the app
|
// enabled notifications in the app
|
||||||
if (newMessageSignalHandler != null) {
|
if (this.background && newMessageSignalHandler != null) {
|
||||||
if (eventType.equals("messages.new")) {
|
if (eventType.equals("messages.new")) {
|
||||||
newMessageSignalHandler.handleNewMessageSignal(jsonEvent);
|
newMessageSignalHandler.handleNewMessageSignal(jsonEvent);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
;; TODO(yenda) investigate why `handle-universal-link` event is
|
;; TODO(yenda) investigate why `handle-universal-link` event is
|
||||||
;; dispatched 7 times for the same link
|
;; dispatched 7 times for the same link
|
||||||
|
|
||||||
|
(def private-chat-regex #".*/chat/private/(.*)$")
|
||||||
(def public-chat-regex #"(?:https?://join\.)?status[.-]im(?::/)?/(?:chat/public/([a-z0-9\-]+)$|([a-z0-9\-]+))$")
|
(def public-chat-regex #"(?:https?://join\.)?status[.-]im(?::/)?/(?:chat/public/([a-z0-9\-]+)$|([a-z0-9\-]+))$")
|
||||||
(def profile-regex #"(?:https?://join\.)?status[.-]im(?::/)?/(?:u/(0x.*)$|u/(.*)$|user/(.*))$")
|
(def profile-regex #"(?:https?://join\.)?status[.-]im(?::/)?/(?:u/(0x.*)$|u/(.*)$|user/(.*))$")
|
||||||
(def browse-regex #"(?:https?://join\.)?status[.-]im(?::/)?/(?:b/(.*)$|browse/(.*))$")
|
(def browse-regex #"(?:https?://join\.)?status[.-]im(?::/)?/(?:b/(.*)$|browse/(.*))$")
|
||||||
|
@ -30,6 +31,7 @@
|
||||||
:internal "status-im:/"})
|
:internal "status-im:/"})
|
||||||
|
|
||||||
(def links {:public-chat "%s/%s"
|
(def links {:public-chat "%s/%s"
|
||||||
|
:private-chat "%s/p/%s"
|
||||||
:user "%s/u/%s"
|
:user "%s/u/%s"
|
||||||
:browse "%s/b/%s"})
|
:browse "%s/b/%s"})
|
||||||
|
|
||||||
|
@ -71,6 +73,10 @@
|
||||||
(when (security/safe-link? url)
|
(when (security/safe-link? url)
|
||||||
{:browser/show-browser-selection url}))
|
{:browser/show-browser-selection url}))
|
||||||
|
|
||||||
|
(fx/defn handle-private-chat [cofx chat-id]
|
||||||
|
(log/info "universal-links: handling private chat" chat-id)
|
||||||
|
(chat/start-chat cofx chat-id {}))
|
||||||
|
|
||||||
(fx/defn handle-public-chat [cofx public-chat]
|
(fx/defn handle-public-chat [cofx public-chat]
|
||||||
(log/info "universal-links: handling public chat" public-chat)
|
(log/info "universal-links: handling public chat" public-chat)
|
||||||
(chat/start-public-chat cofx public-chat {}))
|
(chat/start-public-chat cofx public-chat {}))
|
||||||
|
@ -120,6 +126,9 @@
|
||||||
[cofx url]
|
[cofx url]
|
||||||
(cond
|
(cond
|
||||||
|
|
||||||
|
(match-url url private-chat-regex)
|
||||||
|
(handle-private-chat cofx (match-url url private-chat-regex))
|
||||||
|
|
||||||
(spec/valid? :global/public-key (match-url url profile-regex))
|
(spec/valid? :global/public-key (match-url url profile-regex))
|
||||||
(handle-view-profile cofx {:public-key (match-url url profile-regex)})
|
(handle-view-profile cofx {:public-key (match-url url profile-regex)})
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue