forked from Ivasoft/mattermost-mobile
[Gekidou] Update dependencies (#5581)
* Update detox deps * Push notifications (android & launcher) * Update dependencies
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
package com.mattermost.helpers;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
@@ -20,4 +22,27 @@ public class Credentials {
|
||||
|
||||
keychainModule.getGenericPasswordForOptions(options, promise);
|
||||
}
|
||||
|
||||
public static String getCredentialsForServerSync(ReactApplicationContext context, String serverUrl) {
|
||||
final String[] token = new String[1];
|
||||
Credentials.getCredentialsForServer(context, serverUrl, new ResolvePromise() {
|
||||
@Override
|
||||
public void resolve(@Nullable Object value) {
|
||||
WritableMap map = (WritableMap) value;
|
||||
if (map != null) {
|
||||
token[0] = map.getString("password");
|
||||
String service = map.getString("service");
|
||||
assert service != null;
|
||||
if (service.isEmpty()) {
|
||||
String[] credentials = token[0].split(",[ ]*");
|
||||
if (credentials.length == 2) {
|
||||
token[0] = credentials[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return token[0];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,461 @@
|
||||
package com.mattermost.helpers;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
import androidx.core.app.Person;
|
||||
import androidx.core.app.RemoteInput;
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.mattermost.rnbeta.NotificationDismissService;
|
||||
import com.mattermost.rnbeta.NotificationPreferences;
|
||||
import com.mattermost.rnbeta.NotificationReplyBroadcastReceiver;
|
||||
import com.mattermost.rnbeta.R;
|
||||
import com.wix.reactnativenotifications.core.NotificationIntentAdapter;
|
||||
import com.wix.reactnativenotifications.core.notification.PushNotificationProps;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class CustomPushNotificationHelper {
|
||||
public static final String CHANNEL_HIGH_IMPORTANCE_ID = "channel_01";
|
||||
public static final String CHANNEL_MIN_IMPORTANCE_ID = "channel_02";
|
||||
public static final String KEY_TEXT_REPLY = "CAN_REPLY";
|
||||
public static final int MESSAGE_NOTIFICATION_ID = 435345;
|
||||
public static final String NOTIFICATION_ID = "notificationId";
|
||||
public static final String NOTIFICATION = "notification";
|
||||
|
||||
private static NotificationChannel mHighImportanceChannel;
|
||||
private static NotificationChannel mMinImportanceChannel;
|
||||
|
||||
private static void addMessagingStyleMessages(Context context, NotificationCompat.MessagingStyle messagingStyle, String conversationTitle, Bundle bundle) {
|
||||
String message = bundle.getString("message", bundle.getString("body"));
|
||||
String senderId = bundle.getString("sender_id");
|
||||
String serverUrl = bundle.getString("server_url");
|
||||
if (senderId == null) {
|
||||
senderId = "sender_id";
|
||||
}
|
||||
Bundle userInfoBundle = bundle.getBundle("userInfo");
|
||||
String senderName = getSenderName(bundle);
|
||||
if (userInfoBundle != null) {
|
||||
boolean localPushNotificationTest = userInfoBundle.getBoolean("test");
|
||||
if (localPushNotificationTest) {
|
||||
senderName = "Test";
|
||||
}
|
||||
}
|
||||
|
||||
if (conversationTitle == null || !android.text.TextUtils.isEmpty(senderName.trim())) {
|
||||
message = removeSenderNameFromMessage(message, senderName);
|
||||
}
|
||||
|
||||
long timestamp = new Date().getTime();
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
|
||||
messagingStyle.addMessage(message, timestamp, senderName);
|
||||
} else {
|
||||
Person.Builder sender = new Person.Builder()
|
||||
.setKey(senderId)
|
||||
.setName(senderName);
|
||||
|
||||
if (serverUrl != null) {
|
||||
try {
|
||||
sender.setIcon(IconCompat.createWithBitmap(Objects.requireNonNull(userAvatar(context, serverUrl, senderId))));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// if (serverUrl == null) {
|
||||
message = "Unknown Server\n" + message;
|
||||
// }
|
||||
|
||||
messagingStyle.addMessage(message, timestamp, sender.build());
|
||||
}
|
||||
}
|
||||
|
||||
private static void addNotificationExtras(NotificationCompat.Builder notification, Bundle bundle) {
|
||||
Bundle userInfoBundle = bundle.getBundle("userInfo");
|
||||
if (userInfoBundle == null) {
|
||||
userInfoBundle = new Bundle();
|
||||
}
|
||||
|
||||
String channelId = bundle.getString("channel_id");
|
||||
if (channelId != null) {
|
||||
userInfoBundle.putString("channel_id", channelId);
|
||||
}
|
||||
|
||||
notification.addExtras(userInfoBundle);
|
||||
}
|
||||
|
||||
private static void addNotificationReplyAction(Context context, NotificationCompat.Builder notification, Bundle bundle, int notificationId) {
|
||||
String postId = bundle.getString("post_id");
|
||||
String serverUrl = bundle.getString("server_url");
|
||||
|
||||
if (android.text.TextUtils.isEmpty(postId) || serverUrl == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Intent replyIntent = new Intent(context, NotificationReplyBroadcastReceiver.class);
|
||||
replyIntent.setAction(KEY_TEXT_REPLY);
|
||||
replyIntent.putExtra(NOTIFICATION_ID, notificationId);
|
||||
replyIntent.putExtra(NOTIFICATION, bundle);
|
||||
|
||||
PendingIntent replyPendingIntent = PendingIntent.getBroadcast(
|
||||
context,
|
||||
notificationId,
|
||||
replyIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY)
|
||||
.setLabel("Reply")
|
||||
.build();
|
||||
|
||||
int icon = R.drawable.ic_notif_action_reply;
|
||||
CharSequence title = "Reply";
|
||||
NotificationCompat.Action replyAction = new NotificationCompat.Action.Builder(icon, title, replyPendingIntent)
|
||||
.addRemoteInput(remoteInput)
|
||||
.setAllowGeneratedReplies(true)
|
||||
.build();
|
||||
|
||||
notification
|
||||
.setShowWhen(true)
|
||||
.addAction(replyAction);
|
||||
}
|
||||
|
||||
public static NotificationCompat.Builder createNotificationBuilder(Context context, PendingIntent intent, Bundle bundle, boolean createSummary) {
|
||||
final NotificationCompat.Builder notification = new NotificationCompat.Builder(context, CHANNEL_HIGH_IMPORTANCE_ID);
|
||||
|
||||
String channelId = bundle.getString("channel_id");
|
||||
String postId = bundle.getString("post_id");
|
||||
int notificationId = postId != null ? postId.hashCode() : MESSAGE_NOTIFICATION_ID;
|
||||
NotificationPreferences notificationPreferences = NotificationPreferences.getInstance(context);
|
||||
|
||||
addNotificationExtras(notification, bundle);
|
||||
setNotificationIcons(context, notification, bundle);
|
||||
setNotificationMessagingStyle(context, notification, bundle);
|
||||
setNotificationGroup(notification, channelId, createSummary);
|
||||
setNotificationBadgeType(notification);
|
||||
setNotificationSound(notification, notificationPreferences);
|
||||
setNotificationVibrate(notification, notificationPreferences);
|
||||
setNotificationBlink(notification, notificationPreferences);
|
||||
|
||||
setNotificationChannel(notification, bundle);
|
||||
setNotificationDeleteIntent(context, notification, bundle, notificationId);
|
||||
addNotificationReplyAction(context, notification, bundle, notificationId);
|
||||
|
||||
notification
|
||||
.setContentIntent(intent)
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PRIVATE)
|
||||
.setPriority(Notification.PRIORITY_HIGH)
|
||||
.setCategory(Notification.CATEGORY_MESSAGE)
|
||||
.setAutoCancel(true);
|
||||
|
||||
return notification;
|
||||
}
|
||||
|
||||
public static void createNotificationChannels(Context context) {
|
||||
// Notification channels are not supported in Android Nougat and below
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
return;
|
||||
}
|
||||
|
||||
final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
|
||||
|
||||
if (mHighImportanceChannel == null) {
|
||||
mHighImportanceChannel = new NotificationChannel(CHANNEL_HIGH_IMPORTANCE_ID, "High Importance", NotificationManager.IMPORTANCE_HIGH);
|
||||
mHighImportanceChannel.setShowBadge(true);
|
||||
notificationManager.createNotificationChannel(mHighImportanceChannel);
|
||||
}
|
||||
|
||||
if (mMinImportanceChannel == null) {
|
||||
mMinImportanceChannel = new NotificationChannel(CHANNEL_MIN_IMPORTANCE_ID, "Min Importance", NotificationManager.IMPORTANCE_MIN);
|
||||
mMinImportanceChannel.setShowBadge(true);
|
||||
notificationManager.createNotificationChannel(mMinImportanceChannel);
|
||||
}
|
||||
}
|
||||
|
||||
private static Bitmap getCircleBitmap(Bitmap bitmap) {
|
||||
final Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
|
||||
bitmap.getHeight(), Bitmap.Config.ARGB_8888);
|
||||
final Canvas canvas = new Canvas(output);
|
||||
|
||||
final int color = Color.RED;
|
||||
final Paint paint = new Paint();
|
||||
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
|
||||
final RectF rectF = new RectF(rect);
|
||||
|
||||
paint.setAntiAlias(true);
|
||||
canvas.drawARGB(0, 0, 0, 0);
|
||||
paint.setColor(color);
|
||||
canvas.drawOval(rectF, paint);
|
||||
|
||||
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
|
||||
canvas.drawBitmap(bitmap, rect, rect, paint);
|
||||
|
||||
bitmap.recycle();
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
private static String getConversationTitle(Bundle bundle) {
|
||||
String title = bundle.getString("channel_name");
|
||||
|
||||
if (android.text.TextUtils.isEmpty(title)) {
|
||||
title = bundle.getString("sender_name");
|
||||
}
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
private static int getIconResourceId(Context context, String iconName) {
|
||||
final Resources res = context.getResources();
|
||||
String packageName = context.getPackageName();
|
||||
String defType = "mipmap";
|
||||
|
||||
return res.getIdentifier(iconName, defType, packageName);
|
||||
}
|
||||
|
||||
private static NotificationCompat.MessagingStyle getMessagingStyle(Context context, Bundle bundle) {
|
||||
NotificationCompat.MessagingStyle messagingStyle;
|
||||
String senderId = "me";
|
||||
final String serverUrl = bundle.getString("server_url");
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
|
||||
messagingStyle = new NotificationCompat.MessagingStyle("Me");
|
||||
} else {
|
||||
Person.Builder sender = new Person.Builder()
|
||||
.setKey(senderId)
|
||||
.setName("Me");
|
||||
|
||||
if (serverUrl != null) {
|
||||
try {
|
||||
sender.setIcon(IconCompat.createWithBitmap(Objects.requireNonNull(userAvatar(context, serverUrl, "me"))));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
messagingStyle = new NotificationCompat.MessagingStyle(sender.build());
|
||||
}
|
||||
|
||||
String conversationTitle = getConversationTitle(bundle);
|
||||
setMessagingStyleConversationTitle(messagingStyle, conversationTitle, bundle);
|
||||
addMessagingStyleMessages(context, messagingStyle, conversationTitle, bundle);
|
||||
|
||||
return messagingStyle;
|
||||
}
|
||||
|
||||
private static String getSenderName(Bundle bundle) {
|
||||
String senderName = bundle.getString("sender_name");
|
||||
if (senderName != null) {
|
||||
return senderName;
|
||||
}
|
||||
|
||||
String channelName = bundle.getString("channel_name");
|
||||
if (channelName != null && channelName.startsWith("@")) {
|
||||
return channelName;
|
||||
}
|
||||
|
||||
String message = bundle.getString("message");
|
||||
if (message != null) {
|
||||
String name = message.split(":")[0];
|
||||
if (!name.equals(message)) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
return getConversationTitle(bundle);
|
||||
}
|
||||
|
||||
public static int getSmallIconResourceId(Context context, String iconName) {
|
||||
if (iconName == null) {
|
||||
iconName = "ic_notification";
|
||||
}
|
||||
|
||||
int resourceId = getIconResourceId(context, iconName);
|
||||
|
||||
if (resourceId == 0) {
|
||||
iconName = "ic_launcher";
|
||||
resourceId = getIconResourceId(context, iconName);
|
||||
|
||||
if (resourceId == 0) {
|
||||
resourceId = android.R.drawable.ic_dialog_info;
|
||||
}
|
||||
}
|
||||
|
||||
return resourceId;
|
||||
}
|
||||
|
||||
private static String removeSenderNameFromMessage(String message, String senderName) {
|
||||
int index = message.indexOf(senderName);
|
||||
if (index == 0) {
|
||||
message = message.substring(senderName.length());
|
||||
}
|
||||
|
||||
return message.replaceFirst(": ", "").trim();
|
||||
}
|
||||
|
||||
private static void setMessagingStyleConversationTitle(NotificationCompat.MessagingStyle messagingStyle, String conversationTitle, Bundle bundle) {
|
||||
String channelName = getConversationTitle(bundle);
|
||||
String senderName = bundle.getString("sender_name");
|
||||
if (TextUtils.isEmpty(senderName)) {
|
||||
senderName = getSenderName(bundle);
|
||||
}
|
||||
|
||||
if (conversationTitle != null && !channelName.equals(senderName)) {
|
||||
messagingStyle.setConversationTitle(conversationTitle);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
messagingStyle.setGroupConversation(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void setNotificationBadgeType(NotificationCompat.Builder notification) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
notification.setBadgeIconType(NotificationCompat.BADGE_ICON_LARGE);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setNotificationBlink(NotificationCompat.Builder notification, NotificationPreferences notificationPreferences) {
|
||||
boolean blink = notificationPreferences.getShouldBlink();
|
||||
if (blink) {
|
||||
notification.setLights(Color.CYAN, 500, 500);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setNotificationChannel(NotificationCompat.Builder notification, Bundle bundle) {
|
||||
// If Android Oreo or above we need to register a channel
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
return;
|
||||
}
|
||||
|
||||
NotificationChannel notificationChannel = mHighImportanceChannel;
|
||||
|
||||
boolean testNotification = false;
|
||||
boolean localNotification = false;
|
||||
Bundle userInfoBundle = bundle.getBundle("userInfo");
|
||||
if (userInfoBundle != null) {
|
||||
testNotification = userInfoBundle.getBoolean("test");
|
||||
localNotification = userInfoBundle.getBoolean("local");
|
||||
}
|
||||
|
||||
if (testNotification || localNotification) {
|
||||
notificationChannel = mMinImportanceChannel;
|
||||
}
|
||||
|
||||
notification.setChannelId(notificationChannel.getId());
|
||||
}
|
||||
|
||||
private static void setNotificationDeleteIntent(Context context, NotificationCompat.Builder notification, Bundle bundle, int notificationId) {
|
||||
// Let's add a delete intent when the notification is dismissed
|
||||
Intent delIntent = new Intent(context, NotificationDismissService.class);
|
||||
PushNotificationProps notificationProps = new PushNotificationProps(bundle);
|
||||
delIntent.putExtra(NOTIFICATION_ID, notificationId);
|
||||
PendingIntent deleteIntent = NotificationIntentAdapter.createPendingNotificationIntent(context, delIntent, notificationProps);
|
||||
notification.setDeleteIntent(deleteIntent);
|
||||
}
|
||||
|
||||
private static void setNotificationMessagingStyle(Context context, NotificationCompat.Builder notification, Bundle bundle) {
|
||||
NotificationCompat.MessagingStyle messagingStyle = getMessagingStyle(context, bundle);
|
||||
notification.setStyle(messagingStyle);
|
||||
}
|
||||
|
||||
private static void setNotificationGroup(NotificationCompat.Builder notification, String channelId, boolean setAsSummary) {
|
||||
notification.setGroup(channelId);
|
||||
|
||||
if (setAsSummary) {
|
||||
// if this is the first notification for the channel then set as summary, otherwise skip
|
||||
notification.setGroupSummary(true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setNotificationIcons(Context context, NotificationCompat.Builder notification, Bundle bundle) {
|
||||
String smallIcon = bundle.getString("smallIcon");
|
||||
String channelName = getConversationTitle(bundle);
|
||||
String senderName = bundle.getString("sender_name");
|
||||
String serverUrl = bundle.getString("server_url");
|
||||
|
||||
int smallIconResId = getSmallIconResourceId(context, smallIcon);
|
||||
notification.setSmallIcon(smallIconResId);
|
||||
|
||||
if (serverUrl != null && channelName.equals(senderName)) {
|
||||
try {
|
||||
String senderId = bundle.getString("sender_id");
|
||||
notification.setLargeIcon(userAvatar(context, serverUrl, senderId));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void setNotificationSound(NotificationCompat.Builder notification, NotificationPreferences notificationPreferences) {
|
||||
String soundUri = notificationPreferences.getNotificationSound();
|
||||
if (soundUri != null) {
|
||||
if (!soundUri.equals("none")) {
|
||||
notification.setSound(Uri.parse(soundUri));
|
||||
}
|
||||
} else {
|
||||
Uri defaultUri = Settings.System.DEFAULT_NOTIFICATION_URI;
|
||||
notification.setSound(defaultUri);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setNotificationVibrate(NotificationCompat.Builder notification, NotificationPreferences notificationPreferences) {
|
||||
boolean vibrate = notificationPreferences.getShouldVibrate();
|
||||
if (vibrate) {
|
||||
// Use the system default for vibration
|
||||
notification.setDefaults(Notification.DEFAULT_VIBRATE);
|
||||
}
|
||||
}
|
||||
|
||||
private static Bitmap userAvatar(Context context, final String serverUrl, final String userId) throws IOException {
|
||||
final ReactApplicationContext reactApplicationContext = new ReactApplicationContext(context);
|
||||
final String token = Credentials.getCredentialsForServerSync(reactApplicationContext, serverUrl);
|
||||
|
||||
final OkHttpClient client = new OkHttpClient();
|
||||
final String url = String.format("%s/api/v4/users/%s/image", serverUrl, userId);
|
||||
Request request = new Request.Builder()
|
||||
.header("Authorization", String.format("Bearer %s", token))
|
||||
.url(url)
|
||||
.build();
|
||||
Response response = client.newCall(request).execute();
|
||||
if (response.code() == 200) {
|
||||
assert response.body() != null;
|
||||
byte[] bytes = Objects.requireNonNull(response.body()).bytes();
|
||||
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
|
||||
|
||||
Log.i("ReactNative", String.format("Fetch profile %s", url));
|
||||
return getCircleBitmap(bitmap);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,114 +1,109 @@
|
||||
package com.mattermost.rnbeta;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Person;
|
||||
import android.app.RemoteInput;
|
||||
import android.content.Intent;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.media.AudioManager;
|
||||
import android.net.Uri;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.os.Build;
|
||||
import android.provider.Settings.System;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.mattermost.helpers.CustomPushNotificationHelper;
|
||||
import com.mattermost.helpers.DatabaseHelper;
|
||||
import com.mattermost.helpers.ResolvePromise;
|
||||
import com.wix.reactnativenotifications.core.notification.PushNotification;
|
||||
import com.wix.reactnativenotifications.core.NotificationIntentAdapter;
|
||||
import com.wix.reactnativenotifications.core.ProxyService;
|
||||
import com.wix.reactnativenotifications.core.notification.PushNotification;
|
||||
import com.wix.reactnativenotifications.core.AppLaunchHelper;
|
||||
import com.wix.reactnativenotifications.core.AppLifecycleFacade;
|
||||
import com.wix.reactnativenotifications.core.JsIOHelper;
|
||||
|
||||
import static com.wix.reactnativenotifications.Defs.NOTIFICATION_RECEIVED_EVENT_NAME;
|
||||
|
||||
public class CustomPushNotification extends PushNotification {
|
||||
public static final int MESSAGE_NOTIFICATION_ID = 435345;
|
||||
public static final String GROUP_KEY_MESSAGES = "mm_group_key_messages";
|
||||
public static final String NOTIFICATION = "notification";
|
||||
public static final String NOTIFICATION_ID = "notificationId";
|
||||
public static final String KEY_TEXT_REPLY = "CAN_REPLY";
|
||||
public static final String NOTIFICATION_REPLIED_EVENT_NAME = "notificationReplied";
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class CustomPushNotification extends PushNotification {
|
||||
private static final String PUSH_NOTIFICATIONS = "PUSH_NOTIFICATIONS";
|
||||
private static final String PUSH_TYPE_MESSAGE = "message";
|
||||
private static final String PUSH_TYPE_CLEAR = "clear";
|
||||
private static final String PUSH_TYPE_SESSION = "session";
|
||||
private static final String PUSH_TYPE_UPDATE_BADGE = "update_badge";
|
||||
|
||||
private NotificationChannel mHighImportanceChannel;
|
||||
private NotificationChannel mMinImportanceChannel;
|
||||
|
||||
private static Map<String, Integer> channelIdToNotificationCount = new HashMap<String, Integer>();
|
||||
private static Map<String, List<Bundle>> channelIdToNotification = new HashMap<String, List<Bundle>>();
|
||||
private static AppLifecycleFacade lifecycleFacade;
|
||||
private static Context context;
|
||||
private static int badgeCount = 0;
|
||||
private static final String NOTIFICATIONS_IN_CHANNEL = "notificationsInChannel";
|
||||
|
||||
public CustomPushNotification(Context context, Bundle bundle, AppLifecycleFacade appLifecycleFacade, AppLaunchHelper appLaunchHelper, JsIOHelper jsIoHelper) {
|
||||
super(context, bundle, appLifecycleFacade, appLaunchHelper, jsIoHelper);
|
||||
this.context = context;
|
||||
|
||||
createNotificationChannels();
|
||||
CustomPushNotificationHelper.createNotificationChannels(context);
|
||||
}
|
||||
|
||||
public static void clearNotification(Context mContext, int notificationId, String channelId) {
|
||||
if (notificationId != -1) {
|
||||
Integer count = channelIdToNotificationCount.get(channelId);
|
||||
if (count == null) {
|
||||
count = -1;
|
||||
public static void cancelNotification(Context context, String channelId, Integer notificationId) {
|
||||
if (!android.text.TextUtils.isEmpty(channelId)) {
|
||||
Map<String, List<Integer>> notificationsInChannel = loadNotificationsMap(context);
|
||||
List<Integer> notifications = notificationsInChannel.get(channelId);
|
||||
if (notifications == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
channelIdToNotificationCount.remove(channelId);
|
||||
channelIdToNotification.remove(channelId);
|
||||
notifications.remove(notificationId);
|
||||
saveNotificationsMap(context, notificationsInChannel);
|
||||
final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
|
||||
notificationManager.cancel(notificationId);
|
||||
}
|
||||
}
|
||||
|
||||
if (mContext != null) {
|
||||
final NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
public static void clearChannelNotifications(Context context, String channelId) {
|
||||
if (!android.text.TextUtils.isEmpty(channelId)) {
|
||||
Map<String, List<Integer>> notificationsInChannel = loadNotificationsMap(context);
|
||||
List<Integer> notifications = notificationsInChannel.get(channelId);
|
||||
if (notifications == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
notificationsInChannel.remove(channelId);
|
||||
saveNotificationsMap(context, notificationsInChannel);
|
||||
|
||||
for (final Integer notificationId : notifications) {
|
||||
final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
|
||||
notificationManager.cancel(notificationId);
|
||||
|
||||
if (count != -1) {
|
||||
int total = CustomPushNotification.badgeCount - count;
|
||||
int badgeCount = total < 0 ? 0 : total;
|
||||
CustomPushNotification.badgeCount = badgeCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void clearAllNotifications(Context mContext) {
|
||||
channelIdToNotificationCount.clear();
|
||||
channelIdToNotification.clear();
|
||||
if (mContext != null) {
|
||||
final NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
public static void clearAllNotifications(Context context) {
|
||||
if (context != null) {
|
||||
Map<String, List<Integer>> notificationsInChannel = loadNotificationsMap(context);
|
||||
notificationsInChannel.clear();
|
||||
saveNotificationsMap(context, notificationsInChannel);
|
||||
final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
|
||||
notificationManager.cancelAll();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceived() throws InvalidNotificationException {
|
||||
public void onReceived() {
|
||||
final Bundle initialData = mNotificationProps.asBundle();
|
||||
final String type = initialData.getString("type");
|
||||
final String ackId = initialData.getString("ack_id");
|
||||
final String postId = initialData.getString("post_id");
|
||||
final String channelId = initialData.getString("channel_id");
|
||||
final boolean isIdLoaded = initialData.getString("id_loaded") != null ? initialData.getString("id_loaded").equals("true") : false;
|
||||
int notificationId = MESSAGE_NOTIFICATION_ID;
|
||||
final boolean isIdLoaded = initialData.getString("id_loaded") != null && initialData.getString("id_loaded").equals("true");
|
||||
int notificationId = CustomPushNotificationHelper.MESSAGE_NOTIFICATION_ID;
|
||||
if (postId != null) {
|
||||
notificationId = postId.hashCode();
|
||||
} else if (channelId != null) {
|
||||
notificationId = channelId.hashCode();
|
||||
}
|
||||
|
||||
String serverUrl = initialData.getString("server_url", DatabaseHelper.getOnlyServerUrl(context));
|
||||
String serverUrl = addServerUrlToBundle(initialData);
|
||||
|
||||
if (ackId != null && serverUrl != null) {
|
||||
notificationReceiptDelivery(ackId, serverUrl, postId, type, isIdLoaded, new ResolvePromise() {
|
||||
@@ -116,7 +111,7 @@ public class CustomPushNotification extends PushNotification {
|
||||
public void resolve(@Nullable Object value) {
|
||||
if (isIdLoaded) {
|
||||
Bundle response = (Bundle) value;
|
||||
mNotificationProps = createProps(response);
|
||||
addServerUrlToBundle(response);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,54 +122,42 @@ public class CustomPushNotification extends PushNotification {
|
||||
});
|
||||
}
|
||||
|
||||
// notificationReceiptDelivery can override mNotificationProps
|
||||
// so we fetch the bundle again
|
||||
final Bundle data = mNotificationProps.asBundle();
|
||||
switch (type) {
|
||||
case PUSH_TYPE_MESSAGE:
|
||||
case PUSH_TYPE_SESSION:
|
||||
boolean createSummary = type.equals(PUSH_TYPE_MESSAGE);
|
||||
if (!mAppLifecycleFacade.isAppVisible()) {
|
||||
if (type.equals(PUSH_TYPE_MESSAGE)) {
|
||||
if (channelId != null) {
|
||||
Map<String, List<Integer>> notificationsInChannel = loadNotificationsMap(mContext);
|
||||
List<Integer> list = notificationsInChannel.get(channelId);
|
||||
if (list == null) {
|
||||
list = Collections.synchronizedList(new ArrayList(0));
|
||||
}
|
||||
|
||||
if (serverUrl == null) {
|
||||
String message = data.getString("message");
|
||||
data.putString("message", "Unknown Server\n" + message);
|
||||
}
|
||||
list.add(0, notificationId);
|
||||
if (list.size() > 1) {
|
||||
createSummary = false;
|
||||
}
|
||||
|
||||
if (channelId != null) {
|
||||
notificationId = channelId.hashCode();
|
||||
if (createSummary) {
|
||||
// Add the summary notification id as well
|
||||
list.add(0, notificationId + 1);
|
||||
}
|
||||
|
||||
synchronized (channelIdToNotificationCount) {
|
||||
Integer count = channelIdToNotificationCount.get(channelId);
|
||||
if (count == null) {
|
||||
count = 0;
|
||||
notificationsInChannel.put(channelId, list);
|
||||
saveNotificationsMap(mContext, notificationsInChannel);
|
||||
}
|
||||
}
|
||||
|
||||
buildNotification(notificationId, createSummary);
|
||||
} else {
|
||||
notifyReceivedToJS();
|
||||
}
|
||||
|
||||
count += 1;
|
||||
|
||||
channelIdToNotificationCount.put(channelId, count);
|
||||
}
|
||||
|
||||
synchronized (channelIdToNotification) {
|
||||
List<Bundle> list = channelIdToNotification.get(channelId);
|
||||
if (list == null) {
|
||||
list = Collections.synchronizedList(new ArrayList(0));
|
||||
}
|
||||
|
||||
if (PUSH_TYPE_MESSAGE.equals(type)) {
|
||||
String senderName = getSenderName(data);
|
||||
data.putLong("time", new Date().getTime());
|
||||
data.putString("sender_name", senderName);
|
||||
data.putString("sender_id", data.getString("sender_id"));
|
||||
}
|
||||
list.add(0, data);
|
||||
channelIdToNotification.put(channelId, list);
|
||||
}
|
||||
}
|
||||
|
||||
switch(type) {
|
||||
case PUSH_TYPE_MESSAGE:
|
||||
case PUSH_TYPE_SESSION:
|
||||
super.postNotification(notificationId);
|
||||
break;
|
||||
case PUSH_TYPE_CLEAR:
|
||||
cancelNotification(data, notificationId);
|
||||
break;
|
||||
break;
|
||||
case PUSH_TYPE_CLEAR:
|
||||
clearChannelNotifications(mContext, channelId);
|
||||
break;
|
||||
}
|
||||
|
||||
if (mAppLifecycleFacade.isReactInitialized()) {
|
||||
@@ -184,392 +167,102 @@ public class CustomPushNotification extends PushNotification {
|
||||
|
||||
@Override
|
||||
public void onOpened() {
|
||||
digestNotification();
|
||||
|
||||
Bundle data = mNotificationProps.asBundle();
|
||||
final String channelId = data.getString("channel_id");
|
||||
if (channelId != null) {
|
||||
channelIdToNotificationCount.remove(channelId);
|
||||
channelIdToNotification.remove(channelId);
|
||||
final String postId = data.getString("post_id");
|
||||
Integer notificationId = CustomPushNotificationHelper.MESSAGE_NOTIFICATION_ID;
|
||||
|
||||
if (postId != null) {
|
||||
notificationId = postId.hashCode();
|
||||
}
|
||||
digestNotification();
|
||||
|
||||
if (channelId != null) {
|
||||
Map<String, List<Integer>> notificationsInChannel = loadNotificationsMap(mContext);
|
||||
List<Integer> notifications = notificationsInChannel.get(channelId);
|
||||
notifications.remove(notificationId);
|
||||
saveNotificationsMap(mContext, notificationsInChannel);
|
||||
clearChannelNotifications(mContext, channelId);
|
||||
}
|
||||
}
|
||||
|
||||
private void buildNotification(Integer notificationId, boolean createSummary) {
|
||||
final PendingIntent pendingIntent = super.getCTAPendingIntent();
|
||||
final Notification notification = buildNotification(pendingIntent);
|
||||
if (createSummary) {
|
||||
final Notification summary = getNotificationSummaryBuilder(pendingIntent).build();
|
||||
super.postNotification(summary, notificationId + 1);
|
||||
}
|
||||
super.postNotification(notification, notificationId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Notification.Builder getNotificationBuilder(PendingIntent intent) {
|
||||
// First, get a builder initialized with defaults from the core class.
|
||||
final Notification.Builder notification = new Notification.Builder(mContext);
|
||||
|
||||
protected NotificationCompat.Builder getNotificationBuilder(PendingIntent intent) {
|
||||
Bundle bundle = mNotificationProps.asBundle();
|
||||
|
||||
addNotificationExtras(notification, bundle);
|
||||
setNotificationIcons(notification, bundle);
|
||||
setNotificationMessagingStyle(notification, bundle);
|
||||
setNotificationChannel(notification, bundle);
|
||||
setNotificationBadgeIconType(notification);
|
||||
|
||||
NotificationPreferences notificationPreferences = NotificationPreferences.getInstance(mContext);
|
||||
setNotificationSound(notification, notificationPreferences);
|
||||
setNotificationVibrate(notification, notificationPreferences);
|
||||
setNotificationBlink(notification, notificationPreferences);
|
||||
|
||||
String channelId = bundle.getString("channel_id");
|
||||
int notificationId = channelId != null ? channelId.hashCode() : MESSAGE_NOTIFICATION_ID;
|
||||
setNotificationNumber(notification, channelId);
|
||||
setNotificationDeleteIntent(notification, notificationId);
|
||||
addNotificationReplyAction(notification, notificationId, bundle);
|
||||
|
||||
notification
|
||||
.setContentIntent(intent)
|
||||
.setVisibility(Notification.VISIBILITY_PRIVATE)
|
||||
.setPriority(Notification.PRIORITY_HIGH)
|
||||
.setAutoCancel(true);
|
||||
|
||||
return notification;
|
||||
return CustomPushNotificationHelper.createNotificationBuilder(mContext, intent, bundle, false);
|
||||
}
|
||||
|
||||
private void addNotificationExtras(Notification.Builder notification, Bundle bundle) {
|
||||
Bundle userInfoBundle = bundle.getBundle("userInfo");
|
||||
if (userInfoBundle == null) {
|
||||
userInfoBundle = new Bundle();
|
||||
}
|
||||
|
||||
String channelId = bundle.getString("channel_id");
|
||||
if (channelId != null) {
|
||||
userInfoBundle.putString("channel_id", channelId);
|
||||
}
|
||||
|
||||
notification.addExtras(userInfoBundle);
|
||||
protected NotificationCompat.Builder getNotificationSummaryBuilder(PendingIntent intent) {
|
||||
Bundle bundle = mNotificationProps.asBundle();
|
||||
return CustomPushNotificationHelper.createNotificationBuilder(mContext, intent, bundle, true);
|
||||
}
|
||||
|
||||
private void setNotificationIcons(Notification.Builder notification, Bundle bundle) {
|
||||
String smallIcon = bundle.getString("smallIcon");
|
||||
String largeIcon = bundle.getString("largeIcon");
|
||||
|
||||
int smallIconResId = getSmallIconResourceId(smallIcon);
|
||||
notification.setSmallIcon(smallIconResId);
|
||||
|
||||
int largeIconResId = getLargeIconResourceId(largeIcon);
|
||||
final Resources res = mContext.getResources();
|
||||
Bitmap largeIconBitmap = BitmapFactory.decodeResource(res, largeIconResId);
|
||||
if (largeIconResId != 0 && (largeIconBitmap != null || Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)) {
|
||||
notification.setLargeIcon(largeIconBitmap);
|
||||
}
|
||||
}
|
||||
|
||||
private int getSmallIconResourceId(String iconName) {
|
||||
if (iconName == null) {
|
||||
iconName = "ic_notification";
|
||||
}
|
||||
|
||||
int resourceId = getIconResourceId(iconName);
|
||||
|
||||
if (resourceId == 0) {
|
||||
iconName = "ic_launcher";
|
||||
resourceId = getIconResourceId(iconName);
|
||||
|
||||
if (resourceId == 0) {
|
||||
resourceId = android.R.drawable.ic_dialog_info;
|
||||
}
|
||||
}
|
||||
|
||||
return resourceId;
|
||||
}
|
||||
|
||||
private int getLargeIconResourceId(String iconName) {
|
||||
if (iconName == null) {
|
||||
iconName = "ic_launcher";
|
||||
}
|
||||
|
||||
return getIconResourceId(iconName);
|
||||
}
|
||||
|
||||
private int getIconResourceId(String iconName) {
|
||||
final Resources res = mContext.getResources();
|
||||
String packageName = mContext.getPackageName();
|
||||
String defType = "mipmap";
|
||||
|
||||
return res.getIdentifier(iconName, defType, packageName);
|
||||
}
|
||||
|
||||
private void setNotificationNumber(Notification.Builder notification, String channelId) {
|
||||
Integer number = channelIdToNotificationCount.get(channelId);
|
||||
if (number == null) {
|
||||
number = 0;
|
||||
}
|
||||
notification.setNumber(number);
|
||||
}
|
||||
|
||||
private void setNotificationMessagingStyle(Notification.Builder notification, Bundle bundle) {
|
||||
Notification.MessagingStyle messagingStyle = getMessagingStyle(bundle);
|
||||
notification.setStyle(messagingStyle);
|
||||
}
|
||||
|
||||
private Notification.MessagingStyle getMessagingStyle(Bundle bundle) {
|
||||
Notification.MessagingStyle messagingStyle;
|
||||
String senderId = bundle.getString("sender_id");
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P || senderId == null) {
|
||||
messagingStyle = new Notification.MessagingStyle("");
|
||||
} else {
|
||||
Person sender = new Person.Builder()
|
||||
.setKey(senderId)
|
||||
.setName("")
|
||||
.build();
|
||||
messagingStyle = new Notification.MessagingStyle(sender);
|
||||
}
|
||||
|
||||
String conversationTitle = getConversationTitle(bundle);
|
||||
setMessagingStyleConversationTitle(messagingStyle, conversationTitle, bundle);
|
||||
addMessagingStyleMessages(messagingStyle, conversationTitle, bundle);
|
||||
|
||||
return messagingStyle;
|
||||
}
|
||||
|
||||
private String getConversationTitle(Bundle bundle) {
|
||||
String title = null;
|
||||
|
||||
String version = bundle.getString("version");
|
||||
if (version != null && version.equals("v2")) {
|
||||
title = bundle.getString("channel_name");
|
||||
} else {
|
||||
title = bundle.getString("title");
|
||||
}
|
||||
|
||||
if (android.text.TextUtils.isEmpty(title)) {
|
||||
ApplicationInfo appInfo = mContext.getApplicationInfo();
|
||||
title = mContext.getPackageManager().getApplicationLabel(appInfo).toString();
|
||||
}
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
private void setMessagingStyleConversationTitle(Notification.MessagingStyle messagingStyle, String conversationTitle, Bundle bundle) {
|
||||
String channelName = getConversationTitle(bundle);
|
||||
String senderName = bundle.getString("sender_name");
|
||||
if (android.text.TextUtils.isEmpty(senderName)) {
|
||||
senderName = getSenderName(bundle);
|
||||
}
|
||||
|
||||
if (conversationTitle != null && (!conversationTitle.startsWith("@") || channelName != senderName)) {
|
||||
messagingStyle.setConversationTitle(conversationTitle);
|
||||
}
|
||||
}
|
||||
|
||||
private void addMessagingStyleMessages(Notification.MessagingStyle messagingStyle, String conversationTitle, Bundle bundle) {
|
||||
List<Bundle> bundleList;
|
||||
|
||||
String channelId = bundle.getString("channel_id");
|
||||
List<Bundle> bundleArray = channelIdToNotification.get(channelId);
|
||||
if (bundleArray != null) {
|
||||
bundleList = new ArrayList<Bundle>(bundleArray);
|
||||
} else {
|
||||
bundleList = new ArrayList<Bundle>();
|
||||
bundleList.add(bundle);
|
||||
}
|
||||
|
||||
int bundleCount = bundleList.size() - 1;
|
||||
for (int i = bundleCount; i >= 0; i--) {
|
||||
Bundle data = bundleList.get(i);
|
||||
String message = data.getString("message", data.getString("body"));
|
||||
String senderId = data.getString("sender_id");
|
||||
if (senderId == null) {
|
||||
senderId = "sender_id";
|
||||
}
|
||||
Bundle userInfoBundle = data.getBundle("userInfo");
|
||||
String senderName = getSenderName(data);
|
||||
if (userInfoBundle != null) {
|
||||
boolean localPushNotificationTest = userInfoBundle.getBoolean("test");
|
||||
if (localPushNotificationTest) {
|
||||
senderName = "Test";
|
||||
}
|
||||
}
|
||||
|
||||
if (conversationTitle == null || !android.text.TextUtils.isEmpty(senderName.trim())) {
|
||||
message = removeSenderNameFromMessage(message, senderName);
|
||||
}
|
||||
|
||||
long timestamp = data.getLong("time");
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
|
||||
messagingStyle.addMessage(message, timestamp, senderName);
|
||||
} else {
|
||||
Person sender = new Person.Builder()
|
||||
.setKey(senderId)
|
||||
.setName(senderName)
|
||||
.build();
|
||||
messagingStyle.addMessage(message, timestamp, sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setNotificationChannel(Notification.Builder notification, Bundle bundle) {
|
||||
// If Android Oreo or above we need to register a channel
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
return;
|
||||
}
|
||||
|
||||
NotificationChannel notificationChannel = mHighImportanceChannel;
|
||||
|
||||
boolean testNotification = false;
|
||||
boolean localNotification = false;
|
||||
Bundle userInfoBundle = bundle.getBundle("userInfo");
|
||||
if (userInfoBundle != null) {
|
||||
testNotification = userInfoBundle.getBoolean("test");
|
||||
localNotification = userInfoBundle.getBoolean("local");
|
||||
}
|
||||
|
||||
if (mAppLifecycleFacade.isAppVisible() && !testNotification && !localNotification) {
|
||||
notificationChannel = mMinImportanceChannel;
|
||||
}
|
||||
|
||||
notification.setChannelId(notificationChannel.getId());
|
||||
}
|
||||
|
||||
private void setNotificationBadgeIconType(Notification.Builder notification) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
notification.setBadgeIconType(Notification.BADGE_ICON_SMALL);
|
||||
}
|
||||
}
|
||||
|
||||
private void setNotificationGroup(Notification.Builder notification) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
notification
|
||||
.setGroup(GROUP_KEY_MESSAGES)
|
||||
.setGroupSummary(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void setNotificationSound(Notification.Builder notification, NotificationPreferences notificationPreferences) {
|
||||
String soundUri = notificationPreferences.getNotificationSound();
|
||||
if (soundUri != null) {
|
||||
if (soundUri != "none") {
|
||||
notification.setSound(Uri.parse(soundUri), AudioManager.STREAM_NOTIFICATION);
|
||||
}
|
||||
} else {
|
||||
Uri defaultUri = System.DEFAULT_NOTIFICATION_URI;
|
||||
notification.setSound(defaultUri, AudioManager.STREAM_NOTIFICATION);
|
||||
}
|
||||
}
|
||||
|
||||
private void setNotificationVibrate(Notification.Builder notification, NotificationPreferences notificationPreferences) {
|
||||
boolean vibrate = notificationPreferences.getShouldVibrate();
|
||||
if (vibrate) {
|
||||
// Use the system default for vibration
|
||||
notification.setDefaults(Notification.DEFAULT_VIBRATE);
|
||||
}
|
||||
}
|
||||
|
||||
private void setNotificationBlink(Notification.Builder notification, NotificationPreferences notificationPreferences) {
|
||||
boolean blink = notificationPreferences.getShouldBlink();
|
||||
if (blink) {
|
||||
notification.setLights(Color.CYAN, 500, 500);
|
||||
}
|
||||
}
|
||||
|
||||
private void setNotificationDeleteIntent(Notification.Builder notification, int notificationId) {
|
||||
// Let's add a delete intent when the notification is dismissed
|
||||
Intent delIntent = new Intent(mContext, NotificationDismissService.class);
|
||||
delIntent.putExtra(NOTIFICATION_ID, notificationId);
|
||||
PendingIntent deleteIntent = NotificationIntentAdapter.createPendingNotificationIntent(mContext, delIntent, mNotificationProps);
|
||||
notification.setDeleteIntent(deleteIntent);
|
||||
}
|
||||
|
||||
private void addNotificationReplyAction(Notification.Builder notification, int notificationId, Bundle bundle) {
|
||||
String postId = bundle.getString("post_id");
|
||||
String serverUrl = bundle.getString("server_url", DatabaseHelper.getOnlyServerUrl(context));
|
||||
|
||||
if (android.text.TextUtils.isEmpty(postId) ||
|
||||
serverUrl == null ||
|
||||
Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
|
||||
return;
|
||||
}
|
||||
|
||||
Intent replyIntent = new Intent(mContext, NotificationReplyBroadcastReceiver.class);
|
||||
replyIntent.setAction(KEY_TEXT_REPLY);
|
||||
replyIntent.putExtra(NOTIFICATION_ID, notificationId);
|
||||
replyIntent.putExtra(NOTIFICATION, bundle);
|
||||
|
||||
PendingIntent replyPendingIntent = PendingIntent.getBroadcast(
|
||||
mContext,
|
||||
notificationId,
|
||||
replyIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY)
|
||||
.setLabel("Reply")
|
||||
.build();
|
||||
|
||||
int icon = R.drawable.ic_notif_action_reply;
|
||||
CharSequence title = "Reply";
|
||||
Notification.Action replyAction = new Notification.Action.Builder(icon, title, replyPendingIntent)
|
||||
.addRemoteInput(remoteInput)
|
||||
.setAllowGeneratedReplies(true)
|
||||
.build();
|
||||
|
||||
notification
|
||||
.setShowWhen(true)
|
||||
.addAction(replyAction);
|
||||
private void notificationReceiptDelivery(String ackId, String serverUrl, String postId, String type, boolean isIdLoaded, ResolvePromise promise) {
|
||||
ReceiptDelivery.send(mContext, ackId, serverUrl, postId, type, isIdLoaded, promise);
|
||||
}
|
||||
|
||||
private void notifyReceivedToJS() {
|
||||
mJsIOHelper.sendEventToJS(NOTIFICATION_RECEIVED_EVENT_NAME, mNotificationProps.asBundle(), mAppLifecycleFacade.getRunningReactContext());
|
||||
}
|
||||
|
||||
private void cancelNotification(Bundle data, int notificationId) {
|
||||
final String channelId = data.getString("channel_id");
|
||||
final String badge = data.getString("badge");
|
||||
private String addServerUrlToBundle(Bundle bundle) {
|
||||
String serverUrl = bundle.getString("server_url");
|
||||
if (serverUrl == null) {
|
||||
serverUrl = DatabaseHelper.getOnlyServerUrl(mContext);
|
||||
bundle.putString("server_url", serverUrl);
|
||||
mNotificationProps = createProps(bundle);
|
||||
}
|
||||
|
||||
CustomPushNotification.badgeCount = Integer.parseInt(badge);
|
||||
CustomPushNotification.clearNotification(mContext.getApplicationContext(), notificationId, channelId);
|
||||
return serverUrl;
|
||||
}
|
||||
|
||||
private String getSenderName(Bundle bundle) {
|
||||
String senderName = bundle.getString("sender_name");
|
||||
if (senderName != null) {
|
||||
return senderName;
|
||||
private static void saveNotificationsMap(Context context, Map<String, List<Integer>> inputMap) {
|
||||
SharedPreferences pSharedPref = context.getSharedPreferences(PUSH_NOTIFICATIONS, Context.MODE_PRIVATE);
|
||||
if (pSharedPref != null && context != null) {
|
||||
JSONObject json = new JSONObject(inputMap);
|
||||
String jsonString = json.toString();
|
||||
SharedPreferences.Editor editor = pSharedPref.edit();
|
||||
editor.remove(NOTIFICATIONS_IN_CHANNEL).commit();
|
||||
editor.putString(NOTIFICATIONS_IN_CHANNEL, jsonString);
|
||||
editor.commit();
|
||||
}
|
||||
}
|
||||
|
||||
String channelName = bundle.getString("channel_name");
|
||||
if (channelName != null && channelName.startsWith("@")) {
|
||||
return channelName;
|
||||
}
|
||||
|
||||
String message = bundle.getString("message");
|
||||
if (message != null) {
|
||||
String name = message.split(":")[0];
|
||||
if (name != message) {
|
||||
return name;
|
||||
private static Map<String, List<Integer>> loadNotificationsMap(Context context) {
|
||||
Map<String, List<Integer>> outputMap = new HashMap<>();
|
||||
if (context != null) {
|
||||
SharedPreferences pSharedPref = context.getSharedPreferences(PUSH_NOTIFICATIONS, Context.MODE_PRIVATE);
|
||||
try {
|
||||
if (pSharedPref != null) {
|
||||
String jsonString = pSharedPref.getString(NOTIFICATIONS_IN_CHANNEL, (new JSONObject()).toString());
|
||||
JSONObject json = new JSONObject(jsonString);
|
||||
Iterator<String> keysItr = json.keys();
|
||||
while (keysItr.hasNext()) {
|
||||
String key = keysItr.next();
|
||||
JSONArray array = json.getJSONArray(key);
|
||||
List<Integer> values = new ArrayList<>();
|
||||
for (int i = 0; i < array.length(); ++i) {
|
||||
values.add(array.getInt(i));
|
||||
}
|
||||
outputMap.put(key, values);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return getConversationTitle(bundle);
|
||||
}
|
||||
|
||||
private String removeSenderNameFromMessage(String message, String senderName) {
|
||||
Integer index = message.indexOf(senderName);
|
||||
if (index == 0) {
|
||||
message = message.substring(senderName.length());
|
||||
}
|
||||
|
||||
return message.replaceFirst(": ", "").trim();
|
||||
}
|
||||
|
||||
private void notificationReceiptDelivery(String ackId, String serverUrl, String postId, String type, boolean isIdLoaded, ResolvePromise promise) {
|
||||
ReceiptDelivery.send(context, ackId, serverUrl, postId, type, isIdLoaded, promise);
|
||||
}
|
||||
|
||||
private void createNotificationChannels() {
|
||||
// Notification channels are not supported in Android Nougat and below
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
return;
|
||||
}
|
||||
|
||||
final NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
mHighImportanceChannel = new NotificationChannel("channel_01", "High Importance", NotificationManager.IMPORTANCE_HIGH);
|
||||
mHighImportanceChannel.setShowBadge(true);
|
||||
notificationManager.createNotificationChannel(mHighImportanceChannel);
|
||||
|
||||
mMinImportanceChannel = new NotificationChannel("channel_02", "Min Importance", NotificationManager.IMPORTANCE_MIN);
|
||||
mMinImportanceChannel.setShowBadge(true);
|
||||
notificationManager.createNotificationChannel(mMinImportanceChannel);
|
||||
return outputMap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.app.IntentService;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import com.mattermost.helpers.CustomPushNotificationHelper;
|
||||
import com.wix.reactnativenotifications.core.NotificationIntentAdapter;
|
||||
|
||||
public class NotificationDismissService extends IntentService {
|
||||
@@ -16,11 +17,18 @@ public class NotificationDismissService extends IntentService {
|
||||
|
||||
@Override
|
||||
protected void onHandleIntent(Intent intent) {
|
||||
mContext = getApplicationContext();
|
||||
Bundle bundle = NotificationIntentAdapter.extractPendingNotificationDataFromIntent(intent);
|
||||
int notificationId = intent.getIntExtra(CustomPushNotification.NOTIFICATION_ID, -1);
|
||||
String channelId = bundle.getString("channel_id");
|
||||
CustomPushNotification.clearNotification(mContext, notificationId, channelId);
|
||||
final Context context = getApplicationContext();
|
||||
final Bundle bundle = NotificationIntentAdapter.extractPendingNotificationDataFromIntent(intent);
|
||||
final String channelId = bundle.getString("channel_id");
|
||||
final String postId = bundle.getString("post_id");
|
||||
int notificationId = CustomPushNotificationHelper.MESSAGE_NOTIFICATION_ID;
|
||||
if (postId != null) {
|
||||
notificationId = postId.hashCode();
|
||||
} else if (channelId != null) {
|
||||
notificationId = channelId.hashCode();
|
||||
}
|
||||
|
||||
CustomPushNotification.cancelNotification(context, channelId, notificationId);
|
||||
Log.i("ReactNative", "Dismiss notification");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,7 @@ public class NotificationPreferences {
|
||||
public final String SOUND_PREF = "NotificationSound";
|
||||
public final String VIBRATE_PREF = "NotificationVibrate";
|
||||
public final String BLINK_PREF = "NotificationLights";
|
||||
|
||||
private SharedPreferences mSharedPreferences;
|
||||
private final SharedPreferences mSharedPreferences;
|
||||
|
||||
private NotificationPreferences(Context context) {
|
||||
mSharedPreferences = context.getSharedPreferences(SHARED_NAME, Context.MODE_PRIVATE);
|
||||
@@ -40,18 +39,18 @@ public class NotificationPreferences {
|
||||
public void setNotificationSound(String soundUri) {
|
||||
SharedPreferences.Editor editor = mSharedPreferences.edit();
|
||||
editor.putString(SOUND_PREF, soundUri);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public void setShouldVibrate(boolean vibrate) {
|
||||
SharedPreferences.Editor editor = mSharedPreferences.edit();
|
||||
editor.putBoolean(VIBRATE_PREF, vibrate);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public void setShouldBlink(boolean blink) {
|
||||
SharedPreferences.Editor editor = mSharedPreferences.edit();
|
||||
editor.putBoolean(BLINK_PREF, blink);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import com.facebook.react.bridge.WritableMap;
|
||||
public class NotificationPreferencesModule extends ReactContextBaseJavaModule {
|
||||
private static NotificationPreferencesModule instance;
|
||||
private final MainApplication mApplication;
|
||||
private NotificationPreferences mNotificationPreference;
|
||||
private final NotificationPreferences mNotificationPreference;
|
||||
|
||||
private NotificationPreferencesModule(MainApplication application, ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
@@ -108,7 +108,7 @@ public class NotificationPreferencesModule extends ReactContextBaseJavaModule {
|
||||
|
||||
@ReactMethod
|
||||
public void getDeliveredNotifications(final Promise promise) {
|
||||
Context context = mApplication.getApplicationContext();
|
||||
final Context context = mApplication.getApplicationContext();
|
||||
final NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
StatusBarNotification[] statusBarNotifications = notificationManager.getActiveNotifications();
|
||||
WritableArray result = Arguments.createArray();
|
||||
@@ -116,9 +116,7 @@ public class NotificationPreferencesModule extends ReactContextBaseJavaModule {
|
||||
WritableMap map = Arguments.createMap();
|
||||
Notification n = sbn.getNotification();
|
||||
Bundle bundle = n.extras;
|
||||
int identifier = sbn.getId();
|
||||
String channelId = bundle.getString("channel_id");
|
||||
map.putInt("identifier", identifier);
|
||||
map.putString("channel_id", channelId);
|
||||
result.pushMap(map);
|
||||
}
|
||||
@@ -126,8 +124,8 @@ public class NotificationPreferencesModule extends ReactContextBaseJavaModule {
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void removeDeliveredNotifications(int identifier, String channelId) {
|
||||
public void removeDeliveredNotifications(String channelId) {
|
||||
Context context = mApplication.getApplicationContext();
|
||||
CustomPushNotification.clearNotification(context, identifier, channelId);
|
||||
CustomPushNotification.clearChannelNotifications(context, channelId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.mattermost.rnbeta;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.RemoteInput;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
@@ -10,6 +11,9 @@ import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.app.Person;
|
||||
|
||||
import android.util.Log;
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -28,6 +32,8 @@ import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
|
||||
import com.wix.reactnativenotifications.core.NotificationIntentAdapter;
|
||||
import com.wix.reactnativenotifications.core.ProxyService;
|
||||
import com.wix.reactnativenotifications.core.notification.PushNotificationProps;
|
||||
|
||||
public class NotificationReplyBroadcastReceiver extends BroadcastReceiver {
|
||||
private Context mContext;
|
||||
@@ -47,27 +53,14 @@ public class NotificationReplyBroadcastReceiver extends BroadcastReceiver {
|
||||
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
final ReactApplicationContext reactApplicationContext = new ReactApplicationContext(context);
|
||||
final int notificationId = intent.getIntExtra(CustomPushNotification.NOTIFICATION_ID, -1);
|
||||
final Bundle notification = intent.getBundleExtra(CustomPushNotification.NOTIFICATION);
|
||||
final int notificationId = intent.getIntExtra(CustomPushNotificationHelper.NOTIFICATION_ID, -1);
|
||||
final Bundle notification = intent.getBundleExtra(CustomPushNotificationHelper.NOTIFICATION);
|
||||
final String serverUrl = notification.getString("serverUrl");
|
||||
final String token = Credentials.getCredentialsForServerSync(reactApplicationContext, serverUrl);
|
||||
|
||||
|
||||
Credentials.getCredentialsForServer(reactApplicationContext, serverUrl, new ResolvePromise() {
|
||||
@Override
|
||||
public void resolve(@Nullable Object value) {
|
||||
if (value instanceof Boolean && !(Boolean)value) {
|
||||
return;
|
||||
}
|
||||
|
||||
WritableMap map = (WritableMap) value;
|
||||
if (map != null) {
|
||||
String token = map.getString("password");
|
||||
String serverUrl = map.getString("service");
|
||||
|
||||
replyToMessage(serverUrl, token, notificationId, message);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (token != null) {
|
||||
replyToMessage(serverUrl, token, notificationId, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +73,7 @@ public class NotificationReplyBroadcastReceiver extends BroadcastReceiver {
|
||||
}
|
||||
|
||||
if (token == null || serverUrl == null) {
|
||||
onReplyFailed(notificationManager, notificationId, channelId);
|
||||
onReplyFailed(notificationId);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -103,17 +96,17 @@ public class NotificationReplyBroadcastReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onFailure(Call call, IOException e) {
|
||||
Log.i("ReactNative", String.format("Reply FAILED exception %s", e.getMessage()));
|
||||
onReplyFailed(notificationManager, notificationId, channelId);
|
||||
onReplyFailed(notificationId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Call call, final Response response) throws IOException {
|
||||
if (response.isSuccessful()) {
|
||||
onReplySuccess(notificationManager, notificationId, channelId);
|
||||
onReplySuccess(notificationId, message);
|
||||
Log.i("ReactNative", "Reply SUCCESS");
|
||||
} else {
|
||||
Log.i("ReactNative", String.format("Reply FAILED status %s BODY %s", response.code(), response.body().string()));
|
||||
onReplyFailed(notificationManager, notificationId, channelId);
|
||||
onReplyFailed(notificationId);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -131,37 +124,31 @@ public class NotificationReplyBroadcastReceiver extends BroadcastReceiver {
|
||||
}
|
||||
}
|
||||
|
||||
protected void onReplyFailed(NotificationManager notificationManager, int notificationId, String channelId) {
|
||||
String CHANNEL_ID = "Reply job";
|
||||
Resources res = mContext.getResources();
|
||||
String packageName = mContext.getPackageName();
|
||||
int smallIconResId = res.getIdentifier("ic_notification", "mipmap", packageName);
|
||||
|
||||
Bundle userInfoBundle = new Bundle();
|
||||
userInfoBundle.putString("channel_id", channelId);
|
||||
|
||||
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_ID, NotificationManager.IMPORTANCE_LOW);
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
Notification notification =
|
||||
new Notification.Builder(mContext, CHANNEL_ID)
|
||||
.setContentTitle("Message failed to send.")
|
||||
.setSmallIcon(smallIconResId)
|
||||
.addExtras(userInfoBundle)
|
||||
.build();
|
||||
|
||||
CustomPushNotification.clearNotification(mContext, notificationId, channelId);
|
||||
notificationManager.notify(notificationId, notification);
|
||||
protected void onReplyFailed(int notificationId) {
|
||||
recreateNotification(notificationId, "Message failed to send.");
|
||||
}
|
||||
|
||||
protected void onReplySuccess(NotificationManager notificationManager, int notificationId, String channelId) {
|
||||
notificationManager.cancel(notificationId);
|
||||
CustomPushNotification.clearNotification(mContext, notificationId, channelId);
|
||||
protected void onReplySuccess(int notificationId, final CharSequence message) {
|
||||
recreateNotification(notificationId, message);
|
||||
}
|
||||
|
||||
private void recreateNotification(int notificationId, final CharSequence message) {
|
||||
final Intent cta = new Intent(mContext, ProxyService.class);
|
||||
final PushNotificationProps notificationProps = new PushNotificationProps(bundle);
|
||||
final PendingIntent pendingIntent = NotificationIntentAdapter.createPendingNotificationIntent(mContext, cta, notificationProps);
|
||||
NotificationCompat.Builder builder = CustomPushNotificationHelper.createNotificationBuilder(mContext, pendingIntent, bundle, false);
|
||||
Notification notification = builder.build();
|
||||
NotificationCompat.MessagingStyle messagingStyle = NotificationCompat.MessagingStyle.extractMessagingStyleFromNotification(notification);
|
||||
assert messagingStyle != null;
|
||||
messagingStyle.addMessage(message, System.currentTimeMillis(), (Person)null);
|
||||
notification = builder.setStyle(messagingStyle).build();
|
||||
notificationManager.notify(notificationId, notification);
|
||||
}
|
||||
|
||||
private CharSequence getReplyMessage(Intent intent) {
|
||||
Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
|
||||
if (remoteInput != null) {
|
||||
return remoteInput.getCharSequence(CustomPushNotification.KEY_TEXT_REPLY);
|
||||
return remoteInput.getCharSequence(CustomPushNotificationHelper.KEY_TEXT_REPLY);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -26,31 +26,9 @@ public class ReceiptDelivery {
|
||||
|
||||
public static void send(Context context, final String ackId, final String serverUrl, final String postId, final String type, final boolean isIdLoaded, ResolvePromise promise) {
|
||||
final ReactApplicationContext reactApplicationContext = new ReactApplicationContext(context);
|
||||
|
||||
Credentials.getCredentialsForServer(reactApplicationContext, serverUrl, new ResolvePromise() {
|
||||
@Override
|
||||
public void resolve(@Nullable Object value) {
|
||||
if (value instanceof Boolean && !(Boolean)value) {
|
||||
return;
|
||||
}
|
||||
|
||||
WritableMap map = (WritableMap) value;
|
||||
if (map != null) {
|
||||
String token = map.getString("password");
|
||||
String serverUrl = map.getString("service");
|
||||
if (serverUrl.isEmpty()) {
|
||||
String[] credentials = token.split(",[ ]*");
|
||||
if (credentials.length == 2) {
|
||||
token = credentials[0];
|
||||
serverUrl = credentials[1];
|
||||
}
|
||||
}
|
||||
|
||||
Log.i("ReactNative", String.format("Send receipt delivery ACK=%s TYPE=%s to URL=%s with ID-LOADED=%s", ackId, type, serverUrl, isIdLoaded));
|
||||
execute(serverUrl, postId, token, ackId, type, isIdLoaded, promise);
|
||||
}
|
||||
}
|
||||
});
|
||||
final String token = Credentials.getCredentialsForServerSync(reactApplicationContext, serverUrl);
|
||||
Log.i("ReactNative", String.format("Send receipt delivery ACK=%s TYPE=%s to URL=%s with ID-LOADED=%s", ackId, type, serverUrl, isIdLoaded));
|
||||
execute(serverUrl, postId, token, ackId, type, isIdLoaded, promise);
|
||||
}
|
||||
|
||||
protected static void execute(String serverUrl, String postId, String token, String ackId, String type, boolean isIdLoaded, ResolvePromise promise) {
|
||||
@@ -111,6 +89,8 @@ public class ReceiptDelivery {
|
||||
return;
|
||||
case 401:
|
||||
promise.reject("Receipt delivery failure", "Unauthorized");
|
||||
case 403:
|
||||
promise.reject("Receipt delivery failure", "Forbidden");
|
||||
return;
|
||||
case 500:
|
||||
promise.reject("Receipt delivery failure", "StatusInternalServerError");
|
||||
|
||||
@@ -26,10 +26,8 @@ import {queryActiveServer, queryServer} from '@queries/app/servers';
|
||||
import {deleteIOSDatabase} from '@utils/mattermost_managed';
|
||||
import {hashCode} from '@utils/security';
|
||||
|
||||
import type {MigrationEvents} from '@nozbe/watermelondb/adapters/sqlite';
|
||||
import type {AppDatabase, CreateServerDatabaseArgs, Models, RegisterServerDatabaseArgs, ServerDatabase, ServerDatabases} from '@typings/database/database';
|
||||
import {DatabaseType} from '@typings/database/enums';
|
||||
import type IServers from '@typings/database/models/app/servers';
|
||||
|
||||
import ServerDataOperator from '../../operator/server_data_operator';
|
||||
|
||||
@@ -83,7 +81,7 @@ class DatabaseManager {
|
||||
|
||||
const adapter = new LokiJSAdapter({dbName: APP_DATABASE, migrations: AppDatabaseMigrations, schema, useWebWorker: false, useIncrementalIndexedDB: true});
|
||||
|
||||
const database = new Database({adapter, actionsEnabled: true, modelClasses});
|
||||
const database = new Database({adapter, modelClasses});
|
||||
const operator = new AppDataOperator(database);
|
||||
|
||||
this.appDatabase = {
|
||||
@@ -118,7 +116,7 @@ class DatabaseManager {
|
||||
serverUrl,
|
||||
});
|
||||
|
||||
const database = new Database({adapter, actionsEnabled: true, modelClasses});
|
||||
const database = new Database({adapter, modelClasses});
|
||||
const operator = new ServerDataOperator(database);
|
||||
const serverDatabase = {database, operator};
|
||||
|
||||
@@ -149,9 +147,9 @@ class DatabaseManager {
|
||||
|
||||
if (this.appDatabase?.database && !isServerPresent) {
|
||||
const appDatabase = this.appDatabase.database;
|
||||
await appDatabase.action(async () => {
|
||||
await appDatabase.write(async () => {
|
||||
const serversCollection = appDatabase.collections.get(SERVERS);
|
||||
await serversCollection.create((server: IServers) => {
|
||||
await serversCollection.create((server: ServersModel) => {
|
||||
server.dbPath = databaseFilePath;
|
||||
server.displayName = displayName;
|
||||
server.mentionCount = 0;
|
||||
@@ -201,7 +199,7 @@ class DatabaseManager {
|
||||
public setActiveServerDatabase = async (serverUrl: string): Promise<void> => {
|
||||
if (this.appDatabase?.database) {
|
||||
const database = this.appDatabase?.database;
|
||||
await database.action(async () => {
|
||||
await database.write(async () => {
|
||||
const servers = await database.collections.get(SERVERS).query(Q.where('url', serverUrl)).fetch();
|
||||
if (servers.length) {
|
||||
servers[0].update((server: ServersModel) => {
|
||||
@@ -217,7 +215,7 @@ class DatabaseManager {
|
||||
const database = this.appDatabase?.database;
|
||||
const server = await queryServer(database, serverUrl);
|
||||
if (server) {
|
||||
database.action(async () => {
|
||||
database.write(async () => {
|
||||
await server.update((record) => {
|
||||
record.lastActiveAt = 0;
|
||||
});
|
||||
@@ -234,7 +232,7 @@ class DatabaseManager {
|
||||
const database = this.appDatabase?.database;
|
||||
const server = await queryServer(database, serverUrl);
|
||||
if (server) {
|
||||
database.action(async () => {
|
||||
database.write(async () => {
|
||||
await server.destroyPermanently();
|
||||
});
|
||||
|
||||
@@ -280,7 +278,7 @@ class DatabaseManager {
|
||||
};
|
||||
|
||||
private buildMigrationCallbacks = (dbName: string) => {
|
||||
const migrationEvents: MigrationEvents = {
|
||||
const migrationEvents = {
|
||||
onSuccess: () => {
|
||||
return DeviceEventEmitter.emit(MIGRATION_EVENTS.MIGRATION_SUCCESS, {
|
||||
dbName,
|
||||
@@ -291,7 +289,7 @@ class DatabaseManager {
|
||||
dbName,
|
||||
});
|
||||
},
|
||||
onError: (error) => {
|
||||
onError: (error: Error) => {
|
||||
return DeviceEventEmitter.emit(MIGRATION_EVENTS.MIGRATION_ERROR, {
|
||||
dbName,
|
||||
error,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Database, Q} from '@nozbe/watermelondb';
|
||||
import SQLiteAdapter, {MigrationEvents} from '@nozbe/watermelondb/adapters/sqlite';
|
||||
import SQLiteAdapter from '@nozbe/watermelondb/adapters/sqlite';
|
||||
import logger from '@nozbe/watermelondb/utils/common/logger';
|
||||
import {DeviceEventEmitter, Platform} from 'react-native';
|
||||
import DeviceInfo from 'react-native-device-info';
|
||||
@@ -28,7 +28,6 @@ import {hashCode} from '@utils/security';
|
||||
|
||||
import type {AppDatabase, CreateServerDatabaseArgs, RegisterServerDatabaseArgs, Models, ServerDatabase, ServerDatabases} from '@typings/database/database';
|
||||
import {DatabaseType} from '@typings/database/enums';
|
||||
import type IServers from '@typings/database/models/app/servers';
|
||||
|
||||
import ServerDataOperator from '../operator/server_data_operator';
|
||||
|
||||
@@ -95,7 +94,7 @@ class DatabaseManager {
|
||||
schema,
|
||||
});
|
||||
|
||||
const database = new Database({adapter, actionsEnabled: true, modelClasses});
|
||||
const database = new Database({adapter, modelClasses});
|
||||
const operator = new AppDataOperator(database);
|
||||
|
||||
this.appDatabase = {
|
||||
@@ -143,7 +142,7 @@ class DatabaseManager {
|
||||
serverUrl,
|
||||
});
|
||||
|
||||
const database = new Database({adapter, actionsEnabled: true, modelClasses});
|
||||
const database = new Database({adapter, modelClasses});
|
||||
const operator = new ServerDataOperator(database);
|
||||
const serverDatabase = {database, operator};
|
||||
|
||||
@@ -186,9 +185,9 @@ class DatabaseManager {
|
||||
|
||||
if (this.appDatabase?.database && !isServerPresent) {
|
||||
const appDatabase = this.appDatabase.database;
|
||||
await appDatabase.action(async () => {
|
||||
await appDatabase.write(async () => {
|
||||
const serversCollection = appDatabase.collections.get(SERVERS);
|
||||
await serversCollection.create((server: IServers) => {
|
||||
await serversCollection.create((server: ServersModel) => {
|
||||
server.dbPath = databaseFilePath;
|
||||
server.displayName = displayName;
|
||||
server.mentionCount = 0;
|
||||
@@ -257,7 +256,7 @@ class DatabaseManager {
|
||||
public setActiveServerDatabase = async (serverUrl: string): Promise<void> => {
|
||||
if (this.appDatabase?.database) {
|
||||
const database = this.appDatabase?.database;
|
||||
await database.action(async () => {
|
||||
await database.write(async () => {
|
||||
const servers = await database.collections.get(SERVERS).query(Q.where('url', serverUrl)).fetch();
|
||||
if (servers.length) {
|
||||
servers[0].update((server: ServersModel) => {
|
||||
@@ -279,7 +278,7 @@ class DatabaseManager {
|
||||
const database = this.appDatabase?.database;
|
||||
const server = await queryServer(database, serverUrl);
|
||||
if (server) {
|
||||
database.action(async () => {
|
||||
database.write(async () => {
|
||||
await server.update((record) => {
|
||||
record.lastActiveAt = 0;
|
||||
});
|
||||
@@ -302,7 +301,7 @@ class DatabaseManager {
|
||||
const database = this.appDatabase?.database;
|
||||
const server = await queryServer(database, serverUrl);
|
||||
if (server) {
|
||||
database.action(async () => {
|
||||
database.write(async () => {
|
||||
await server.destroyPermanently();
|
||||
});
|
||||
|
||||
@@ -365,7 +364,7 @@ class DatabaseManager {
|
||||
* @returns {MigrationEvents}
|
||||
*/
|
||||
private buildMigrationCallbacks = (dbName: string) => {
|
||||
const migrationEvents: MigrationEvents = {
|
||||
const migrationEvents = {
|
||||
onSuccess: () => {
|
||||
return DeviceEventEmitter.emit(MIGRATION_EVENTS.MIGRATION_SUCCESS, {
|
||||
dbName,
|
||||
|
||||
@@ -7,7 +7,7 @@ import {MM_TABLES} from '@constants/database';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import ServerDataOperator from '@database/operator/server_data_operator';
|
||||
|
||||
import type IServers from '@typings/database/models/app/servers';
|
||||
import type ServersModel from '@typings/database/models/app/servers';
|
||||
|
||||
const {SERVERS} = MM_TABLES.APP;
|
||||
|
||||
@@ -73,7 +73,7 @@ describe('*** Database Manager tests ***', () => {
|
||||
await DatabaseManager.destroyServerDatabase('https://appv1.mattermost.com');
|
||||
|
||||
const fetchServerRecords = async (serverUrl: string) => {
|
||||
const servers = await DatabaseManager.appDatabase?.database!.collections.get(SERVERS).query(Q.where('url', serverUrl)).fetch() as IServers[];
|
||||
const servers = await DatabaseManager.appDatabase?.database!.collections.get(SERVERS).query(Q.where('url', serverUrl)).fetch() as ServersModel[];
|
||||
return servers.length;
|
||||
};
|
||||
|
||||
|
||||
@@ -5,12 +5,12 @@ import {Q} from '@nozbe/watermelondb';
|
||||
import {Platform} from 'react-native';
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
import {DatabaseType} from '@typings/database/enums';
|
||||
import {getIOSAppGroupDetails} from '@utils/mattermost_managed';
|
||||
|
||||
import DatabaseManager from './index';
|
||||
|
||||
import type IServers from '@typings/database/models/app/servers';
|
||||
import {DatabaseType} from '@typings/database/enums';
|
||||
import type ServersModel from '@typings/database/models/app/servers';
|
||||
|
||||
export default async () => {
|
||||
await DatabaseManager.init([]);
|
||||
@@ -59,7 +59,7 @@ export default async () => {
|
||||
'https://comm5.mattermost.com',
|
||||
'https://comm4.mattermost.com',
|
||||
]),
|
||||
)).fetch()) as IServers[];
|
||||
)).fetch()) as ServersModel[];
|
||||
return servers;
|
||||
};
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
retrieveRecords,
|
||||
} from '@database/operator/utils/general';
|
||||
|
||||
import type {WriterInterface} from '@nozbe/watermelondb/Database';
|
||||
import type Model from '@nozbe/watermelondb/Model';
|
||||
|
||||
import type {
|
||||
@@ -182,8 +183,8 @@ export default class BaseDataOperator {
|
||||
batchRecords = async (models: Model[]): Promise<void> => {
|
||||
try {
|
||||
if (models.length > 0) {
|
||||
await this.database.action(async () => {
|
||||
await this.database.batch(...models);
|
||||
await this.database.write(async (writer: WriterInterface) => {
|
||||
await writer.batch(...models);
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
@@ -106,7 +106,7 @@ const PostsInChannelHandler = (superclass: any) => class extends superclass {
|
||||
return [targetChunk];
|
||||
}
|
||||
|
||||
targetChunk = await this.database.action(async () => {
|
||||
targetChunk = await this.database.write(async () => {
|
||||
return targetChunk!.update((record) => {
|
||||
record.earliest = Math.min(record.earliest, earliest);
|
||||
record.latest = Math.max(record.latest, latest);
|
||||
@@ -158,7 +158,7 @@ const PostsInChannelHandler = (superclass: any) => class extends superclass {
|
||||
return [recentChunk];
|
||||
}
|
||||
|
||||
recentChunk = await this.database.action(async () => {
|
||||
recentChunk = await this.database.write(async () => {
|
||||
return recentChunk!.update((record) => {
|
||||
record.latest = Math.max(record.latest, latest);
|
||||
});
|
||||
|
||||
@@ -5,6 +5,8 @@ import DatabaseManager from '@database/manager';
|
||||
import {createPostsChain, sanitizePosts} from '@database/operator/utils/post';
|
||||
import {sanitizeReactions} from '@database/operator/utils/reaction';
|
||||
|
||||
import type {WriterInterface} from '@nozbe/watermelondb/Database';
|
||||
|
||||
import type ReactionModel from '@typings/database/models/servers/reaction';
|
||||
|
||||
import {mockedPosts, mockedReactions} from './mock';
|
||||
@@ -92,8 +94,8 @@ describe('DataOperator: Utils tests', () => {
|
||||
|
||||
// Jest in not using the same database instance amongst the Singletons; hence, we are creating the reaction record here
|
||||
// eslint-disable-next-line max-nested-callbacks
|
||||
await server?.database!.action(async () => {
|
||||
await server.database!.batch(...prepareRecords);
|
||||
await server?.database!.write(async (writer: WriterInterface) => {
|
||||
await writer.batch(...prepareRecords);
|
||||
});
|
||||
|
||||
const {
|
||||
|
||||
@@ -50,9 +50,14 @@ const launchApp = async (props: LaunchProps, resetNavigation = true) => {
|
||||
serverUrl = extra.payload?.server_url;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
serverUrl = await getActiveServerUrl();
|
||||
break;
|
||||
}
|
||||
|
||||
serverUrl = await getActiveServerUrl();
|
||||
if (props.launchError && !serverUrl) {
|
||||
serverUrl = await getActiveServerUrl();
|
||||
}
|
||||
|
||||
if (serverUrl) {
|
||||
const credentials = await getServerCredentials(serverUrl);
|
||||
@@ -135,6 +140,7 @@ export const getLaunchPropsFromDeepLink = (deepLinkUrl: string): LaunchProps =>
|
||||
|
||||
export const getLaunchPropsFromNotification = (notification: NotificationWithData): LaunchProps => {
|
||||
const {payload} = notification;
|
||||
|
||||
const launchProps: LaunchProps = {
|
||||
launchType: LaunchType.Notification,
|
||||
};
|
||||
|
||||
@@ -127,7 +127,7 @@ class PushNotifications {
|
||||
this.handleInAppNotification(notification);
|
||||
} else if (userInteraction && !payload.userInfo?.local) {
|
||||
const props = getLaunchPropsFromNotification(notification);
|
||||
relaunchApp(props);
|
||||
relaunchApp(props, true);
|
||||
}
|
||||
break;
|
||||
case NOTIFICATION_TYPE.SESSION:
|
||||
|
||||
2322
detox/package-lock.json
generated
2322
detox/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -7,16 +7,16 @@
|
||||
"@babel/plugin-proposal-class-properties": "7.14.5",
|
||||
"@babel/plugin-transform-modules-commonjs": "7.14.5",
|
||||
"@babel/plugin-transform-runtime": "7.14.5",
|
||||
"@babel/preset-env": "7.14.5",
|
||||
"@babel/preset-env": "7.14.8",
|
||||
"axios": "0.21.1",
|
||||
"babel-jest": "27.0.2",
|
||||
"babel-jest": "27.0.6",
|
||||
"babel-plugin-module-resolver": "4.1.0",
|
||||
"deepmerge": "4.2.2",
|
||||
"detox": "18.18.1",
|
||||
"detox": "18.20.0",
|
||||
"form-data": "4.0.0",
|
||||
"jest": "27.0.4",
|
||||
"jest-circus": "27.0.4",
|
||||
"jest-cli": "27.0.4",
|
||||
"jest": "27.0.6",
|
||||
"jest-circus": "27.0.6",
|
||||
"jest-cli": "27.0.6",
|
||||
"jest-html-reporters": "2.1.6",
|
||||
"jest-junit": "12.2.0",
|
||||
"sanitize-filename": "1.6.3",
|
||||
|
||||
@@ -23,6 +23,7 @@ target 'Mattermost' do
|
||||
pod 'Permission-Camera', :path => "#{permissions_path}/Camera"
|
||||
pod 'Permission-PhotoLibrary', :path => "#{permissions_path}/PhotoLibrary"
|
||||
pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi', :modular_headers => true
|
||||
pod 'simdjson', path: '../node_modules/@nozbe/simdjson'
|
||||
|
||||
pod 'XCDYouTubeKit', '2.8.2'
|
||||
pod 'Swime', '3.0.6'
|
||||
|
||||
@@ -28,7 +28,7 @@ PODS:
|
||||
- React-jsi (= 0.64.2)
|
||||
- ReactCommon/turbomodule/core (= 0.64.2)
|
||||
- glog (0.3.5)
|
||||
- jail-monkey (2.5.0):
|
||||
- jail-monkey (2.6.0):
|
||||
- React-Core
|
||||
- libwebp (1.2.0):
|
||||
- libwebp/demux (= 1.2.0)
|
||||
@@ -256,7 +256,7 @@ PODS:
|
||||
- React-Core
|
||||
- Starscream (~> 4.0.4)
|
||||
- SwiftyJSON (~> 5.0)
|
||||
- react-native-notifications (3.5.0):
|
||||
- react-native-notifications (4.1.1):
|
||||
- React-Core
|
||||
- react-native-paste-input (0.1.4):
|
||||
- React-Core
|
||||
@@ -338,12 +338,12 @@ PODS:
|
||||
- React-Core
|
||||
- ReactNativeKeyboardTrackingView (5.7.0):
|
||||
- React
|
||||
- ReactNativeNavigation (7.17.1):
|
||||
- ReactNativeNavigation (7.18.1):
|
||||
- React-Core
|
||||
- React-RCTImage
|
||||
- React-RCTText
|
||||
- ReactNativeNavigation/Core (= 7.17.1)
|
||||
- ReactNativeNavigation/Core (7.17.1):
|
||||
- ReactNativeNavigation/Core (= 7.18.1)
|
||||
- ReactNativeNavigation/Core (7.18.1):
|
||||
- React-Core
|
||||
- React-RCTImage
|
||||
- React-RCTText
|
||||
@@ -353,13 +353,13 @@ PODS:
|
||||
- React-Core
|
||||
- RNCMaskedView (0.1.11):
|
||||
- React
|
||||
- RNDeviceInfo (8.1.3):
|
||||
- RNDeviceInfo (8.1.4):
|
||||
- React-Core
|
||||
- RNDevMenu (4.0.2):
|
||||
- React-Core
|
||||
- React-Core/DevSupport
|
||||
- React-RCTNetwork
|
||||
- RNFastImage (8.3.6):
|
||||
- RNFastImage (8.3.7):
|
||||
- React-Core
|
||||
- SDWebImage (~> 5.8)
|
||||
- SDWebImageWebPCoder (~> 0.6.1)
|
||||
@@ -407,10 +407,10 @@ PODS:
|
||||
- RNRudderSdk (1.0.0):
|
||||
- React
|
||||
- Rudder (>= 1.0.20)
|
||||
- RNSentry (2.6.0):
|
||||
- RNSentry (2.6.1):
|
||||
- React-Core
|
||||
- Sentry (= 7.0.0)
|
||||
- RNShare (6.2.3):
|
||||
- Sentry (= 7.1.4)
|
||||
- RNShare (6.5.0):
|
||||
- React-Core
|
||||
- RNSVG (12.1.1):
|
||||
- React
|
||||
@@ -423,9 +423,10 @@ PODS:
|
||||
- SDWebImageWebPCoder (0.6.1):
|
||||
- libwebp (~> 1.0)
|
||||
- SDWebImage/Core (~> 5.7)
|
||||
- Sentry (7.0.0):
|
||||
- Sentry/Core (= 7.0.0)
|
||||
- Sentry/Core (7.0.0)
|
||||
- Sentry (7.1.4):
|
||||
- Sentry/Core (= 7.1.4)
|
||||
- Sentry/Core (7.1.4)
|
||||
- simdjson (0.9.6-fix2)
|
||||
- Starscream (4.0.4)
|
||||
- SwiftyJSON (5.0.1)
|
||||
- Swime (3.0.6)
|
||||
@@ -437,7 +438,7 @@ PODS:
|
||||
- UMCore
|
||||
- UMTaskManagerInterface (6.2.0):
|
||||
- UMCore
|
||||
- WatermelonDB (0.22.0):
|
||||
- WatermelonDB (0.23.0):
|
||||
- React
|
||||
- React-jsi
|
||||
- XCDYouTubeKit (2.8.2)
|
||||
@@ -515,6 +516,7 @@ DEPENDENCIES:
|
||||
- RNShare (from `../node_modules/react-native-share`)
|
||||
- RNSVG (from `../node_modules/react-native-svg`)
|
||||
- RNVectorIcons (from `../node_modules/react-native-vector-icons`)
|
||||
- "simdjson (from `../node_modules/@nozbe/simdjson`)"
|
||||
- Starscream (from `https://github.com/mattermost/Starscream.git`, commit `1b4b93708fb63d2665625a11e57461772a65364a`)
|
||||
- Swime (= 3.0.6)
|
||||
- UMAppLoader (from `../node_modules/unimodules-app-loader/ios`)
|
||||
@@ -676,6 +678,8 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/react-native-svg"
|
||||
RNVectorIcons:
|
||||
:path: "../node_modules/react-native-vector-icons"
|
||||
simdjson:
|
||||
:path: "../node_modules/@nozbe/simdjson"
|
||||
Starscream:
|
||||
:commit: 1b4b93708fb63d2665625a11e57461772a65364a
|
||||
:git: https://github.com/mattermost/Starscream.git
|
||||
@@ -708,7 +712,7 @@ SPEC CHECKSUMS:
|
||||
FBLazyVector: e686045572151edef46010a6f819ade377dfeb4b
|
||||
FBReactNativeSpec: cef0cc6d50abc92e8cf52f140aa22b5371cfec0b
|
||||
glog: 73c2498ac6884b13ede40eda8228cb1eee9d9d62
|
||||
jail-monkey: feb2bdedc4d67312cd41a455c22661d804bba985
|
||||
jail-monkey: 07b83767601a373db876e939b8dbf3f5eb15f073
|
||||
libwebp: e90b9c01d99205d03b6bb8f2c8c415e5a4ef66f0
|
||||
Permission-Camera: ac603073e4128e51e6ca3c39129778f05b4082fa
|
||||
Permission-PhotoLibrary: 0748c1a490fad126dfe36dbea8234dedfe59cc27
|
||||
@@ -731,7 +735,7 @@ SPEC CHECKSUMS:
|
||||
react-native-hw-keyboard-event: b517cefb8d5c659a38049c582de85ff43337dc53
|
||||
react-native-netinfo: e849fc21ca2f4128a5726c801a82fc6f4a6db50d
|
||||
react-native-network-client: 30ab97e7e6c8d6f2d2b10cc1ebad0cbf9c894c6e
|
||||
react-native-notifications: 89a73cd2cd2648e1734fa10e3507681c9e4f14de
|
||||
react-native-notifications: b7391a61c9a3919a8cccf6e3a4c542b419cb5ee2
|
||||
react-native-paste-input: 4d6ecc3875153212b5503b6da093277db4ace241
|
||||
react-native-safe-area-context: f0906bf8bc9835ac9a9d3f97e8bde2a997d8da79
|
||||
react-native-video: 0bb76b6d6b77da3009611586c7dbf817b947f30e
|
||||
@@ -750,13 +754,13 @@ SPEC CHECKSUMS:
|
||||
ReactCommon: 149906e01aa51142707a10665185db879898e966
|
||||
ReactNativeExceptionHandler: b11ff67c78802b2f62eed0e10e75cb1ef7947c60
|
||||
ReactNativeKeyboardTrackingView: 02137fac3b2ebd330d74fa54ead48b14750a2306
|
||||
ReactNativeNavigation: 8ccac6aadb88ce59ff1594bfbe1f579b9bb5e81a
|
||||
ReactNativeNavigation: 88128fa06b2c349b613e1e0fd3cdff2c58c01c55
|
||||
RNCAsyncStorage: b03032fdbdb725bea0bd9e5ec5a7272865ae7398
|
||||
RNCClipboard: 41d8d918092ae8e676f18adada19104fa3e68495
|
||||
RNCMaskedView: 0e1bc4bfa8365eba5fbbb71e07fbdc0555249489
|
||||
RNDeviceInfo: 8d3a29207835f972bce883723882980143270d55
|
||||
RNDeviceInfo: 0b3e0154c1c659ea9779cb3e883e66ece92326a9
|
||||
RNDevMenu: fd325b5554b61fe7f48d9205a3877cf5ee88cd7c
|
||||
RNFastImage: 044259b52d726b183fa401f3521b2e5a864afc0a
|
||||
RNFastImage: a7384db75df352500261e8e8f1ac2026def26102
|
||||
RNFileViewer: 83cc066ad795b1f986791d03b56fe0ee14b6a69f
|
||||
RNGestureHandler: a479ebd5ed4221a810967000735517df0d2db211
|
||||
RNKeychain: f75b8c8b2f17d3b2aa1f25b4a0ac5b83d947ff8f
|
||||
@@ -765,14 +769,15 @@ SPEC CHECKSUMS:
|
||||
RNReactNativeHapticFeedback: 653a8c126a0f5e88ce15ffe280b3ff37e1fbb285
|
||||
RNReanimated: 9c13c86454bfd54dab7505c1a054470bfecd2563
|
||||
RNRudderSdk: 9aa881c2bf754dc3b05e392340a5e3663a970f0a
|
||||
RNSentry: a2b02b326ae4fce91ce7c57d3f7dcf8df4f72269
|
||||
RNShare: 16c78aeb7a78d19e8f5597e405e87f90d91f8eb9
|
||||
RNSentry: af7873b080a0beb74c020644644d247ef4771644
|
||||
RNShare: 047d42214f875d731bde73a2b67418638af85ad9
|
||||
RNSVG: 551acb6562324b1d52a4e0758f7ca0ec234e278f
|
||||
RNVectorIcons: 31cebfcf94e8cf8686eb5303ae0357da64d7a5a4
|
||||
Rudder: 3eae52018e1a401d3610b3f16f6210026eb327c8
|
||||
SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d
|
||||
SDWebImageWebPCoder: d0dac55073088d24b2ac1b191a71a8f8d0adac21
|
||||
Sentry: 89d26e036063b9cb9caa59b6951dd2f8277aa13b
|
||||
Sentry: 1d3eb1a25f8c5333c88dd5603904a6d461cd9fcf
|
||||
simdjson: 85016870cd17207312b718ef6652eb6a1cd6a2b0
|
||||
Starscream: 5178aed56b316f13fa3bc55694e583d35dd414d9
|
||||
SwiftyJSON: 2f33a42c6fbc52764d96f13368585094bfd8aa5e
|
||||
Swime: d7b2c277503b6cea317774aedc2dce05613f8b0b
|
||||
@@ -780,11 +785,11 @@ SPEC CHECKSUMS:
|
||||
UMCore: 2f671796d7439604a1cf8ac7bbe5809cd5c50437
|
||||
UMReactNativeAdapter: 684b07b79d5fe52b496d2b50bfe31f68d7daf71a
|
||||
UMTaskManagerInterface: 2be431101b73604e64fbfffcf759336f9d8fccbb
|
||||
WatermelonDB: 1da309a2b3fe35360e92f5a6bda2156543447955
|
||||
WatermelonDB: 577c61fceff16e9f9103b59d14aee4850c0307b6
|
||||
XCDYouTubeKit: 79baadb0560673a67c771eba45f83e353fd12c1f
|
||||
Yoga: 575c581c63e0d35c9a83f4b46d01d63abc1100ac
|
||||
YoutubePlayer-in-WKWebView: cfbf46da51d7370662a695a8f351e5fa1d3e1008
|
||||
|
||||
PODFILE CHECKSUM: 7741358261bad1ae9b7877b2299303396085e050
|
||||
PODFILE CHECKSUM: fe7a8bc870b0f26b5cb70bccd50d5c634a7f5059
|
||||
|
||||
COCOAPODS: 1.10.1
|
||||
|
||||
9775
package-lock.json
generated
9775
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
66
package.json
66
package.json
@@ -7,17 +7,17 @@
|
||||
"license": "Apache 2.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.14.6",
|
||||
"@formatjs/intl-datetimeformat": "4.1.6",
|
||||
"@babel/runtime": "7.14.8",
|
||||
"@formatjs/intl-datetimeformat": "4.2.0",
|
||||
"@formatjs/intl-getcanonicallocales": "1.7.1",
|
||||
"@formatjs/intl-locale": "2.4.33",
|
||||
"@formatjs/intl-numberformat": "7.1.5",
|
||||
"@formatjs/intl-pluralrules": "4.0.28",
|
||||
"@formatjs/intl-relativetimeformat": "9.1.7",
|
||||
"@formatjs/intl-locale": "2.4.34",
|
||||
"@formatjs/intl-numberformat": "7.2.0",
|
||||
"@formatjs/intl-pluralrules": "4.1.0",
|
||||
"@formatjs/intl-relativetimeformat": "9.2.0",
|
||||
"@mattermost/react-native-emm": "1.1.4",
|
||||
"@mattermost/react-native-network-client": "github:mattermost/react-native-network-client",
|
||||
"@mattermost/react-native-paste-input": "0.1.4",
|
||||
"@nozbe/watermelondb": "0.22.0",
|
||||
"@nozbe/watermelondb": "0.23.0",
|
||||
"@nozbe/with-observables": "1.4.0",
|
||||
"@react-native-community/async-storage": "1.12.1",
|
||||
"@react-native-community/cameraroll": "4.0.4",
|
||||
@@ -26,29 +26,29 @@
|
||||
"@react-native-community/netinfo": "6.0.0",
|
||||
"@react-native-cookies/cookies": "6.0.8",
|
||||
"@rudderstack/rudder-sdk-react-native": "1.0.12",
|
||||
"@sentry/react-native": "2.6.0",
|
||||
"@sentry/react-native": "2.6.1",
|
||||
"commonmark": "0.30.0",
|
||||
"commonmark-react-renderer": "4.3.5",
|
||||
"deep-equal": "2.0.5",
|
||||
"deepmerge": "4.2.2",
|
||||
"emoji-regex": "9.2.2",
|
||||
"fuse.js": "6.4.6",
|
||||
"jail-monkey": "2.5.0",
|
||||
"mime-db": "1.48.0",
|
||||
"jail-monkey": "2.6.0",
|
||||
"mime-db": "1.49.0",
|
||||
"moment-timezone": "0.5.33",
|
||||
"nock": "13.1.1",
|
||||
"prop-types": "15.7.2",
|
||||
"react": "17.0.2",
|
||||
"react-intl": "5.20.4",
|
||||
"react-intl": "5.20.6",
|
||||
"react-native": "0.64.2",
|
||||
"react-native-android-open-settings": "1.3.0",
|
||||
"react-native-button": "3.0.1",
|
||||
"react-native-calendars": "1.1264.0",
|
||||
"react-native-device-info": "8.1.3",
|
||||
"react-native-device-info": "8.1.4",
|
||||
"react-native-document-picker": "5.2.0",
|
||||
"react-native-elements": "3.4.2",
|
||||
"react-native-exception-handler": "2.10.10",
|
||||
"react-native-fast-image": "8.3.6",
|
||||
"react-native-fast-image": "8.3.7",
|
||||
"react-native-file-viewer": "2.1.4",
|
||||
"react-native-gesture-handler": "1.10.3",
|
||||
"react-native-haptic-feedback": "1.11.0",
|
||||
@@ -58,16 +58,16 @@
|
||||
"react-native-keychain": "7.0.0",
|
||||
"react-native-linear-gradient": "2.5.6",
|
||||
"react-native-localize": "2.1.1",
|
||||
"react-native-navigation": "7.17.1",
|
||||
"react-native-notifications": "3.5.0",
|
||||
"react-native-navigation": "7.18.1",
|
||||
"react-native-notifications": "4.1.1",
|
||||
"react-native-permissions": "3.0.5",
|
||||
"react-native-reanimated": "2.2.0",
|
||||
"react-native-redash": "16.1.1",
|
||||
"react-native-safe-area-context": "3.2.0",
|
||||
"react-native-share": "6.2.3",
|
||||
"react-native-share": "6.5.0",
|
||||
"react-native-slider": "0.11.0",
|
||||
"react-native-svg": "12.1.1",
|
||||
"react-native-unimodules": "0.14.5",
|
||||
"react-native-unimodules": "0.14.6",
|
||||
"react-native-vector-icons": "8.1.0",
|
||||
"react-native-video": "5.1.1",
|
||||
"react-native-webview": "11.6.5",
|
||||
@@ -77,44 +77,44 @@
|
||||
"serialize-error": "8.1.0",
|
||||
"shallow-equals": "1.0.0",
|
||||
"tinycolor2": "1.4.2",
|
||||
"url-parse": "1.5.1"
|
||||
"url-parse": "1.5.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "7.14.5",
|
||||
"@babel/core": "7.14.6",
|
||||
"@babel/cli": "7.14.8",
|
||||
"@babel/core": "7.14.8",
|
||||
"@babel/plugin-proposal-class-properties": "7.14.5",
|
||||
"@babel/plugin-proposal-decorators": "7.14.5",
|
||||
"@babel/plugin-transform-flow-strip-types": "7.14.5",
|
||||
"@babel/plugin-transform-runtime": "7.14.5",
|
||||
"@babel/preset-env": "7.14.7",
|
||||
"@babel/preset-env": "7.14.8",
|
||||
"@babel/preset-typescript": "7.14.5",
|
||||
"@babel/register": "7.14.5",
|
||||
"@react-native-community/eslint-config": "3.0.0",
|
||||
"@testing-library/react-native": "7.2.0",
|
||||
"@types/jest": "26.0.24",
|
||||
"@types/react": "17.0.14",
|
||||
"@types/react": "17.0.15",
|
||||
"@types/react-intl": "3.0.0",
|
||||
"@types/react-native": "0.64.11",
|
||||
"@types/react-native-button": "3.0.0",
|
||||
"@types/react-native": "0.64.12",
|
||||
"@types/react-native-button": "3.0.1",
|
||||
"@types/react-native-share": "3.3.3",
|
||||
"@types/react-native-video": "5.0.8",
|
||||
"@types/react-test-renderer": "17.0.1",
|
||||
"@types/semver": "7.3.7",
|
||||
"@types/semver": "7.3.8",
|
||||
"@types/shallow-equals": "1.0.0",
|
||||
"@types/tinycolor2": "1.4.3",
|
||||
"@types/url-parse": "1.4.3",
|
||||
"@typescript-eslint/eslint-plugin": "4.28.2",
|
||||
"@typescript-eslint/parser": "4.28.2",
|
||||
"@typescript-eslint/eslint-plugin": "4.28.5",
|
||||
"@typescript-eslint/parser": "4.28.5",
|
||||
"babel-eslint": "10.1.0",
|
||||
"babel-jest": "27.0.6",
|
||||
"babel-loader": "8.2.2",
|
||||
"babel-plugin-module-resolver": "4.1.0",
|
||||
"babel-plugin-transform-remove-console": "6.9.4",
|
||||
"deep-freeze": "0.0.1",
|
||||
"detox": "18.18.1",
|
||||
"eslint": "7.30.0",
|
||||
"detox": "18.20.0",
|
||||
"eslint": "7.31.0",
|
||||
"eslint-plugin-header": "3.1.1",
|
||||
"eslint-plugin-jest": "24.3.6",
|
||||
"eslint-plugin-jest": "24.4.0",
|
||||
"eslint-plugin-mattermost": "github:mattermost/eslint-plugin-mattermost#46ad99355644a719bf32082f472048f526605181",
|
||||
"eslint-plugin-react": "7.24.0",
|
||||
"eslint-plugin-react-hooks": "4.2.0",
|
||||
@@ -123,15 +123,15 @@
|
||||
"jest": "26.6.3",
|
||||
"jest-cli": "26.6.3",
|
||||
"jetifier": "2.0.0",
|
||||
"metro-react-native-babel-preset": "0.66.1",
|
||||
"metro-react-native-babel-preset": "0.66.2",
|
||||
"mmjstool": "github:mattermost/mattermost-utilities#519b99a4e51e6c67a0dbd46a6efdff27dc835aaa",
|
||||
"mock-async-storage": "2.2.0",
|
||||
"patch-package": "6.4.7",
|
||||
"react-native-dev-menu": "4.0.2",
|
||||
"react-native-dotenv": "3.0.0",
|
||||
"react-native-dotenv": "3.1.1",
|
||||
"react-native-storybook-loader": "2.0.4",
|
||||
"react-test-renderer": "17.0.2",
|
||||
"ts-jest": "27.0.3",
|
||||
"ts-jest": "27.0.4",
|
||||
"typescript": "4.3.5",
|
||||
"underscore": "1.13.1",
|
||||
"util": "0.12.4"
|
||||
|
||||
@@ -1,29 +1,20 @@
|
||||
diff --git a/node_modules/@nozbe/watermelondb/adapters/sqlite/index.d.ts b/node_modules/@nozbe/watermelondb/adapters/sqlite/index.d.ts
|
||||
index 4b67b51..6eaa23a 100644
|
||||
index bb8f49a..1036aca 100644
|
||||
--- a/node_modules/@nozbe/watermelondb/adapters/sqlite/index.d.ts
|
||||
+++ b/node_modules/@nozbe/watermelondb/adapters/sqlite/index.d.ts
|
||||
@@ -20,9 +20,16 @@ declare module '@nozbe/watermelondb/adapters/sqlite' {
|
||||
|
||||
export type SQLiteQuery = [SQL, SQLiteArg[]]
|
||||
|
||||
+ export type MigrationEvents = {
|
||||
+ onSuccess: () => void,
|
||||
+ onStart: () => void,
|
||||
+ onError: (error: Error) => void,
|
||||
+ }
|
||||
+
|
||||
@@ -23,6 +23,7 @@ declare module '@nozbe/watermelondb/adapters/sqlite' {
|
||||
export interface SQLiteAdapterOptions {
|
||||
dbName?: string
|
||||
migrations?: SchemaMigrations
|
||||
+ migrationEvents?: MigrationEvents
|
||||
+ migrationEvents?: MigrationEvents,
|
||||
schema: AppSchema
|
||||
synchronous?: boolean
|
||||
jsi?: boolean
|
||||
}
|
||||
diff --git a/node_modules/@nozbe/watermelondb/native/android/src/main/java/com/nozbe/watermelondb/Database.kt b/node_modules/@nozbe/watermelondb/native/android/src/main/java/com/nozbe/watermelondb/Database.kt
|
||||
index 2217222..49a6ff7 100644
|
||||
index 802f137..640b08c 100644
|
||||
--- a/node_modules/@nozbe/watermelondb/native/android/src/main/java/com/nozbe/watermelondb/Database.kt
|
||||
+++ b/node_modules/@nozbe/watermelondb/native/android/src/main/java/com/nozbe/watermelondb/Database.kt
|
||||
@@ -15,6 +15,18 @@ class Database(private val name: String, private val context: Context) {
|
||||
@@ -18,6 +18,18 @@ class Database(private val name: String, private val context: Context) {
|
||||
if (name == ":memory:" || name.contains("mode=memory")) {
|
||||
context.cacheDir.delete()
|
||||
File(context.cacheDir, name).path
|
||||
@@ -1,9 +1,9 @@
|
||||
diff --git a/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java b/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java
|
||||
index 3b4e398..8e91f6b 100644
|
||||
index 2b30edf..2063845 100644
|
||||
--- a/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java
|
||||
+++ b/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java
|
||||
@@ -55,14 +55,18 @@ public class NavigationModule extends ReactContextBaseJavaModule {
|
||||
reactContext.addLifecycleEventListener(new LifecycleEventListenerAdapter() {
|
||||
@@ -61,15 +61,19 @@ public class NavigationModule extends ReactContextBaseJavaModule {
|
||||
|
||||
@Override
|
||||
public void onHostResume() {
|
||||
- eventEmitter = new EventEmitter(reactContext);
|
||||
@@ -14,6 +14,7 @@ index 3b4e398..8e91f6b 100644
|
||||
- navigator().getChildRegistry(),
|
||||
- ((NavigationApplication) activity().getApplication()).getExternalComponents()
|
||||
- );
|
||||
- navigator().onHostResume();
|
||||
+ try {
|
||||
+ eventEmitter = new EventEmitter(reactContext);
|
||||
+ navigator().setEventEmitter(eventEmitter);
|
||||
@@ -23,13 +24,14 @@ index 3b4e398..8e91f6b 100644
|
||||
+ navigator().getChildRegistry(),
|
||||
+ ((NavigationApplication) activity().getApplication()).getExternalComponents()
|
||||
+ );
|
||||
+ navigator().onHostResume();
|
||||
+ } catch (ClassCastException e) {
|
||||
+ // The most current activity is not a NavigationActivity
|
||||
+ }
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -210,8 +214,12 @@ public class NavigationModule extends ReactContextBaseJavaModule {
|
||||
@@ -217,8 +221,12 @@ public class NavigationModule extends ReactContextBaseJavaModule {
|
||||
|
||||
protected void handle(Runnable task) {
|
||||
UiThread.post(() -> {
|
||||
@@ -40,7 +42,7 @@ index 3b4e398..8e91f6b 100644
|
||||
+ task.run();
|
||||
+ }
|
||||
+ } catch (ClassCastException e) {
|
||||
+ // The most current activity is not a NavigationActivity
|
||||
+ // The most current activity is not a NavigationActivity)
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -71,28 +73,27 @@ index 1e5751e..f921605 100644
|
||||
view.setOnHierarchyChangeListener(null);
|
||||
if (view.getParent() instanceof ViewGroup) {
|
||||
diff --git a/node_modules/react-native-navigation/lib/ios/RNNOverlayWindow.m b/node_modules/react-native-navigation/lib/ios/RNNOverlayWindow.m
|
||||
index 815e1c6..a35a087 100644
|
||||
index 934e7e7..19169a3 100644
|
||||
--- a/node_modules/react-native-navigation/lib/ios/RNNOverlayWindow.m
|
||||
+++ b/node_modules/react-native-navigation/lib/ios/RNNOverlayWindow.m
|
||||
@@ -1,5 +1,7 @@
|
||||
@@ -1,6 +1,8 @@
|
||||
#import "RNNOverlayWindow.h"
|
||||
#import "RNNReactView.h"
|
||||
#import <React/RCTModalHostView.h>
|
||||
+#import <react-native-safe-area-context/RNCSafeAreaView.h>
|
||||
+#import <react-native-safe-area-context/RNCSafeAreaProvider.h>
|
||||
|
||||
@implementation RNNOverlayWindow
|
||||
|
||||
@@ -7,7 +9,9 @@
|
||||
UIView *hitTestResult = [super hitTest:point withEvent:event];
|
||||
@@ -9,6 +11,8 @@
|
||||
|
||||
if ([hitTestResult isKindOfClass:[UIWindow class]] ||
|
||||
- [hitTestResult.subviews.firstObject isKindOfClass:RNNReactView.class]) {
|
||||
+ [hitTestResult.subviews.firstObject isKindOfClass:RNNReactView.class] ||
|
||||
[hitTestResult.subviews.firstObject isKindOfClass:RNNReactView.class] ||
|
||||
+ [hitTestResult isKindOfClass:[RNCSafeAreaView class]] ||
|
||||
+ [hitTestResult isKindOfClass:[RNCSafeAreaProvider class]]) {
|
||||
+ [hitTestResult isKindOfClass:[RNCSafeAreaProvider class]] ||
|
||||
[hitTestResult isKindOfClass:[RCTModalHostView class]]) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
diff --git a/node_modules/react-native-navigation/lib/ios/RNNViewLocation.m b/node_modules/react-native-navigation/lib/ios/RNNViewLocation.m
|
||||
index 2e60123..56830c8 100644
|
||||
--- a/node_modules/react-native-navigation/lib/ios/RNNViewLocation.m
|
||||
@@ -173,25 +173,21 @@ index 0d70024..b9e6c88 100644
|
||||
PushNotificationProps asProps();
|
||||
}
|
||||
diff --git a/node_modules/react-native-notifications/lib/android/app/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java b/node_modules/react-native-notifications/lib/android/app/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java
|
||||
index f6ac8ec..08154fc 100644
|
||||
index fe1fb94..c9e0301 100644
|
||||
--- a/node_modules/react-native-notifications/lib/android/app/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java
|
||||
+++ b/node_modules/react-native-notifications/lib/android/app/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.wix.reactnativenotifications.core.notification;
|
||||
|
||||
+import android.app.AlarmManager;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
@@ -8,6 +9,7 @@ import android.content.Context;
|
||||
@@ -8,6 +8,10 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
+import android.util.Log;
|
||||
+
|
||||
+import androidx.core.app.NotificationCompat;
|
||||
+import androidx.core.app.NotificationManagerCompat;
|
||||
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.wix.reactnativenotifications.core.AppLaunchHelper;
|
||||
@@ -18,7 +20,9 @@ import com.wix.reactnativenotifications.core.InitialNotificationHolder;
|
||||
@@ -18,7 +22,9 @@ import com.wix.reactnativenotifications.core.InitialNotificationHolder;
|
||||
import com.wix.reactnativenotifications.core.JsIOHelper;
|
||||
import com.wix.reactnativenotifications.core.NotificationIntentAdapter;
|
||||
import com.wix.reactnativenotifications.core.ProxyService;
|
||||
@@ -201,7 +197,7 @@ index f6ac8ec..08154fc 100644
|
||||
import static com.wix.reactnativenotifications.Defs.NOTIFICATION_OPENED_EVENT_NAME;
|
||||
import static com.wix.reactnativenotifications.Defs.NOTIFICATION_RECEIVED_EVENT_NAME;
|
||||
import static com.wix.reactnativenotifications.Defs.NOTIFICATION_RECEIVED_BACKGROUND_EVENT_NAME;
|
||||
@@ -29,7 +33,7 @@ public class PushNotification implements IPushNotification {
|
||||
@@ -29,7 +35,7 @@ public class PushNotification implements IPushNotification {
|
||||
final protected AppLifecycleFacade mAppLifecycleFacade;
|
||||
final protected AppLaunchHelper mAppLaunchHelper;
|
||||
final protected JsIOHelper mJsIOHelper;
|
||||
@@ -210,7 +206,16 @@ index f6ac8ec..08154fc 100644
|
||||
final protected AppVisibilityListener mAppVisibilityListener = new AppVisibilityListener() {
|
||||
@Override
|
||||
public void onAppVisible() {
|
||||
@@ -78,6 +82,42 @@ public class PushNotification implements IPushNotification {
|
||||
@@ -62,7 +68,7 @@ public class PushNotification implements IPushNotification {
|
||||
}
|
||||
|
||||
@Override
|
||||
- public void onReceived() throws InvalidNotificationException {
|
||||
+ public void onReceived() {
|
||||
if (!mAppLifecycleFacade.isAppVisible()) {
|
||||
postNotification(null);
|
||||
notifyReceivedBackgroundToJS();
|
||||
@@ -81,6 +87,41 @@ public class PushNotification implements IPushNotification {
|
||||
return postNotification(notificationId);
|
||||
}
|
||||
|
||||
@@ -248,25 +253,61 @@ index f6ac8ec..08154fc 100644
|
||||
+
|
||||
+ return postNotification(notificationId);
|
||||
+ }
|
||||
+
|
||||
+
|
||||
@Override
|
||||
public PushNotificationProps asProps() {
|
||||
return mNotificationProps.copy();
|
||||
@@ -140,7 +180,9 @@ public class PushNotification implements IPushNotification {
|
||||
@@ -143,15 +184,16 @@ public class PushNotification implements IPushNotification {
|
||||
}
|
||||
|
||||
protected Notification buildNotification(PendingIntent intent) {
|
||||
- return getNotificationBuilder(intent).build();
|
||||
+ Notification.Builder builder = getNotificationBuilder(intent);
|
||||
+ Notification notification = builder.build();
|
||||
+ return notification;
|
||||
+ NotificationCompat.Builder builder = getNotificationBuilder(intent);
|
||||
+ return builder.build();
|
||||
}
|
||||
|
||||
- protected Notification.Builder getNotificationBuilder(PendingIntent intent) {
|
||||
- final Notification.Builder notification = new Notification.Builder(mContext)
|
||||
+ protected NotificationCompat.Builder getNotificationBuilder(PendingIntent intent) {
|
||||
+ final NotificationCompat.Builder notification = new NotificationCompat.Builder(mContext, DEFAULT_CHANNEL_ID)
|
||||
.setContentTitle(mNotificationProps.getTitle())
|
||||
.setContentText(mNotificationProps.getBody())
|
||||
.setContentIntent(intent)
|
||||
- .setDefaults(Notification.DEFAULT_ALL)
|
||||
+ .setDefaults(NotificationCompat.DEFAULT_ALL)
|
||||
.setAutoCancel(true);
|
||||
|
||||
setUpIcon(notification);
|
||||
@@ -166,7 +208,7 @@ public class PushNotification implements IPushNotification {
|
||||
return notification;
|
||||
}
|
||||
|
||||
- private void setUpIcon(Notification.Builder notification) {
|
||||
+ private void setUpIcon(NotificationCompat.Builder notification) {
|
||||
int iconResId = getAppResourceId("notification_icon", "drawable");
|
||||
if (iconResId != 0) {
|
||||
notification.setSmallIcon(iconResId);
|
||||
@@ -177,7 +219,7 @@ public class PushNotification implements IPushNotification {
|
||||
setUpIconColor(notification);
|
||||
}
|
||||
|
||||
- private void setUpIconColor(Notification.Builder notification) {
|
||||
+ private void setUpIconColor(NotificationCompat.Builder notification) {
|
||||
int colorResID = getAppResourceId("colorAccent", "color");
|
||||
if (colorResID != 0 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
int color = mContext.getResources().getColor(colorResID);
|
||||
@@ -192,7 +234,7 @@ public class PushNotification implements IPushNotification {
|
||||
}
|
||||
|
||||
protected void postNotification(int id, Notification notification) {
|
||||
- final NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
+ final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(mContext);
|
||||
notificationManager.notify(id, notification);
|
||||
}
|
||||
|
||||
protected Notification.Builder getNotificationBuilder(PendingIntent intent) {
|
||||
diff --git a/node_modules/react-native-notifications/lib/android/app/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotificationPublisher.java b/node_modules/react-native-notifications/lib/android/app/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotificationPublisher.java
|
||||
new file mode 100644
|
||||
index 0000000..58ff887
|
||||
index 0000000..5b64593
|
||||
--- /dev/null
|
||||
+++ b/node_modules/react-native-notifications/lib/android/app/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotificationPublisher.java
|
||||
@@ -0,0 +1,27 @@
|
||||
@@ -297,6 +338,7 @@ index 0000000..58ff887
|
||||
+ pushNotification.onPostScheduledRequest(notificationId);
|
||||
+ }
|
||||
+}
|
||||
\ No newline at end of file
|
||||
diff --git a/node_modules/react-native-notifications/lib/android/app/src/main/java/com/wix/reactnativenotifications/core/notificationdrawer/IPushNotificationsDrawer.java b/node_modules/react-native-notifications/lib/android/app/src/main/java/com/wix/reactnativenotifications/core/notificationdrawer/IPushNotificationsDrawer.java
|
||||
index e22cd62..48aa1cd 100644
|
||||
--- a/node_modules/react-native-notifications/lib/android/app/src/main/java/com/wix/reactnativenotifications/core/notificationdrawer/IPushNotificationsDrawer.java
|
||||
@@ -388,13 +430,13 @@ index ad7fc1a..a04ec6b 100644
|
||||
get title() {
|
||||
return this.payload.title;
|
||||
diff --git a/node_modules/react-native-notifications/lib/dist/Notifications.d.ts b/node_modules/react-native-notifications/lib/dist/Notifications.d.ts
|
||||
index 3a75bcf..10600d2 100644
|
||||
index 6e49fd4..1d94217 100644
|
||||
--- a/node_modules/react-native-notifications/lib/dist/Notifications.d.ts
|
||||
+++ b/node_modules/react-native-notifications/lib/dist/Notifications.d.ts
|
||||
@@ -36,6 +36,10 @@ export declare class NotificationsRoot {
|
||||
@@ -37,6 +37,10 @@ export declare class NotificationsRoot {
|
||||
* cancelLocalNotification
|
||||
*/
|
||||
cancelLocalNotification(notificationId: string): void;
|
||||
cancelLocalNotification(notificationId: number): void;
|
||||
+ /**
|
||||
+ * cancelAllLocalNotifications
|
||||
+ */
|
||||
@@ -403,7 +445,7 @@ index 3a75bcf..10600d2 100644
|
||||
* removeAllDeliveredNotifications
|
||||
*/
|
||||
diff --git a/node_modules/react-native-notifications/lib/dist/Notifications.js b/node_modules/react-native-notifications/lib/dist/Notifications.js
|
||||
index 15eea09..48b3d23 100644
|
||||
index 44ab53f..8000701 100644
|
||||
--- a/node_modules/react-native-notifications/lib/dist/Notifications.js
|
||||
+++ b/node_modules/react-native-notifications/lib/dist/Notifications.js
|
||||
@@ -55,6 +55,12 @@ class NotificationsRoot {
|
||||
@@ -431,10 +473,10 @@ index 0e78cb5..ae90bd1 100644
|
||||
+ constructor(identifier: string, activationMode: 'background' | 'foreground' | 'authenticationRequired' | 'destructive', title: string, authenticationRequired: boolean, textInput?: NotificationTextInput);
|
||||
}
|
||||
diff --git a/node_modules/react-native-notifications/lib/ios/RNNotificationCenter.m b/node_modules/react-native-notifications/lib/ios/RNNotificationCenter.m
|
||||
index 0a30b5a..a45a83d 100644
|
||||
index 7452523..a093262 100644
|
||||
--- a/node_modules/react-native-notifications/lib/ios/RNNotificationCenter.m
|
||||
+++ b/node_modules/react-native-notifications/lib/ios/RNNotificationCenter.m
|
||||
@@ -58,7 +58,7 @@ - (void)getDeliveredNotifications:(RCTResponseSenderBlock)callback {
|
||||
@@ -83,7 +83,7 @@
|
||||
for (UNNotification *notification in notifications) {
|
||||
[formattedNotifications addObject:[RCTConvert UNNotificationPayload:notification]];
|
||||
}
|
||||
@@ -444,10 +486,10 @@ index 0a30b5a..a45a83d 100644
|
||||
}
|
||||
|
||||
diff --git a/node_modules/react-native-notifications/lib/src/Notifications.ts b/node_modules/react-native-notifications/lib/src/Notifications.ts
|
||||
index 8a4a51e..551fac2 100644
|
||||
index 0848f6d..ceb271d 100644
|
||||
--- a/node_modules/react-native-notifications/lib/src/Notifications.ts
|
||||
+++ b/node_modules/react-native-notifications/lib/src/Notifications.ts
|
||||
@@ -79,6 +79,13 @@ export class NotificationsRoot {
|
||||
@@ -80,6 +80,13 @@ export class NotificationsRoot {
|
||||
return this.commands.cancelLocalNotification(notificationId);
|
||||
}
|
||||
|
||||
@@ -462,7 +504,7 @@ index 8a4a51e..551fac2 100644
|
||||
* removeAllDeliveredNotifications
|
||||
*/
|
||||
diff --git a/node_modules/react-native-notifications/lib/src/NotificationsIOS.ts b/node_modules/react-native-notifications/lib/src/NotificationsIOS.ts
|
||||
index b4218ab..38388c5 100644
|
||||
index 98fc19d..0c8ea3d 100644
|
||||
--- a/node_modules/react-native-notifications/lib/src/NotificationsIOS.ts
|
||||
+++ b/node_modules/react-native-notifications/lib/src/NotificationsIOS.ts
|
||||
@@ -52,13 +52,6 @@ export class NotificationsIOS {
|
||||
Reference in New Issue
Block a user