diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 6cc5eb9de..8e1e59741 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -45,7 +45,12 @@ - + + diff --git a/android/app/src/main/java/com/mattermost/rnbeta/CustomPushNotification.java b/android/app/src/main/java/com/mattermost/rnbeta/CustomPushNotification.java index 1812ef689..e87e25acd 100644 --- a/android/app/src/main/java/com/mattermost/rnbeta/CustomPushNotification.java +++ b/android/app/src/main/java/com/mattermost/rnbeta/CustomPushNotification.java @@ -11,10 +11,13 @@ import android.os.Bundle; import android.os.Build; import android.app.Notification; import android.app.NotificationManager; +import android.app.RemoteInput; import java.util.LinkedHashMap; import java.util.ArrayList; +import java.lang.reflect.Field; import com.wix.reactnativenotifications.core.notification.PushNotification; +import com.wix.reactnativenotifications.core.NotificationIntentAdapter; import com.wix.reactnativenotifications.core.AppLaunchHelper; import com.wix.reactnativenotifications.core.AppLifecycleFacade; import com.wix.reactnativenotifications.core.JsIOHelper; @@ -27,18 +30,25 @@ 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_ID = "notificationId"; + public static final String KEY_TEXT_REPLY = "CAN_REPLY"; + public static final String NOTIFICATION_REPLIED_EVENT_NAME = "notificationReplied"; + private static LinkedHashMap channelIdToNotificationCount = new LinkedHashMap(); private static LinkedHashMap> channelIdToNotification = new LinkedHashMap>(); + private static AppLifecycleFacade lifecycleFacade; + private static Context context; public CustomPushNotification(Context context, Bundle bundle, AppLifecycleFacade appLifecycleFacade, AppLaunchHelper appLaunchHelper, JsIOHelper jsIoHelper) { super(context, bundle, appLifecycleFacade, appLaunchHelper, jsIoHelper); + this.context = context; } - public static void clearNotification(int notificationId) { + public static void clearNotification(int notificationId, String channelId) { if (notificationId != -1) { - String channelId = String.valueOf(notificationId); channelIdToNotificationCount.remove(channelId); channelIdToNotification.remove(channelId); + final NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager.cancel(notificationId); } } @@ -108,8 +118,9 @@ public class CustomPushNotification extends PushNotification { title = mContext.getPackageManager().getApplicationLabel(appInfo).toString(); } - int notificationId = bundle.getString("channel_id").hashCode(); String channelId = bundle.getString("channel_id"); + String postId = bundle.getString("post_id"); + int notificationId = channelId.hashCode(); String message = bundle.getString("message"); String subText = bundle.getString("subText"); String numberString = bundle.getString("badge"); @@ -143,11 +154,7 @@ public class CustomPushNotification extends PushNotification { ApplicationBadgeHelper.instance.setApplicationIconBadgeNumber(mContext.getApplicationContext(), Integer.parseInt(numberString)); } - int numMessages = 0; - Object objCount = channelIdToNotificationCount.get(channelId); - if (objCount != null) { - numMessages = (Integer)objCount; - } + int numMessages = getMessageCountInChannel(channelId); notification .setGroupSummary(true) @@ -173,19 +180,40 @@ public class CustomPushNotification extends PushNotification { style.setBigContentTitle(title); notification.setStyle(style) .setContentTitle(summaryTitle); -// .setNumber(numMessages); } // Let's add a delete intent when the notification is dismissed - Intent delIntent = new Intent(mContext, NotificationDismissReceiver.class); + Intent delIntent = new Intent(mContext, NotificationDismissService.class); delIntent.putExtra(NOTIFICATION_ID, notificationId); - PendingIntent deleteIntent = PendingIntent.getBroadcast(mContext, 0, delIntent, 0); + PendingIntent deleteIntent = NotificationIntentAdapter.createPendingNotificationIntent(mContext, delIntent, mNotificationProps); notification.setDeleteIntent(deleteIntent); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { notification.setGroup(GROUP_KEY_MESSAGES); } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && postId != null) { + Intent replyIntent = new Intent(mContext, NotificationReplyService.class); + replyIntent.setAction(KEY_TEXT_REPLY); + replyIntent.putExtra(NOTIFICATION_ID, notificationId); + replyIntent.putExtra("pushNotification", bundle); + PendingIntent replyPendingIntent = PendingIntent.getService(mContext, 103, replyIntent, PendingIntent.FLAG_UPDATE_CURRENT); + + RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY) + .setLabel("Reply") + .build(); + + Notification.Action replyAction = new Notification.Action.Builder( + R.drawable.ic_notif_action_reply, "Reply", replyPendingIntent) + .addRemoteInput(remoteInput) + .setAllowGeneratedReplies(true) + .build(); + + notification + .setShowWhen(true) + .addAction(replyAction); + } + Bitmap largeIconBitmap = BitmapFactory.decodeResource(res, largeIconResId); if (largeIconResId != 0 && (largeIcon != null || Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)) { notification.setLargeIcon(largeIconBitmap); @@ -202,6 +230,15 @@ public class CustomPushNotification extends PushNotification { mJsIOHelper.sendEventToJS(NOTIFICATION_RECEIVED_EVENT_NAME, mNotificationProps.asBundle(), mAppLifecycleFacade.getRunningReactContext()); } + public static Integer getMessageCountInChannel(String channelId) { + Object objCount = channelIdToNotificationCount.get(channelId); + if (objCount != null) { + return (Integer)objCount; + } + + return 0; + } + private void cancelNotification(Bundle data, int notificationId) { final String channelId = data.getString("channel_id"); diff --git a/android/app/src/main/java/com/mattermost/rnbeta/NotificationDismissReceiver.java b/android/app/src/main/java/com/mattermost/rnbeta/NotificationDismissReceiver.java deleted file mode 100644 index be0706b39..000000000 --- a/android/app/src/main/java/com/mattermost/rnbeta/NotificationDismissReceiver.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.mattermost.rnbeta; - -import android.content.Context; -import android.content.Intent; -import android.content.BroadcastReceiver; - - -public class NotificationDismissReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - int notificationId = intent.getIntExtra(CustomPushNotification.NOTIFICATION_ID, -1); - CustomPushNotification.clearNotification(notificationId); - } -} diff --git a/android/app/src/main/java/com/mattermost/rnbeta/NotificationDismissService.java b/android/app/src/main/java/com/mattermost/rnbeta/NotificationDismissService.java new file mode 100644 index 000000000..48406f275 --- /dev/null +++ b/android/app/src/main/java/com/mattermost/rnbeta/NotificationDismissService.java @@ -0,0 +1,23 @@ +package com.mattermost.rnbeta; + +import android.content.Context; +import android.content.Intent; +import android.app.IntentService; +import android.os.Bundle; + +import com.wix.reactnativenotifications.core.NotificationIntentAdapter; + +public class NotificationDismissService extends IntentService { + + public NotificationDismissService() { + super("notificationDismissService"); + } + + @Override + protected void onHandleIntent(Intent intent) { + Bundle bundle = NotificationIntentAdapter.extractPendingNotificationDataFromIntent(intent); + int notificationId = intent.getIntExtra(CustomPushNotification.NOTIFICATION_ID, -1); + String channelId = bundle.getString("channel_id"); + CustomPushNotification.clearNotification(notificationId, channelId); + } +} diff --git a/android/app/src/main/java/com/mattermost/rnbeta/NotificationReplyService.java b/android/app/src/main/java/com/mattermost/rnbeta/NotificationReplyService.java new file mode 100644 index 000000000..cadc2abcb --- /dev/null +++ b/android/app/src/main/java/com/mattermost/rnbeta/NotificationReplyService.java @@ -0,0 +1,49 @@ +package com.mattermost.rnbeta; + +import android.content.Context; +import android.content.Intent; +import android.app.NotificationManager; +import android.app.RemoteInput; +import android.os.Bundle; +import android.support.annotation.Nullable; + +import com.facebook.react.HeadlessJsTaskService; +import com.facebook.react.bridge.Arguments; +import com.facebook.react.jstasks.HeadlessJsTaskConfig; + + +import com.wix.reactnativenotifications.core.NotificationIntentAdapter; + +public class NotificationReplyService extends HeadlessJsTaskService { + + @Override + protected @Nullable HeadlessJsTaskConfig getTaskConfig(Intent intent) { + if (CustomPushNotification.KEY_TEXT_REPLY.equals(intent.getAction())) { + CharSequence message = getReplyMessage(intent); + + Bundle bundle = NotificationIntentAdapter.extractPendingNotificationDataFromIntent(intent); + String channelId = bundle.getString("channel_id"); + bundle.putCharSequence("text", message); + bundle.putInt("msg_count", CustomPushNotification.getMessageCountInChannel(channelId)); + + int notificationId = intent.getIntExtra(CustomPushNotification.NOTIFICATION_ID, -1); + CustomPushNotification.clearNotification(notificationId, channelId); + + return new HeadlessJsTaskConfig( + "notificationReplied", + Arguments.fromBundle(bundle), + 5000); + + } + + return null; + } + + private CharSequence getReplyMessage(Intent intent) { + Bundle remoteInput = RemoteInput.getResultsFromIntent(intent); + if (remoteInput != null) { + return remoteInput.getCharSequence(CustomPushNotification.KEY_TEXT_REPLY); + } + return null; + } +} diff --git a/android/app/src/main/res/drawable-hdpi/ic_notif_action_reply.png b/android/app/src/main/res/drawable-hdpi/ic_notif_action_reply.png new file mode 100644 index 000000000..d7d3365f5 Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/ic_notif_action_reply.png differ diff --git a/android/app/src/main/res/drawable-mdpi/ic_notif_action_reply.png b/android/app/src/main/res/drawable-mdpi/ic_notif_action_reply.png new file mode 100644 index 000000000..a144ef606 Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/ic_notif_action_reply.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/ic_notif_action_reply.png b/android/app/src/main/res/drawable-xhdpi/ic_notif_action_reply.png new file mode 100644 index 000000000..775b2a724 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/ic_notif_action_reply.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/ic_notif_action_reply.png b/android/app/src/main/res/drawable-xxhdpi/ic_notif_action_reply.png new file mode 100644 index 000000000..c5cd53e89 Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/ic_notif_action_reply.png differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/ic_notif_action_reply.png b/android/app/src/main/res/drawable-xxxhdpi/ic_notif_action_reply.png new file mode 100644 index 000000000..36600d49a Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/ic_notif_action_reply.png differ diff --git a/app/components/badge.js b/app/components/badge.js index c5a0ab008..2efa43ced 100644 --- a/app/components/badge.js +++ b/app/components/badge.js @@ -91,7 +91,7 @@ export default class Badge extends PureComponent { setTimeout(() => { this.setNativeProps({ style: { - display: 'flex' + opacity: 1 } }); }, 100); @@ -125,7 +125,7 @@ export default class Badge extends PureComponent { > {this.renderText()} diff --git a/app/mattermost.js b/app/mattermost.js index 8c048b7b2..e2b4c14e8 100644 --- a/app/mattermost.js +++ b/app/mattermost.js @@ -5,7 +5,7 @@ import 'babel-polyfill'; import Analytics from 'analytics-react-native'; import Orientation from 'react-native-orientation'; import {Provider} from 'react-redux'; -import {Navigation} from 'react-native-navigation'; +import {Navigation, NativeEventsReceiver} from 'react-native-navigation'; import {IntlProvider} from 'react-intl'; import { Alert, @@ -23,6 +23,7 @@ import {General} from 'mattermost-redux/constants'; import {setAppState, setDeviceToken, setServerVersion} from 'mattermost-redux/actions/general'; import {markChannelAsRead} from 'mattermost-redux/actions/channels'; import {logError} from 'mattermost-redux/actions/errors'; +import {createPost} from 'mattermost-redux/actions/posts'; import {logout} from 'mattermost-redux/actions/users'; import {close as closeWebSocket} from 'mattermost-redux/actions/websocket'; import {Client, Client4} from 'mattermost-redux/client'; @@ -149,6 +150,7 @@ export default class Mattermost { PushNotifications.configure({ onRegister: this.onRegisterDevice, onNotification: this.onPushNotification, + onReply: this.onPushNotificationReply, popInitialNotification: true, requestPermissions: true }); @@ -158,24 +160,30 @@ export default class Mattermost { const {dispatch, getState} = store; const isActive = appState === 'active'; setAppState(isActive)(dispatch, getState); - try { - if (!isActive && !this.inBackgroundSince) { - this.inBackgroundSince = Date.now(); - } else if (isActive && this.inBackgroundSince && (Date.now() - this.inBackgroundSince) >= AUTHENTICATION_TIMEOUT) { - this.inBackgroundSince = null; - if (this.mdmEnabled) { - const config = await mattermostManaged.getConfig(); - const authNeeded = config.inAppPinCode && config.inAppPinCode === 'true'; - if (authNeeded) { - const authenticated = await this.handleAuthentication(config.vendor); - if (!authenticated) { - mattermostManaged.quitApp(); + + if (isActive && this.shouldRelaunchonActive) { + this.launchApp(); + this.shouldRelaunchonActive = false; + } else { + try { + if (!isActive && !this.inBackgroundSince) { + this.inBackgroundSince = Date.now(); + } else if (isActive && this.inBackgroundSince && (Date.now() - this.inBackgroundSince) >= AUTHENTICATION_TIMEOUT) { + this.inBackgroundSince = null; + if (this.mdmEnabled) { + const config = await mattermostManaged.getConfig(); + const authNeeded = config.inAppPinCode && config.inAppPinCode === 'true'; + if (authNeeded) { + const authenticated = await this.handleAuthentication(config.vendor); + if (!authenticated) { + mattermostManaged.quitApp(); + } } } } + } catch (error) { + // do nothing } - } catch (error) { - // do nothing } }; @@ -347,11 +355,33 @@ export default class Mattermost { const state = store.getState(); if (state.views.root.hydrationComplete) { this.unsubscribeFromStore(); - this.handleManagedConfig().then((shouldStart) => { - if (shouldStart) { - this.startApp(); - } - }); + + const notification = PushNotifications.getNotification(); + if (notification) { + // If we have a notification means that the app was started cause of a reply + // and the app was not sitting in the background nor opened + const {data, text, badge} = notification; + this.onPushNotificationReply(data, text, badge); + PushNotifications.resetNotification(); + } + + if (Platform.OS === 'android') { + // In case of Android we need to handle the bridge being initialized by HeadlessJS + Promise.resolve(Navigation.isAppLaunched()).then((appLaunched) => { + if (appLaunched) { + this.launchApp(); // App is launched -> show UI + } else { + new NativeEventsReceiver().appLaunched(this.launchApp); // App hasn't been launched yet -> show the UI only when needed. + } + }); + } else if (AppState.currentState === 'background') { + // for IOS replying from push notification starts the app in the background + this.shouldRelaunchonActive = true; + this.configurePushNotifications(); + this.startFakeApp(); + } else { + this.launchApp(); + } } }; @@ -366,6 +396,7 @@ export default class Mattermost { } else { prefix = General.PUSH_NOTIFY_ANDROID_REACT_NATIVE; } + setDeviceToken(`${prefix}:${data.token}`)(dispatch, getState); this.isConfigured = true; }; @@ -407,6 +438,46 @@ export default class Mattermost { } }; + onPushNotificationReply = (data, text, badge, completed) => { + const {dispatch, getState} = store; + const state = getState(); + const {currentUserId} = state.entities.users; + + if (currentUserId) { + // one thing to note is that for android it will reply to the last post in the stack + const rootId = data.root_id || data.post_id; + const post = { + user_id: currentUserId, + channel_id: data.channel_id, + root_id: rootId, + parent_id: rootId, + message: text + }; + + if (!Client4.getUrl()) { + // Make sure the Client has the server url set + Client4.setUrl(state.entities.general.credentials.url); + } + + if (!Client.getToken()) { + // Make sure the Client has the server token set + Client4.setToken(state.entities.general.credentials.token); + } + + createPost(post)(dispatch, getState); + markChannelAsRead(data.channel_id)(dispatch, getState); + + if (badge >= 0) { + PushNotifications.setApplicationIconBadgeNumber(badge); + } + } + + if (completed) { + // You must call to completed(), otherwise the action will not be triggered + completed(); + } + }; + resetBadgeAndVersion = () => { const {dispatch, getState} = store; Client4.serverVersion = ''; @@ -426,6 +497,14 @@ export default class Mattermost { this.startApp('fade'); }; + launchApp = () => { + this.handleManagedConfig().then((shouldStart) => { + if (shouldStart) { + this.startApp(); + } + }); + }; + startFakeApp = async () => { return Navigation.startSingleScreenApp({ screen: { @@ -443,6 +522,10 @@ export default class Mattermost { }; startApp = (animationType = 'none') => { + if (!this.isConfigured) { + this.configurePushNotifications(); + } + Navigation.startSingleScreenApp({ screen: { screen: 'Root', @@ -457,9 +540,5 @@ export default class Mattermost { }, animationType }); - - if (!this.isConfigured) { - this.configurePushNotifications(); - } }; } diff --git a/app/push_notifications/push_notifications.android.js b/app/push_notifications/push_notifications.android.js index 6051c6c7b..051f5ad56 100644 --- a/app/push_notifications/push_notifications.android.js +++ b/app/push_notifications/push_notifications.android.js @@ -1,13 +1,16 @@ // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import {AppState} from 'react-native'; +import {AppRegistry, AppState} from 'react-native'; import {NotificationsAndroid, PendingNotifications} from 'react-native-notifications'; +import Notification from 'react-native-notifications/notification.android'; class PushNotification { constructor() { this.onRegister = null; this.onNotification = null; + this.onReply = null; + this.deviceNotification = null; NotificationsAndroid.setNotificationReceivedListener((notification) => { if (notification) { @@ -22,6 +25,21 @@ class PushNotification { this.handleNotification(data, true); } }); + + AppRegistry.registerHeadlessTask('notificationReplied', () => async (deviceNotification) => { + const notification = new Notification(deviceNotification); + const data = notification.getData(); + + if (this.onReply && AppState.currentState === 'background') { + this.onReply(data, data.text, parseInt(data.badge, 10) - parseInt(data.msg_count, 10)); + } else { + this.deviceNotification = { + data, + text: data.text, + badge: parseInt(data.badge, 10) - parseInt(data.msg_count, 10) + }; + } + }); } handleNotification = (data, userInteraction) => { @@ -41,6 +59,7 @@ class PushNotification { configure(options) { this.onRegister = options.onRegister; this.onNotification = options.onNotification; + this.onReply = options.onReply; NotificationsAndroid.refreshToken(); NotificationsAndroid.setRegistrationTokenUpdateListener((deviceToken) => { @@ -80,6 +99,14 @@ class PushNotification { setApplicationIconBadgeNumber(number) { NotificationsAndroid.setBadgesCount(number); } + + getNotification() { + return this.deviceNotification; + } + + resetNotification() { + this.deviceNotification = null; + } } export default new PushNotification(); diff --git a/app/push_notifications/push_notifications.ios.js b/app/push_notifications/push_notifications.ios.js index eef25fadf..7cea3c312 100644 --- a/app/push_notifications/push_notifications.ios.js +++ b/app/push_notifications/push_notifications.ios.js @@ -2,12 +2,18 @@ // See License.txt for license information. import {AppState} from 'react-native'; -import NotificationsIOS from 'react-native-notifications'; +import NotificationsIOS, {NotificationAction, NotificationCategory} from 'react-native-notifications'; + +const CATEGORY = 'CAN_REPLY'; +const REPLY_ACTION = 'REPLY_ACTION'; + +let replyCategory; class PushNotification { constructor() { this.onRegister = null; this.onNotification = null; + this.onReply = null; NotificationsIOS.addEventListener('notificationReceivedForeground', (notification) => { const info = { @@ -32,6 +38,20 @@ class PushNotification { }; this.handleNotification(info, false, true); }); + + const replyAction = new NotificationAction({ + activationMode: 'background', + title: 'Reply', + behavior: 'textInput', + authenticationRequired: true, + identifier: REPLY_ACTION + }, this.handleReply); + + replyCategory = new NotificationCategory({ + identifier: CATEGORY, + actions: [replyAction], + context: 'default' + }); } handleNotification = (data, foreground, userInteraction) => { @@ -48,9 +68,24 @@ class PushNotification { } }; + handleReply = (action, completed) => { + if (action.identifier === REPLY_ACTION) { + const data = action.notification.getData(); + const text = action.text; + const badge = parseInt(action.notification._badge, 10) - 1; //eslint-disable-line no-underscore-dangle + + if (this.onReply) { + this.onReply(data, text, badge, completed); + } + } else { + completed(); + } + }; + configure(options) { this.onRegister = options.onRegister; this.onNotification = options.onNotification; + this.onReply = options.onReply; NotificationsIOS.addEventListener('remoteNotificationsRegistered', (deviceToken) => { if (this.onRegister) { @@ -59,7 +94,7 @@ class PushNotification { }); if (options.requestPermissions) { - this.requestPermissions(); + this.requestPermissions([replyCategory]); } if (options.popInitialNotification) { @@ -67,8 +102,8 @@ class PushNotification { } } - requestPermissions = () => { - NotificationsIOS.requestPermissions(); + requestPermissions = (permissions) => { + NotificationsIOS.requestPermissions(permissions); }; localNotificationSchedule(notification) { @@ -91,6 +126,10 @@ class PushNotification { setApplicationIconBadgeNumber(number) { NotificationsIOS.setBadgesCount(number); } + + getNotification() { + return null; + } } export default new PushNotification(); diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 5fdc68639..8dc07e169 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -350,7 +350,13 @@ platform :android do ) find_replace_string( - path_to_file: './android/app/src/main/java/com/mattermost/rn/NotificationDismissReceiver.java', + path_to_file: './android/app/src/main/java/com/mattermost/rn/NotificationDismissService.java', + old_string: 'package com.mattermost.rnbeta;', + new_string: 'package com.mattermost.rn;' + ) + + find_replace_string( + path_to_file: './android/app/src/main/java/com/mattermost/rn/NotificationReplyService.java', old_string: 'package com.mattermost.rnbeta;', new_string: 'package com.mattermost.rn;' ) diff --git a/ios/Mattermost.xcodeproj/project.pbxproj b/ios/Mattermost.xcodeproj/project.pbxproj index fa042cd0c..024e38532 100644 --- a/ios/Mattermost.xcodeproj/project.pbxproj +++ b/ios/Mattermost.xcodeproj/project.pbxproj @@ -5,7 +5,6 @@ }; objectVersion = 46; objects = { - /* Begin PBXBuildFile section */ 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; }; 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; }; @@ -1435,7 +1434,6 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "\"$(SRCROOT)/$(TARGET_NAME)\"", ); PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1453,7 +1451,6 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "\"$(SRCROOT)/$(TARGET_NAME)\"", ); PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/ios/Mattermost/AppDelegate.m b/ios/Mattermost/AppDelegate.m index 0dfe7074b..b73499115 100644 --- a/ios/Mattermost/AppDelegate.m +++ b/ios/Mattermost/AppDelegate.m @@ -60,4 +60,16 @@ { [RNNotifications didReceiveLocalNotification:notification]; } + +// Required for the notification actions. +- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())completionHandler +{ + [RNNotifications handleActionWithIdentifier:identifier forLocalNotification:notification withResponseInfo:responseInfo completionHandler:completionHandler]; +} + +- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())completionHandler +{ + [RNNotifications handleActionWithIdentifier:identifier forRemoteNotification:userInfo withResponseInfo:responseInfo completionHandler:completionHandler]; +} + @end diff --git a/ios/Mattermost/Info.plist b/ios/Mattermost/Info.plist index 13f33d3af..e326a3199 100644 --- a/ios/Mattermost/Info.plist +++ b/ios/Mattermost/Info.plist @@ -44,7 +44,7 @@ NSCameraUsageDescription Take a Photo or Video and upload it to your mattermost instance NSLocationWhenInUseUsageDescription - + NSPhotoLibraryUsageDescription Upload Photos and Videos to your Mattermost instance UIAppFonts @@ -57,16 +57,8 @@ MaterialIcons.ttf Octicons.ttf Zocial.ttf - Entypo.ttf - EvilIcons.ttf - FontAwesome.ttf - Foundation.ttf - Ionicons.ttf MaterialCommunityIcons.ttf - MaterialIcons.ttf - Octicons.ttf SimpleLineIcons.ttf - Zocial.ttf OpenSans-Bold.ttf OpenSans-BoldItalic.ttf OpenSans-ExtraBold.ttf diff --git a/yarn.lock b/yarn.lock index ebc7873cf..2c8c0442e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4560,8 +4560,8 @@ react-native-navigation@1.1.131: lodash "4.x.x" react-native-notifications@enahum/react-native-notifications.git: - version "1.1.11" - resolved "https://codeload.github.com/enahum/react-native-notifications/tar.gz/a8450bcbfc6ae46ed4b97f6fe723aac44c8ad598" + version "1.1.15" + resolved "https://codeload.github.com/enahum/react-native-notifications/tar.gz/084d5e928d8149e711c1b6c384f3d87cc16072f9" dependencies: core-js "^1.0.0" uuid "^2.0.3"