[NEW] Reply notification (#1448)
This commit is contained in:
parent
9084f22ab1
commit
5f0389c7de
|
@ -217,6 +217,10 @@ dependencies {
|
|||
} else {
|
||||
implementation jscFlavor
|
||||
}
|
||||
|
||||
implementation "com.google.code.gson:gson:2.8.5"
|
||||
implementation "com.github.bumptech.glide:glide:4.9.0"
|
||||
annotationProcessor "com.github.bumptech.glide:compiler:4.9.0"
|
||||
}
|
||||
|
||||
// Run this once to be able to run the application with BUCK
|
||||
|
|
|
@ -47,6 +47,15 @@
|
|||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
|
||||
<receiver
|
||||
android:name=".ReplyBroadcast"
|
||||
android:enabled="true"
|
||||
android:exported="false" />
|
||||
<receiver
|
||||
android:name=".DismissNotification"
|
||||
android:enabled="true"
|
||||
android:exported="false" >
|
||||
</receiver>
|
||||
<activity
|
||||
android:noHistory="true"
|
||||
android:name=".share.ShareActivity"
|
||||
|
|
|
@ -4,56 +4,139 @@ import android.app.Notification;
|
|||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.RemoteInput;
|
||||
import android.content.Intent;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.media.AudioManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings.System;
|
||||
import android.media.RingtoneManager;
|
||||
|
||||
import com.google.gson.*;
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.lang.InterruptedException;
|
||||
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.wix.reactnativenotifications.core.AppLaunchHelper;
|
||||
import com.wix.reactnativenotifications.core.AppLifecycleFacade;
|
||||
import com.wix.reactnativenotifications.core.JsIOHelper;
|
||||
import com.wix.reactnativenotifications.core.notification.PushNotification;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static com.wix.reactnativenotifications.Defs.NOTIFICATION_RECEIVED_EVENT_NAME;
|
||||
|
||||
public class CustomPushNotification extends PushNotification {
|
||||
public static ReactApplicationContext reactApplicationContext;
|
||||
|
||||
public CustomPushNotification(Context context, Bundle bundle, AppLifecycleFacade appLifecycleFacade, AppLaunchHelper appLaunchHelper, JsIOHelper jsIoHelper) {
|
||||
super(context, bundle, appLifecycleFacade, appLaunchHelper, jsIoHelper);
|
||||
reactApplicationContext = new ReactApplicationContext(context);
|
||||
}
|
||||
|
||||
private static Map<String, List<String>> notificationMessages = new HashMap<String, List<String>>();
|
||||
public static String KEY_REPLY = "KEY_REPLY";
|
||||
public static String NOTIFICATION_ID = "NOTIFICATION_ID";
|
||||
|
||||
public static void clearMessages(int notId) {
|
||||
notificationMessages.remove(Integer.toString(notId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceived() throws InvalidNotificationException {
|
||||
final Bundle bundle = mNotificationProps.asBundle();
|
||||
|
||||
String notId = bundle.getString("notId");
|
||||
String message = bundle.getString("message");
|
||||
|
||||
if (notificationMessages.get(notId) == null) {
|
||||
notificationMessages.put(notId, new ArrayList<String>());
|
||||
}
|
||||
notificationMessages.get(notId).add(message);
|
||||
|
||||
super.postNotification(Integer.parseInt(notId));
|
||||
|
||||
notifyReceivedToJS();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpened() {
|
||||
Bundle bundle = mNotificationProps.asBundle();
|
||||
final String notId = bundle.getString("notId");
|
||||
notificationMessages.remove(notId);
|
||||
digestNotification();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Notification.Builder getNotificationBuilder(PendingIntent intent) {
|
||||
final Resources res = mContext.getResources();
|
||||
String packageName = mContext.getPackageName();
|
||||
final Notification.Builder notification = new Notification.Builder(mContext);
|
||||
|
||||
Bundle bundle = mNotificationProps.asBundle();
|
||||
int smallIconResId = res.getIdentifier("ic_notification", "mipmap", packageName);
|
||||
int largeIconResId = res.getIdentifier("ic_launcher", "mipmap", packageName);
|
||||
String title = bundle.getString("title");
|
||||
String message = bundle.getString("message");
|
||||
String notId = bundle.getString("notId");
|
||||
|
||||
String CHANNEL_ID = "rocketchatrn_channel_01";
|
||||
String CHANNEL_NAME = "All";
|
||||
|
||||
final Notification.Builder notification = new Notification.Builder(mContext)
|
||||
.setSmallIcon(smallIconResId)
|
||||
notification
|
||||
.setContentIntent(intent)
|
||||
.setContentTitle(title)
|
||||
.setContentText(message)
|
||||
.setStyle(new Notification.BigTextStyle().bigText(message))
|
||||
.setPriority(Notification.PRIORITY_HIGH)
|
||||
.setDefaults(Notification.DEFAULT_ALL)
|
||||
.setAutoCancel(true);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
notification.setColor(mContext.getColor(R.color.notification_text));
|
||||
Integer notificationId = Integer.parseInt(notId);
|
||||
notificationChannel(notification);
|
||||
notificationIcons(notification, bundle);
|
||||
notificationStyle(notification, notificationId, bundle);
|
||||
notificationReply(notification, notificationId, bundle);
|
||||
notificationDismiss(notification, notificationId);
|
||||
|
||||
return notification;
|
||||
}
|
||||
|
||||
private void notifyReceivedToJS() {
|
||||
mJsIOHelper.sendEventToJS(NOTIFICATION_RECEIVED_EVENT_NAME, mNotificationProps.asBundle(), mAppLifecycleFacade.getRunningReactContext());
|
||||
}
|
||||
|
||||
private Bitmap getAvatar(String uri) {
|
||||
try {
|
||||
return Glide.with(mContext)
|
||||
.asBitmap()
|
||||
.apply(RequestOptions.bitmapTransform(new RoundedCorners(10)))
|
||||
.load(uri)
|
||||
.submit(100, 100)
|
||||
.get();
|
||||
} catch (final ExecutionException | InterruptedException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void notificationIcons(Notification.Builder notification, Bundle bundle) {
|
||||
final Resources res = mContext.getResources();
|
||||
String packageName = mContext.getPackageName();
|
||||
|
||||
int smallIconResId = res.getIdentifier("ic_notification", "mipmap", packageName);
|
||||
|
||||
Gson gson = new Gson();
|
||||
Ejson ejson = gson.fromJson(bundle.getString("ejson", "{}"), Ejson.class);
|
||||
|
||||
notification
|
||||
.setSmallIcon(smallIconResId)
|
||||
.setLargeIcon(getAvatar(ejson.getAvatarUri()));
|
||||
}
|
||||
|
||||
private void notificationChannel(Notification.Builder notification) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
String CHANNEL_ID = "rocketchatrn_channel_01";
|
||||
String CHANNEL_NAME = "All";
|
||||
|
||||
NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
|
||||
CHANNEL_NAME,
|
||||
NotificationManager.IMPORTANCE_DEFAULT);
|
||||
|
@ -63,10 +146,65 @@ public class CustomPushNotification extends PushNotification {
|
|||
|
||||
notification.setChannelId(CHANNEL_ID);
|
||||
}
|
||||
|
||||
Bitmap largeIconBitmap = BitmapFactory.decodeResource(res, largeIconResId);
|
||||
notification.setLargeIcon(largeIconBitmap);
|
||||
|
||||
return notification;
|
||||
}
|
||||
|
||||
private void notificationStyle(Notification.Builder notification, int notId, Bundle bundle) {
|
||||
Notification.InboxStyle messageStyle = new Notification.InboxStyle();
|
||||
List<String> messages = notificationMessages.get(Integer.toString(notId));
|
||||
if (messages != null) {
|
||||
for (int i = 0; i < messages.size(); i++) {
|
||||
messageStyle.addLine(messages.get(i));
|
||||
}
|
||||
String summary = bundle.getString("summaryText");
|
||||
messageStyle.setSummaryText(summary.replace("%n%", Integer.toString(messages.size())));
|
||||
notification.setNumber(messages.size());
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
notification.setColor(mContext.getColor(R.color.notification_text));
|
||||
}
|
||||
|
||||
notification.setStyle(messageStyle);
|
||||
}
|
||||
|
||||
private void notificationReply(Notification.Builder notification, int notificationId, Bundle bundle) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
|
||||
return;
|
||||
}
|
||||
String label = "Reply";
|
||||
|
||||
final Resources res = mContext.getResources();
|
||||
String packageName = mContext.getPackageName();
|
||||
int smallIconResId = res.getIdentifier("ic_notification", "mipmap", packageName);
|
||||
|
||||
Intent replyIntent = new Intent(mContext, ReplyBroadcast.class);
|
||||
replyIntent.setAction(KEY_REPLY);
|
||||
replyIntent.putExtra("pushNotification", bundle);
|
||||
|
||||
PendingIntent replyPendingIntent = PendingIntent.getBroadcast(mContext, notificationId, replyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
RemoteInput remoteInput = new RemoteInput.Builder(KEY_REPLY)
|
||||
.setLabel(label)
|
||||
.build();
|
||||
|
||||
CharSequence title = label;
|
||||
Notification.Action replyAction = new Notification.Action.Builder(smallIconResId, title, replyPendingIntent)
|
||||
.addRemoteInput(remoteInput)
|
||||
.setAllowGeneratedReplies(true)
|
||||
.build();
|
||||
|
||||
notification
|
||||
.setShowWhen(true)
|
||||
.addAction(replyAction);
|
||||
}
|
||||
|
||||
private void notificationDismiss(Notification.Builder notification, int notificationId) {
|
||||
Intent intent = new Intent(mContext, DismissNotification.class);
|
||||
intent.putExtra(NOTIFICATION_ID, notificationId);
|
||||
|
||||
PendingIntent dismissPendingIntent = PendingIntent.getBroadcast(mContext, notificationId, intent, 0);
|
||||
|
||||
notification.setDeleteIntent(dismissPendingIntent);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package chat.rocket.reactnative;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
public class DismissNotification extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
int notId = intent.getExtras().getInt(CustomPushNotification.NOTIFICATION_ID);
|
||||
CustomPushNotification.clearMessages(notId);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package chat.rocket.reactnative;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import chat.rocket.userdefaults.RNUserDefaultsModule;
|
||||
|
||||
public class Ejson {
|
||||
String host;
|
||||
String rid;
|
||||
String type;
|
||||
Sender sender;
|
||||
|
||||
private String TOKEN_KEY = "reactnativemeteor_usertoken-";
|
||||
private SharedPreferences sharedPreferences = RNUserDefaultsModule.getPreferences(CustomPushNotification.reactApplicationContext);
|
||||
|
||||
public String getAvatarUri() {
|
||||
if (!type.equals("d")) {
|
||||
return null;
|
||||
}
|
||||
return serverURL() + "/avatar/" + this.sender.username + "?rc_token=" + token() + "&rc_uid=" + userId();
|
||||
}
|
||||
|
||||
public String token() {
|
||||
return sharedPreferences.getString(TOKEN_KEY.concat(userId()), "");
|
||||
}
|
||||
|
||||
public String userId() {
|
||||
return sharedPreferences.getString(TOKEN_KEY.concat(serverURL()), "");
|
||||
}
|
||||
|
||||
public String serverURL() {
|
||||
String url = this.host;
|
||||
if (url.endsWith("/")) {
|
||||
url = url.substring(0, url.length() - 1);
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
private class Sender {
|
||||
String username;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
package chat.rocket.reactnative;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.RemoteInput;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import okhttp3.Call;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
|
||||
import chat.rocket.userdefaults.RNUserDefaultsModule;
|
||||
import com.wix.reactnativenotifications.core.NotificationIntentAdapter;
|
||||
|
||||
public class ReplyBroadcast extends BroadcastReceiver {
|
||||
private Context mContext;
|
||||
private Bundle bundle;
|
||||
private NotificationManager notificationManager;
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
|
||||
final CharSequence message = getReplyMessage(intent);
|
||||
if (message == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mContext = context;
|
||||
bundle = NotificationIntentAdapter.extractPendingNotificationDataFromIntent(intent);
|
||||
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
String notId = bundle.getString("notId");
|
||||
|
||||
Gson gson = new Gson();
|
||||
Ejson ejson = gson.fromJson(bundle.getString("ejson", "{}"), Ejson.class);
|
||||
|
||||
replyToMessage(ejson, Integer.parseInt(notId), message);
|
||||
}
|
||||
}
|
||||
|
||||
protected void replyToMessage(final Ejson ejson, final int notId, final CharSequence message) {
|
||||
String serverURL = ejson.serverURL();
|
||||
String rid = ejson.rid;
|
||||
|
||||
if (serverURL == null || rid == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final OkHttpClient client = new OkHttpClient();
|
||||
final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
|
||||
|
||||
String json = buildMessage(rid, message.toString());
|
||||
|
||||
CustomPushNotification.clearMessages(notId);
|
||||
|
||||
RequestBody body = RequestBody.create(JSON, json);
|
||||
Request request = new Request.Builder()
|
||||
.header("x-auth-token", ejson.token())
|
||||
.header("x-user-id", ejson.userId())
|
||||
.url(String.format("%s/api/v1/chat.sendMessage", serverURL))
|
||||
.post(body)
|
||||
.build();
|
||||
|
||||
client.newCall(request).enqueue(new okhttp3.Callback() {
|
||||
@Override
|
||||
public void onFailure(Call call, IOException e) {
|
||||
Log.i("RCNotification", String.format("Reply FAILED exception %s", e.getMessage()));
|
||||
onReplyFailed(notificationManager, notId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Call call, final Response response) throws IOException {
|
||||
if (response.isSuccessful()) {
|
||||
Log.d("RCNotification", "Reply SUCCESS");
|
||||
onReplySuccess(notificationManager, notId);
|
||||
} else {
|
||||
Log.i("RCNotification", String.format("Reply FAILED status %s BODY %s", response.code(), response.body().string()));
|
||||
onReplyFailed(notificationManager, notId);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private String getMessageId() {
|
||||
final String ALPHA_NUMERIC_STRING = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
int count = 17;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
while (count-- != 0) {
|
||||
int character = (int)(Math.random()*ALPHA_NUMERIC_STRING.length());
|
||||
builder.append(ALPHA_NUMERIC_STRING.charAt(character));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
protected String buildMessage(String rid, String message) {
|
||||
Gson gsonBuilder = new GsonBuilder().create();
|
||||
|
||||
Map msgMap = new HashMap();
|
||||
msgMap.put("_id", getMessageId());
|
||||
msgMap.put("rid", rid);
|
||||
msgMap.put("msg", message);
|
||||
msgMap.put("tmid", null);
|
||||
|
||||
Map msg = new HashMap();
|
||||
msg.put("message", msgMap);
|
||||
|
||||
String json = gsonBuilder.toJson(msg);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
protected void onReplyFailed(NotificationManager notificationManager, int notId) {
|
||||
String CHANNEL_ID = "CHANNEL_ID_REPLY_FAILED";
|
||||
|
||||
final Resources res = mContext.getResources();
|
||||
String packageName = mContext.getPackageName();
|
||||
int smallIconResId = res.getIdentifier("ic_notification", "mipmap", packageName);
|
||||
|
||||
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_ID, NotificationManager.IMPORTANCE_LOW);
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
Notification notification =
|
||||
new Notification.Builder(mContext, CHANNEL_ID)
|
||||
.setContentTitle("Failed to reply message.")
|
||||
.setSmallIcon(smallIconResId)
|
||||
.build();
|
||||
|
||||
notificationManager.notify(notId, notification);
|
||||
}
|
||||
|
||||
protected void onReplySuccess(NotificationManager notificationManager, int notId) {
|
||||
notificationManager.cancel(notId);
|
||||
}
|
||||
|
||||
private CharSequence getReplyMessage(Intent intent) {
|
||||
Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
|
||||
if (remoteInput != null) {
|
||||
return remoteInput.getCharSequence(CustomPushNotification.KEY_REPLY);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,17 @@
|
|||
import NotificationsIOS from 'react-native-notifications';
|
||||
import NotificationsIOS, { NotificationAction, NotificationCategory } from 'react-native-notifications';
|
||||
|
||||
import reduxStore from '../../lib/createStore';
|
||||
import I18n from '../../i18n';
|
||||
|
||||
const replyAction = new NotificationAction({
|
||||
activationMode: 'background',
|
||||
title: I18n.t('Reply'),
|
||||
textInput: {
|
||||
buttonTitle: I18n.t('Reply'),
|
||||
placeholder: I18n.t('Type_message')
|
||||
},
|
||||
identifier: 'REPLY_ACTION'
|
||||
});
|
||||
|
||||
class PushNotification {
|
||||
constructor() {
|
||||
|
@ -20,7 +31,12 @@ class PushNotification {
|
|||
completion();
|
||||
});
|
||||
|
||||
NotificationsIOS.requestPermissions();
|
||||
const actions = [];
|
||||
actions.push(new NotificationCategory({
|
||||
identifier: 'MESSAGE',
|
||||
actions: [replyAction]
|
||||
}));
|
||||
NotificationsIOS.requestPermissions(actions);
|
||||
}
|
||||
|
||||
getDeviceToken() {
|
||||
|
|
|
@ -111,6 +111,7 @@ const handleLoginSuccess = function* handleLoginSuccess({ user }) {
|
|||
});
|
||||
|
||||
yield RNUserDefaults.set(`${ RocketChat.TOKEN_KEY }-${ server }`, user.id);
|
||||
yield RNUserDefaults.set(`${ RocketChat.TOKEN_KEY }-${ user.id }`, user.token);
|
||||
yield put(setUser(user));
|
||||
EventEmitter.emit('connected');
|
||||
|
||||
|
|
|
@ -381,7 +381,7 @@ PODS:
|
|||
- React
|
||||
- RNScreens (2.0.0-alpha.3):
|
||||
- React
|
||||
- RNUserDefaults (1.3.5):
|
||||
- RNUserDefaults (1.7.0):
|
||||
- React
|
||||
- RNVectorIcons (6.6.0):
|
||||
- React
|
||||
|
@ -756,7 +756,7 @@ SPEC CHECKSUMS:
|
|||
RNReanimated: b2ab0b693dddd2339bd2f300e770f6302d2e960c
|
||||
RNRootView: 895a4813dedeaca82db2fa868ca1c333d790e494
|
||||
RNScreens: 402a99b0a27c0c32f079cec12d3ccbd35e20cd7f
|
||||
RNUserDefaults: 8a4928443510aa99e4ccb3b53f1bf186593d690b
|
||||
RNUserDefaults: af71a1cdf1c12baf8210bc741c65f5faba9826d6
|
||||
RNVectorIcons: 0bb4def82230be1333ddaeee9fcba45f0b288ed4
|
||||
RSKImageCropper: a446db0e8444a036b34f3c43db01b2373baa4b2a
|
||||
SDWebImage: 96d7f03415ccb28d299d765f93557ff8a617abd8
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
{
|
||||
"name": "RNUserDefaults",
|
||||
"version": "1.3.5",
|
||||
"summary": "Use `UserDefaults` (iOS) with React Native and `AsyncStorage` on AndroidOS.",
|
||||
"description": "Use `UserDefaults` (iOS) with React Native and `AsyncStorage` on AndroidOS.",
|
||||
"version": "1.7.0",
|
||||
"summary": "Use `UserDefaults` (iOS) with React Native and `SharedPreferences` on AndroidOS.",
|
||||
"description": "Use `UserDefaults` (iOS) with React Native and `SharedPreferences` on AndroidOS.",
|
||||
"license": "MIT",
|
||||
"authors": "djorkaeffalexandre",
|
||||
"homepage": "https://github.com/djorkaeffalexandre/rn-user-defaults",
|
||||
"homepage": "https://github.com/RocketChat/rn-user-defaults.git",
|
||||
"source": {
|
||||
"git": "https://github.com/djorkaeffalexandre/rn-user-defaults.git"
|
||||
"git": "https://github.com/RocketChat/rn-user-defaults.git"
|
||||
},
|
||||
"requires_arc": true,
|
||||
"platforms": {
|
||||
|
|
|
@ -381,7 +381,7 @@ PODS:
|
|||
- React
|
||||
- RNScreens (2.0.0-alpha.3):
|
||||
- React
|
||||
- RNUserDefaults (1.3.5):
|
||||
- RNUserDefaults (1.7.0):
|
||||
- React
|
||||
- RNVectorIcons (6.6.0):
|
||||
- React
|
||||
|
@ -756,7 +756,7 @@ SPEC CHECKSUMS:
|
|||
RNReanimated: b2ab0b693dddd2339bd2f300e770f6302d2e960c
|
||||
RNRootView: 895a4813dedeaca82db2fa868ca1c333d790e494
|
||||
RNScreens: 402a99b0a27c0c32f079cec12d3ccbd35e20cd7f
|
||||
RNUserDefaults: 8a4928443510aa99e4ccb3b53f1bf186593d690b
|
||||
RNUserDefaults: af71a1cdf1c12baf8210bc741c65f5faba9826d6
|
||||
RNVectorIcons: 0bb4def82230be1333ddaeee9fcba45f0b288ed4
|
||||
RSKImageCropper: a446db0e8444a036b34f3c43db01b2373baa4b2a
|
||||
SDWebImage: 96d7f03415ccb28d299d765f93557ff8a617abd8
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
</dict>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>fetch</string>
|
||||
<string>voip</string>
|
||||
</array>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
|
|
|
@ -95,7 +95,7 @@
|
|||
"rn-extensions-share": "^2.3.10",
|
||||
"rn-fetch-blob": "0.11.2",
|
||||
"rn-root-view": "^1.0.3",
|
||||
"rn-user-defaults": "^1.3.5",
|
||||
"rn-user-defaults": "^1.7.0",
|
||||
"semver": "6.3.0",
|
||||
"snyk": "1.210.0",
|
||||
"strip-ansi": "5.2.0",
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
diff --git a/node_modules/react-native-notifications/RNNotifications/RNNotificationEventHandler.m b/node_modules/react-native-notifications/RNNotifications/RNNotificationEventHandler.m
|
||||
index edc4fd4..aeb5eaa 100644
|
||||
--- a/node_modules/react-native-notifications/RNNotifications/RNNotificationEventHandler.m
|
||||
+++ b/node_modules/react-native-notifications/RNNotifications/RNNotificationEventHandler.m
|
||||
@@ -28,9 +28,92 @@ - (void)didReceiveForegroundNotification:(UNNotification *)notification withComp
|
||||
[RNEventEmitter sendEvent:RNNotificationReceivedForeground body:[RNNotificationParser parseNotification:notification]];
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Generate a random alphanumeric string to message id
|
||||
+*/
|
||||
+-(NSString *)random:(int)len {
|
||||
+ NSString *letters = @"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
+ NSMutableString *randomString = [NSMutableString stringWithCapacity:len];
|
||||
+
|
||||
+ for (int i=0; i<len; i++) {
|
||||
+ [randomString appendFormat: @"%C", [letters characterAtIndex: arc4random_uniform([letters length])]];
|
||||
+ }
|
||||
+
|
||||
+ return randomString;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Remove trailing slash on server url from notification
|
||||
+*/
|
||||
+-(NSString *)serverURL:(NSString *)host {
|
||||
+ if ([host length] > 0) {
|
||||
+ unichar last = [host characterAtIndex:[host length] - 1];
|
||||
+ if (last == '/') {
|
||||
+ host = [host substringToIndex:[host length] - 1];
|
||||
+ }
|
||||
+ }
|
||||
+ return host;
|
||||
+}
|
||||
+
|
||||
- (void)didReceiveNotificationResponse:(UNNotificationResponse *)response completionHandler:(void (^)(void))completionHandler {
|
||||
- [_store setActionCompletionHandler:completionHandler withCompletionKey:response.notification.request.identifier];
|
||||
- [RNEventEmitter sendEvent:RNNotificationOpened body:[RNNotificationParser parseNotificationResponse:response]];
|
||||
+ // if notification response is a REPLY_ACTION
|
||||
+ if ([response.actionIdentifier isEqualToString:@"REPLY_ACTION"]) {
|
||||
+ // convert notification data to dictionary payload
|
||||
+ NSDictionary *notification = [RCTConvert UNNotificationPayload:response.notification];
|
||||
+
|
||||
+ // parse ejson from notification
|
||||
+ NSData *ejsonData = [[notification valueForKey:@"ejson"] dataUsingEncoding:NSUTF8StringEncoding];
|
||||
+ NSError *error;
|
||||
+ NSDictionary *ejson = [NSJSONSerialization JSONObjectWithData:ejsonData options:kNilOptions error:&error];
|
||||
+
|
||||
+ // data from notification
|
||||
+ NSString *host = [ejson valueForKey:@"host"];
|
||||
+ NSString *rid = [ejson valueForKey:@"rid"];
|
||||
+
|
||||
+ // msg on textinput of notification
|
||||
+ NSString *msg = [(UNTextInputNotificationResponse *)response userText];
|
||||
+
|
||||
+ // get credentials
|
||||
+ NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.ios.chat.rocket"];
|
||||
+ NSString *TOKEN_KEY = @"reactnativemeteor_usertoken";
|
||||
+ NSString *userId = [userDefaults stringForKey:[NSString stringWithFormat:@"%@-%@", TOKEN_KEY, [self serverURL:host]]];
|
||||
+ NSString *token = [userDefaults stringForKey:[NSString stringWithFormat:@"%@-%@", TOKEN_KEY, userId]];
|
||||
+
|
||||
+ // background task - we need this because fetch doesn't work if app is closed/killed
|
||||
+ UIApplication *app = [UIApplication sharedApplication];
|
||||
+ __block UIBackgroundTaskIdentifier task = [app beginBackgroundTaskWithExpirationHandler:^{
|
||||
+ [app endBackgroundTask:task];
|
||||
+ task = UIBackgroundTaskInvalid;
|
||||
+ }];
|
||||
+ // we use global queue to make requests with app closed/killed
|
||||
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
+ // we make a synchronous request to post new message
|
||||
+ NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/api/v1/chat.sendMessage", [self serverURL:host]]]];
|
||||
+
|
||||
+ NSString *message = [NSString stringWithFormat:@"{ \"message\": { \"_id\": \"%@\", \"msg\": \"%@\", \"rid\": \"%@\" } }", [self random:17], msg, rid];
|
||||
+
|
||||
+ [request setHTTPMethod:@"POST"];
|
||||
+ [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
+ [request addValue:userId forHTTPHeaderField:@"x-user-id"];
|
||||
+ [request addValue:token forHTTPHeaderField:@"x-auth-token"];
|
||||
+ [request setHTTPBody:[message dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
+
|
||||
+ NSURLResponse *response = nil;
|
||||
+ NSError *error = nil;
|
||||
+ NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
|
||||
+
|
||||
+ // end background task
|
||||
+ [app endBackgroundTask:task];
|
||||
+ task = UIBackgroundTaskInvalid;
|
||||
+
|
||||
+ // complete notification response
|
||||
+ completionHandler();
|
||||
+ });
|
||||
+ } else {
|
||||
+ // We only set initial notification and emit event to JS when not is a reply action
|
||||
+ [_store setActionCompletionHandler:completionHandler withCompletionKey:response.notification.request.identifier];
|
||||
+ [RNEventEmitter sendEvent:RNNotificationOpened body:[RNNotificationParser parseNotificationResponse:response]];
|
||||
+ }
|
||||
}
|
||||
|
||||
@end
|
|
@ -10219,10 +10219,10 @@ rn-root-view@^1.0.3:
|
|||
resolved "https://registry.yarnpkg.com/rn-root-view/-/rn-root-view-1.0.3.tgz#a2cddc717278cb2175fb29b7c006e407b7f0d0e2"
|
||||
integrity sha512-BIKm8hY5q8+pxK9B5ugYjqutoI9xn2JfxIZKWoaFmAl1bOIM4oXjwFQrRM1e6lFgzz99MN6Mf2dK3Alsywnvvw==
|
||||
|
||||
rn-user-defaults@^1.3.5:
|
||||
version "1.3.5"
|
||||
resolved "https://registry.yarnpkg.com/rn-user-defaults/-/rn-user-defaults-1.3.5.tgz#8a93325e3fbbc47b1abd4147dc39b25eec8a45ab"
|
||||
integrity sha512-mqB57aQBb88QK49revJeJGMQXkPl2qtLeF4mINa7XTVCruAruNkm5wgTKLyS5aNLWdd3XIjkkAUSgH6o6FvIVQ==
|
||||
rn-user-defaults@^1.7.0:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/rn-user-defaults/-/rn-user-defaults-1.7.0.tgz#8d1b79657dec3977e8f8983814b8591821f77236"
|
||||
integrity sha512-Qo6sIH8wldmQ0oOMMvljec4WOa/a1Up1pdatoXZGaPG1gl8OKgKH5HPKyddcABYtxPeBUTPVzCxP/6S6wPCqGQ==
|
||||
|
||||
rsvp@^3.3.3:
|
||||
version "3.6.2"
|
||||
|
|
Loading…
Reference in New Issue