Merge branch 'master' into mark-as-unread

This commit is contained in:
Harrison Healey 2019-11-19 09:57:43 -05:00
commit b69c6af2b4
15 changed files with 264 additions and 163 deletions

View file

@ -91,15 +91,18 @@ commands:
steps:
- restore_cache:
name: Restore npm cache
key: v1-npm-{{ checksum "package.json" }}-{{ arch }}
key: v2-npm-{{ checksum "package.json" }}-{{ arch }}
- run:
name: Getting JavaScript dependencies
command: NODE_ENV=development npm install
command: NODE_ENV=development npm install --ignore-scripts
- save_cache:
name: Save npm cache
key: v1-npm-{{ checksum "package.json" }}-{{ arch }}
key: v2-npm-{{ checksum "package.json" }}-{{ arch }}
paths:
- node_modules
- run:
name: "Run post install scripts"
command: make post-install
pods-dependencies:
description: "Get cocoapods dependencies"

View file

@ -74,6 +74,7 @@ clean: ## Cleans dependencies, previous builds and temp files
@echo Cleanup finished
post-install:
@./node_modules/.bin/patch-package
@./node_modules/.bin/jetify
@rm -f node_modules/intl/.babelrc
@ -84,8 +85,6 @@ post-install:
@sed -i'' -e 's|"./lib/locales": false|"./lib/locales": "./lib/locales"|g' node_modules/intl-relativeformat/package.json
@sed -i'' -e 's|"./locale-data/complete.js": false|"./locale-data/complete.js": "./locale-data/complete.js"|g' node_modules/intl/package.json
@./node_modules/.bin/patch-package
start: | pre-run ## Starts the React Native packager server
$(call start_packager)

View file

@ -20,6 +20,8 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.Build;
import android.provider.Settings.System;
import androidx.annotation.Nullable;
import android.util.Log;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
@ -36,6 +38,9 @@ import com.wix.reactnativenotifications.core.JsIOHelper;
import static com.wix.reactnativenotifications.Defs.NOTIFICATION_RECEIVED_EVENT_NAME;
import com.mattermost.react_native_interface.ResolvePromise;
import com.facebook.react.bridge.WritableMap;
public class CustomPushNotification extends PushNotification {
public static final int MESSAGE_NOTIFICATION_ID = 435345;
public static final String GROUP_KEY_MESSAGES = "mm_group_key_messages";
@ -45,6 +50,7 @@ public class CustomPushNotification extends PushNotification {
private static final String PUSH_TYPE_MESSAGE = "message";
private static final String PUSH_TYPE_CLEAR = "clear";
private static final String PUSH_TYPE_ID_LOADED = "id_loaded";
private static final String PUSH_TYPE_UPDATE_BADGE = "update_badge";
private NotificationChannel mHighImportanceChannel;
@ -96,16 +102,34 @@ public class CustomPushNotification extends PushNotification {
@Override
public void onReceived() throws InvalidNotificationException {
Bundle data = mNotificationProps.asBundle();
final String channelId = data.getString("channel_id");
final String type = data.getString("type");
final String ackId = data.getString("ack_id");
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");
int notificationId = MESSAGE_NOTIFICATION_ID;
if (ackId != null) {
notificationReceiptDelivery(ackId, type);
notificationReceiptDelivery(ackId, postId, type, new ResolvePromise() {
@Override
public void resolve(@Nullable Object value) {
if (PUSH_TYPE_ID_LOADED.equals(type)) {
Bundle response = (Bundle) value;
mNotificationProps = createProps(response);
}
}
@Override
public void reject(String code, String message) {
Log.e("ReactNative", code + ": " + message);
}
});
}
// notificationReceiptDelivery can override mNotificationProps
// so we fetch the bundle again
final Bundle data = mNotificationProps.asBundle();
if (channelId != null) {
notificationId = channelId.hashCode();
@ -501,8 +525,8 @@ public class CustomPushNotification extends PushNotification {
return message.replaceFirst(senderName, "").replaceFirst(": ", "").trim();
}
private void notificationReceiptDelivery(String ackId, String type) {
ReceiptDelivery.send(context, ackId, type);
private void notificationReceiptDelivery(String ackId, String postId, String type, ResolvePromise promise) {
ReceiptDelivery.send(context, ackId, postId, type, promise);
}
private void createNotificationChannels() {

View file

@ -2,6 +2,7 @@ package com.mattermost.rnbeta;
import android.content.Context;
import androidx.annotation.Nullable;
import android.os.Bundle;
import android.util.Log;
import java.lang.System;
@ -18,13 +19,14 @@ import org.json.JSONException;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.Arguments;
import com.mattermost.react_native_interface.ResolvePromise;
public class ReceiptDelivery {
static final String CURRENT_SERVER_URL = "@currentServerUrl";
public static void send (Context context, final String ackId, final String type) {
public static void send(Context context, final String ackId, final String postId, final String type, ResolvePromise promise) {
final ReactApplicationContext reactApplicationContext = new ReactApplicationContext(context);
MattermostCredentialsHelper.getCredentialsForCurrentServer(reactApplicationContext, new ResolvePromise() {
@ -47,17 +49,22 @@ public class ReceiptDelivery {
}
Log.i("ReactNative", String.format("Send receipt delivery ACK=%s TYPE=%s to URL=%s with TOKEN=%s", ackId, type, serverUrl, token));
execute(serverUrl, token, ackId, type);
execute(serverUrl, postId, token, ackId, type, promise);
}
}
});
}
protected static void execute(String serverUrl, String token, String ackId, String type) {
if (token == null || serverUrl == null) {
protected static void execute(String serverUrl, String postId, String token, String ackId, String type, ResolvePromise promise) {
if (token == null) {
promise.reject("Receipt delivery failure", "Invalid token");
return;
}
if (serverUrl == null) {
promise.reject("Receipt delivery failure", "Invalid server URL");
}
JSONObject json;
long receivedAt = System.currentTimeMillis();
@ -67,8 +74,10 @@ public class ReceiptDelivery {
json.put("received_at", receivedAt);
json.put("platform", "android");
json.put("type", type);
json.put("post_id", postId);
} catch (JSONException e) {
Log.e("ReactNative", "Receipt delivery failed to build json payload");
promise.reject("Receipt delivery failure", e.toString());
return;
}
@ -86,9 +95,24 @@ public class ReceiptDelivery {
.build();
try {
client.newCall(request).execute();
Response response = client.newCall(request).execute();
String responseBody = response.body().toString();
if (response.code() != 200) {
throw new Exception(responseBody);
}
JSONObject jsonResponse = new JSONObject(responseBody);
Bundle bundle = new Bundle();
String keys[] = new String[] {"post_id", "category", "message", "team_id", "channel_id", "channel_name", "type", "sender_id", "sender_name", "version"};
for (int i = 0; i < keys.length; i++) {
String key = keys[i];
if (jsonResponse.has(key)) {
bundle.putString(key, jsonResponse.getString(key));
}
}
promise.resolve(bundle);
} catch (Exception e) {
Log.e("ReactNative", "Receipt delivery failed to send");
promise.reject("Receipt delivery failure", e.toString());
}
}
}

View file

@ -14,6 +14,7 @@ import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
import {getChannel, isChannelReadOnlyById} from 'mattermost-redux/selectors/entities/channels';
import {addReaction} from 'app/actions/views/emoji';
import {MAX_ALLOWED_REACTIONS} from 'app/constants/emoji';
import Reactions from './reactions';
@ -27,17 +28,23 @@ function makeMapStateToProps() {
const channelIsArchived = channel.delete_at !== 0;
const channelIsReadOnly = isChannelReadOnlyById(state, channelId);
const currentUserId = getCurrentUserId(state);
const reactions = getReactionsForPostSelector(state, ownProps.postId);
let canAddReaction = true;
let canRemoveReaction = true;
let canAddMoreReactions = true;
if (channelIsArchived || channelIsReadOnly) {
canAddReaction = false;
canRemoveReaction = false;
canAddMoreReactions = false;
} else if (hasNewPermissions(state)) {
canAddReaction = haveIChannelPermission(state, {
team: teamId,
channel: channelId,
permission: Permissions.ADD_REACTION,
});
canAddMoreReactions = Object.values(reactions).length < MAX_ALLOWED_REACTIONS;
canRemoveReaction = haveIChannelPermission(state, {
team: teamId,
channel: channelId,
@ -45,14 +52,12 @@ function makeMapStateToProps() {
});
}
const currentUserId = getCurrentUserId(state);
const reactions = getReactionsForPostSelector(state, ownProps.postId);
return {
currentUserId,
reactions,
theme: getTheme(state),
canAddReaction,
canAddMoreReactions,
canRemoveReaction,
};
};

View file

@ -5,7 +5,7 @@ import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {
Image,
ScrollView,
View,
} from 'react-native';
import {intlShape} from 'react-intl';
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
@ -26,13 +26,14 @@ export default class Reactions extends PureComponent {
getReactionsForPost: PropTypes.func.isRequired,
removeReaction: PropTypes.func.isRequired,
}).isRequired,
canAddReaction: PropTypes.bool,
canAddMoreReactions: PropTypes.bool,
canRemoveReaction: PropTypes.bool.isRequired,
currentUserId: PropTypes.string.isRequired,
position: PropTypes.oneOf(['right', 'left']),
postId: PropTypes.string.isRequired,
reactions: PropTypes.object,
theme: PropTypes.object.isRequired,
canAddReaction: PropTypes.bool,
canRemoveReaction: PropTypes.bool.isRequired,
};
static defaultProps = {
@ -132,7 +133,7 @@ export default class Reactions extends PureComponent {
};
render() {
const {position, reactions, canAddReaction} = this.props;
const {position, reactions, canAddMoreReactions} = this.props;
const styles = getStyleSheet(this.props.theme);
if (!reactions) {
@ -140,7 +141,7 @@ export default class Reactions extends PureComponent {
}
let addMoreReactions = null;
if (canAddReaction) {
if (canAddMoreReactions) {
addMoreReactions = (
<TouchableWithFeedback
key='addReaction'
@ -173,14 +174,9 @@ export default class Reactions extends PureComponent {
}
return (
<ScrollView
alwaysBounceHorizontal={false}
horizontal={true}
overScrollMode='never'
keyboardShouldPersistTaps={'always'}
>
<View style={styles.reactionsContainer}>
{reactionElements}
</ScrollView>
</View>
);
}
}
@ -207,5 +203,11 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
paddingHorizontal: 6,
width: 40,
},
reactionsContainer: {
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap',
alignContent: 'flex-start',
},
};
});

View file

@ -2,3 +2,4 @@
// See LICENSE.txt for license information.
export const ALL_EMOJIS = 'all_emojis';
export const MAX_ALLOWED_REACTIONS = 40;

View file

@ -38,7 +38,7 @@ class PushNotification {
this.deviceNotification = {
data,
foreground,
message: data.message,
message: data.body || data.message,
userInfo: data.userInfo,
userInteraction,
};
@ -155,9 +155,10 @@ class PushNotification {
ephemeralStore.appStartedFromPushNotification = true;
}
const data = notification.getData();
const info = {
...notification.getData(),
message: notification.getMessage(),
...data,
message: data.body || notification.getMessage(),
};
if (!userInteraction) {
@ -166,9 +167,10 @@ class PushNotification {
};
onNotificationReceivedForeground = (notification) => {
const data = notification.getData();
const info = {
...notification.getData(),
message: notification.getMessage(),
...data,
message: data.body || notification.getMessage(),
};
this.handleNotification(info, true, false);
};
@ -177,9 +179,10 @@ class PushNotification {
if (action.identifier === REPLY_ACTION) {
this.handleReply(notification, action.text, completion);
} else {
const data = notification.getData();
const info = {
...notification.getData(),
message: notification.getMessage(),
...data,
message: data.body || notification.getMessage(),
};
this.handleNotification(info, false, true);
completion();

View file

@ -14,6 +14,7 @@ import {
setUnreadPost,
} from 'mattermost-redux/actions/posts';
import {General, Permissions} from 'mattermost-redux/constants';
import {makeGetReactionsForPost} from 'mattermost-redux/selectors/entities/posts';
import {getChannel, getCurrentChannelId} from 'mattermost-redux/selectors/entities/channels';
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
import {getConfig, getLicense, hasNewPermissions} from 'mattermost-redux/selectors/entities/general';
@ -22,95 +23,104 @@ import {haveIChannelPermission} from 'mattermost-redux/selectors/entities/roles'
import {getCurrentTeamId, getCurrentTeamUrl} from 'mattermost-redux/selectors/entities/teams';
import {canEditPost} from 'mattermost-redux/utils/post_utils';
import {MAX_ALLOWED_REACTIONS} from 'app/constants/emoji';
import {THREAD} from 'app/constants/screen';
import {addReaction} from 'app/actions/views/emoji';
import {getDimensions, isLandscape} from 'app/selectors/device';
import PostOptions from './post_options';
export function mapStateToProps(state, ownProps) {
const post = ownProps.post;
const channel = getChannel(state, post.channel_id) || {};
const config = getConfig(state);
const license = getLicense(state);
const currentUserId = getCurrentUserId(state);
const currentTeamId = getCurrentTeamId(state);
const currentChannelId = getCurrentChannelId(state);
export function makeMapStateToProps() {
const getReactionsForPostSelector = makeGetReactionsForPost();
const channelIsArchived = channel.delete_at !== 0;
return (state, ownProps) => {
const post = ownProps.post;
const channel = getChannel(state, post.channel_id) || {};
const config = getConfig(state);
const license = getLicense(state);
const currentUserId = getCurrentUserId(state);
const currentTeamId = getCurrentTeamId(state);
const currentChannelId = getCurrentChannelId(state);
const reactions = getReactionsForPostSelector(state, post.id);
const channelIsArchived = channel.delete_at !== 0;
let canAddReaction = true;
let canReply = true;
let canCopyPermalink = true;
let canCopyText = false;
let canEdit = false;
let canEditUntil = -1;
let {canDelete} = ownProps;
let canFlag = true;
let canPin = true;
let canAddReaction = true;
let canReply = true;
let canCopyPermalink = true;
let canCopyText = false;
let canEdit = false;
let canEditUntil = -1;
let {canDelete} = ownProps;
let canFlag = true;
let canPin = true;
if (hasNewPermissions(state)) {
canAddReaction = haveIChannelPermission(state, {
team: currentTeamId,
channel: post.channel_id,
permission: Permissions.ADD_REACTION,
});
}
if (ownProps.location === THREAD) {
canReply = false;
}
if (channelIsArchived || ownProps.channelIsReadOnly) {
canAddReaction = false;
canReply = false;
canDelete = false;
canPin = false;
} else {
canEdit = canEditPost(state, config, license, currentTeamId, currentChannelId, currentUserId, post);
if (canEdit && license.IsLicensed === 'true' &&
(config.AllowEditPost === General.ALLOW_EDIT_POST_TIME_LIMIT || (config.PostEditTimeLimit !== -1 && config.PostEditTimeLimit !== '-1'))
) {
canEditUntil = post.create_at + (config.PostEditTimeLimit * 1000);
if (hasNewPermissions(state)) {
canAddReaction = haveIChannelPermission(state, {
team: currentTeamId,
channel: post.channel_id,
permission: Permissions.ADD_REACTION,
});
}
}
if (ownProps.isSystemMessage) {
canAddReaction = false;
canReply = false;
canCopyPermalink = false;
canEdit = false;
canPin = false;
canFlag = false;
}
if (ownProps.hasBeenDeleted) {
canDelete = false;
}
if (ownProps.location === THREAD) {
canReply = false;
}
if (!ownProps.showAddReaction) {
canAddReaction = false;
}
if (channelIsArchived || ownProps.channelIsReadOnly) {
canAddReaction = false;
canReply = false;
canDelete = false;
canPin = false;
} else {
canEdit = canEditPost(state, config, license, currentTeamId, currentChannelId, currentUserId, post);
if (canEdit && license.IsLicensed === 'true' &&
(config.AllowEditPost === General.ALLOW_EDIT_POST_TIME_LIMIT || (config.PostEditTimeLimit !== -1 && config.PostEditTimeLimit !== '-1'))
) {
canEditUntil = post.create_at + (config.PostEditTimeLimit * 1000);
}
}
if (!ownProps.isSystemMessage && ownProps.managedConfig?.copyAndPasteProtection !== 'true' && post.message) {
canCopyText = true;
}
if (ownProps.isSystemMessage) {
canAddReaction = false;
canReply = false;
canCopyPermalink = false;
canEdit = false;
canPin = false;
canFlag = false;
}
if (ownProps.hasBeenDeleted) {
canDelete = false;
}
return {
...getDimensions(state),
canAddReaction,
canReply,
canCopyPermalink,
canCopyText,
canEdit,
canEditUntil,
canDelete,
canFlag,
canPin,
currentTeamUrl: getCurrentTeamUrl(state),
currentUserId: getCurrentUserId(state),
isMyPost: currentUserId === post.user_id,
theme: getTheme(state),
isLandscape: isLandscape(state),
if (!ownProps.showAddReaction) {
canAddReaction = false;
}
if (!ownProps.isSystemMessage && ownProps.managedConfig?.copyAndPasteProtection !== 'true' && post.message) {
canCopyText = true;
}
if (reactions && Object.values(reactions).length >= MAX_ALLOWED_REACTIONS) {
canAddReaction = false;
}
return {
...getDimensions(state),
canAddReaction,
canReply,
canCopyPermalink,
canCopyText,
canEdit,
canEditUntil,
canDelete,
canFlag,
canPin,
currentTeamUrl: getCurrentTeamUrl(state),
currentUserId,
isMyPost: currentUserId === post.user_id,
theme: getTheme(state),
isLandscape: isLandscape(state),
};
};
}
@ -129,4 +139,4 @@ function mapDispatchToProps(dispatch) {
};
}
export default connect(mapStateToProps, mapDispatchToProps)(PostOptions);
export default connect(makeMapStateToProps, mapDispatchToProps)(PostOptions);

View file

@ -1,6 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {mapStateToProps} from './index';
import {makeMapStateToProps} from './index';
import * as channelSelectors from 'mattermost-redux/selectors/entities/channels';
import * as generalSelectors from 'mattermost-redux/selectors/entities/general';
@ -24,10 +24,24 @@ deviceSelectors.getDimensions = jest.fn();
deviceSelectors.isLandscape = jest.fn();
preferencesSelectors.getTheme = jest.fn();
describe('mapStateToProps', () => {
const baseState = {};
describe('makeMapStateToProps', () => {
const baseState = {
entities: {
posts: {
posts: {
post_id: {},
},
reactions: {
post_id: {},
},
},
},
};
const baseOwnProps = {
post: {},
post: {
id: 'post_id',
},
};
test('canFlag is false for system messages', () => {
@ -36,6 +50,7 @@ describe('mapStateToProps', () => {
isSystemMessage: true,
};
const mapStateToProps = makeMapStateToProps();
const props = mapStateToProps(baseState, ownProps);
expect(props.canFlag).toBe(false);
});
@ -46,7 +61,8 @@ describe('mapStateToProps', () => {
isSystemMessage: false,
};
const mapStateToProps = makeMapStateToProps();
const props = mapStateToProps(baseState, ownProps);
expect(props.canFlag).toBe(true);
});
});
});

View file

@ -9,15 +9,37 @@ class NotificationService: UNNotificationServiceExtension {
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
if let bestAttemptContent = bestAttemptContent {
let ackId = bestAttemptContent.userInfo["ack_id"]
let type = bestAttemptContent.userInfo["type"]
let postId = bestAttemptContent.userInfo["post_id"]
UploadSession.shared.notificationReceipt(
notificationId: bestAttemptContent.userInfo["ack_id"],
notificationId: ackId,
receivedAt: Date().millisencondsSince1970,
type: bestAttemptContent.userInfo["type"]
)
contentHandler(bestAttemptContent)
type: type,
postId: postId
) { data, error in
if (type as? String == "id_loaded") {
guard let data = data, error == nil else {
return
}
let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as! Dictionary<String,Any>
bestAttemptContent.title = json!["channel_name"] as! String
bestAttemptContent.body = json!["message"] as! String
bestAttemptContent.userInfo["channel_name"] = json!["channel_name"] as! String
bestAttemptContent.userInfo["team_id"] = json!["team_id"] as? String
bestAttemptContent.userInfo["sender_id"] = json!["sender_id"] as! String
bestAttemptContent.userInfo["sender_name"] = json!["sender_name"] as! String
bestAttemptContent.userInfo["root_id"] = json!["root_id"] as? String
bestAttemptContent.userInfo["override_username"] = json!["override_username"] as? String
bestAttemptContent.userInfo["override_icon_url"] = json!["override_icon_url"] as? String
bestAttemptContent.userInfo["from_webhook"] = json!["from_webhook"] as? String
}
contentHandler(bestAttemptContent)
}
}
}

View file

@ -25,15 +25,6 @@ PODS:
- React
- KeyboardTrackingView (5.5.0):
- React
- libwebp (1.0.3):
- libwebp/demux (= 1.0.3)
- libwebp/mux (= 1.0.3)
- libwebp/webp (= 1.0.3)
- libwebp/demux (1.0.3):
- libwebp/webp
- libwebp/mux (1.0.3):
- libwebp/demux
- libwebp/webp (1.0.3)
- RCTRequired (0.61.2)
- RCTTypeSafety (0.61.2):
- FBLazyVector (= 0.61.2)
@ -268,10 +259,6 @@ PODS:
- React
- RNDeviceInfo (2.1.2):
- React
- RNFastImage (7.0.2):
- React
- SDWebImage (~> 5.0)
- SDWebImageWebPCoder (~> 0.2.3)
- RNGestureHandler (1.4.1):
- React
- RNKeychain (4.0.1):
@ -287,12 +274,6 @@ PODS:
- React
- RNVectorIcons (6.6.0):
- React
- SDWebImage (5.2.2):
- SDWebImage/Core (= 5.2.2)
- SDWebImage/Core (5.2.2)
- SDWebImageWebPCoder (0.2.5):
- libwebp (~> 1.0)
- SDWebImage/Core (~> 5.0)
- Sentry (4.4.0):
- Sentry/Core (= 4.4.0)
- Sentry/Core (4.4.0)
@ -348,7 +329,6 @@ DEPENDENCIES:
- rn-fetch-blob (from `../node_modules/rn-fetch-blob`)
- "RNCAsyncStorage (from `../node_modules/@react-native-community/async-storage`)"
- RNDeviceInfo (from `../node_modules/react-native-device-info`)
- RNFastImage (from `../node_modules/react-native-fast-image`)
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- RNKeychain (from `../node_modules/react-native-keychain`)
- RNReactNativeDocViewer (from `../node_modules/react-native-doc-viewer`)
@ -363,9 +343,6 @@ DEPENDENCIES:
SPEC REPOS:
https://github.com/cocoapods/specs.git:
- boost-for-react-native
- libwebp
- SDWebImage
- SDWebImageWebPCoder
- Sentry
- Swime
- XCDYouTubeKit
@ -458,8 +435,6 @@ EXTERNAL SOURCES:
:path: "../node_modules/@react-native-community/async-storage"
RNDeviceInfo:
:path: "../node_modules/react-native-device-info"
RNFastImage:
:path: "../node_modules/react-native-fast-image"
RNGestureHandler:
:path: "../node_modules/react-native-gesture-handler"
RNKeychain:
@ -487,7 +462,6 @@ SPEC CHECKSUMS:
glog: 1f3da668190260b06b429bb211bfbee5cd790c28
jail-monkey: 0830c18bb6f085938a4c8529d554f9b29230a5a4
KeyboardTrackingView: d4d7236123b401ed9b1e02869e7943117740c522
libwebp: 057912d6d0abfb6357d8bb05c0ea470301f5d61e
RCTRequired: c639d59ed389cfb1f1203f65c2ea946d8ec586e2
RCTTypeSafety: dc23fb655d6c77667c78e327bf661bc11e3b8aec
RCTYouTube: a36b9960e040063877fb8dc61fff19d3bd1a97ff
@ -523,7 +497,6 @@ SPEC CHECKSUMS:
rn-fetch-blob: 3258c6483235bb7daf16cf921306ffb18406071f
RNCAsyncStorage: 5ae4d57458804e99f73d427214442a6b10a53856
RNDeviceInfo: fd8296de6fca8b743cdc499b896f48e8a9f1faf5
RNFastImage: 9b0c22643872bb7494c8d87bbbb66cc4c0d9e7a2
RNGestureHandler: 4cb47a93019c1a201df2644413a0a1569a51c8aa
RNKeychain: 45dbd50d1ac4bd42c3740f76ffb135abf05746d0
RNReactNativeDocViewer: 571c6ac38483531b8fb521d02a6ba54652ed10a7
@ -531,8 +504,6 @@ SPEC CHECKSUMS:
RNSentry: 2803ba8c8129dcf26b79e9b4d8c80168be6e4390
RNSVG: be27aa7c58819f97399388ae53d7fa0572f32c7f
RNVectorIcons: 0bb4def82230be1333ddaeee9fcba45f0b288ed4
SDWebImage: 5fcdb02cc35e05fc35791ec514b191d27189f872
SDWebImageWebPCoder: 947093edd1349d820c40afbd9f42acb6cdecd987
Sentry: 26650184fe71eb7476dfd2737acb5ea6cc64b4b1
Swime: d7b2c277503b6cea317774aedc2dce05613f8b0b
XCDYouTubeKit: 4ca4e3322fa556ec1c32932d378365c15ce1386e

View file

@ -126,8 +126,12 @@ import os.log
}
})
}
public func notificationReceipt(notificationId: Any?, receivedAt: Int, type: Any?) {
notificationReceipt(notificationId:notificationId, receivedAt:receivedAt, type:type, postId:nil, completion:{_, _ in})
}
public func notificationReceipt(notificationId: Any?, receivedAt: Int, type: Any?, postId: Any? = nil, completion: @escaping (Data?, Error?) -> Void) {
if (notificationId != nil) {
let store = StoreManager.shared() as StoreManager
let entities = store.getEntities(true)
@ -142,18 +146,23 @@ import os.log
"id": notificationId as Any,
"received_at": receivedAt,
"platform": "ios",
"type": type as Any
"type": type as Any,
"post_id": postId as Any
]
if !JSONSerialization.isValidJSONObject(jsonObject) {return}
guard let url = URL(string: urlString) else {return}
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("Bearer \(sessionToken!)", forHTTPHeaderField: "Authorization")
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.httpBody = try? JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted)
URLSession(configuration: .ephemeral).dataTask(with: request).resume()
let task = URLSession(configuration: .ephemeral).dataTask(with: request) { data, _, error in
completion(data, error)
}
task.resume()
}
}
}

2
package-lock.json generated
View file

@ -4673,7 +4673,7 @@
"dependencies": {
"json5": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
"resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
"integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
"dev": true
}

View file

@ -165,7 +165,7 @@ index 0d70024..47b962e 100644
PushNotificationProps asProps();
}
diff --git a/node_modules/react-native-notifications/android/app/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java b/node_modules/react-native-notifications/android/app/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java
index 5e4e3d2..871e157 100644
index 5e4e3d2..ec37f87 100644
--- a/node_modules/react-native-notifications/android/app/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java
+++ b/node_modules/react-native-notifications/android/app/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java
@@ -1,5 +1,6 @@
@ -175,16 +175,28 @@ index 5e4e3d2..871e157 100644
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
@@ -20,7 +21,9 @@ import com.wix.reactnativenotifications.core.InitialNotificationHolder;
@@ -20,18 +21,20 @@ import com.wix.reactnativenotifications.core.InitialNotificationHolder;
import com.wix.reactnativenotifications.core.JsIOHelper;
import com.wix.reactnativenotifications.core.NotificationIntentAdapter;
import com.wix.reactnativenotifications.core.ProxyService;
+import com.wix.reactnativenotifications.core.helpers.ScheduleNotificationHelper;
+import static com.wix.reactnativenotifications.Defs.LOGTAG;
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_FOREGROUND_EVENT_NAME;
public class PushNotification implements IPushNotification {
+ protected PushNotificationProps mNotificationProps;
final protected Context mContext;
final protected AppLifecycleFacade mAppLifecycleFacade;
final protected AppLaunchHelper mAppLaunchHelper;
final protected JsIOHelper mJsIOHelper;
- final protected PushNotificationProps mNotificationProps;
final protected AppVisibilityListener mAppVisibilityListener = new AppVisibilityListener() {
@Override
public void onAppVisible() {
@@ -80,6 +83,41 @@ public class PushNotification implements IPushNotification {
return postNotification(notificationId);
}