From f71e8a998244be6a7b147e9ed34215e964447e44 Mon Sep 17 00:00:00 2001 From: tmoldovan8x8 <62697631+tmoldovan8x8@users.noreply.github.com> Date: Wed, 17 Feb 2021 16:26:40 +0200 Subject: [PATCH] feat(mobile) adds actions and events for the chat --- .../org/jitsi/meet/sdk/BroadcastAction.java | 5 +- .../org/jitsi/meet/sdk/BroadcastEvent.java | 10 ++- .../jitsi/meet/sdk/BroadcastIntentHelper.java | 17 ++++ .../org/jitsi/meet/sdk/ExternalAPIModule.java | 3 + ios/app/src/ViewController.m | 8 ++ ios/sdk/src/ExternalAPI.h | 5 +- ios/sdk/src/ExternalAPI.m | 41 +++++++-- ios/sdk/src/JitsiMeetView.h | 8 +- ios/sdk/src/JitsiMeetView.m | 15 ++++ ios/sdk/src/JitsiMeetViewDelegate.h | 14 ++++ react/features/chat/middleware.js | 2 + .../mobile/external-api/middleware.js | 83 ++++++++++++++++++- 12 files changed, 194 insertions(+), 17 deletions(-) diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/BroadcastAction.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/BroadcastAction.java index c40a35322..be01b253d 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/BroadcastAction.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/BroadcastAction.java @@ -63,7 +63,10 @@ public class BroadcastAction { HANG_UP("org.jitsi.meet.HANG_UP"), SEND_ENDPOINT_TEXT_MESSAGE("org.jitsi.meet.SEND_ENDPOINT_TEXT_MESSAGE"), TOGGLE_SCREEN_SHARE("org.jitsi.meet.TOGGLE_SCREEN_SHARE"), - RETRIEVE_PARTICIPANTS_INFO("org.jitsi.meet.RETRIEVE_PARTICIPANTS_INFO"); + RETRIEVE_PARTICIPANTS_INFO("org.jitsi.meet.RETRIEVE_PARTICIPANTS_INFO"), + OPEN_CHAT("org.jitsi.meet.OPEN_CHAT"), + CLOSE_CHAT("org.jitsi.meet.CLOSE_CHAT"), + SEND_CHAT_MESSAGE("org.jitsi.meet.SEND_CHAT_MESSAGE"); private final String action; diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/BroadcastEvent.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/BroadcastEvent.java index a1dfa09f3..05241d64d 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/BroadcastEvent.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/BroadcastEvent.java @@ -83,7 +83,9 @@ public class BroadcastEvent { PARTICIPANT_LEFT("org.jitsi.meet.PARTICIPANT_LEFT"), ENDPOINT_TEXT_MESSAGE_RECEIVED("org.jitsi.meet.ENDPOINT_TEXT_MESSAGE_RECEIVED"), SCREEN_SHARE_TOGGLED("org.jitsi.meet.SCREEN_SHARE_TOGGLED"), - PARTICIPANTS_INFO_RETRIEVED("org.jitsi.meet.PARTICIPANTS_INFO_RETRIEVED"); + PARTICIPANTS_INFO_RETRIEVED("org.jitsi.meet.PARTICIPANTS_INFO_RETRIEVED"), + CHAT_MESSAGE_RECEIVED("org.jitsi.meet.CHAT_MESSAGE_RECEIVED"), + CHAT_TOGGLED("org.jitsi.meet.CHAT_TOGGLED"); private static final String CONFERENCE_WILL_JOIN_NAME = "CONFERENCE_WILL_JOIN"; private static final String CONFERENCE_JOINED_NAME = "CONFERENCE_JOINED"; @@ -94,6 +96,8 @@ public class BroadcastEvent { private static final String ENDPOINT_TEXT_MESSAGE_RECEIVED_NAME = "ENDPOINT_TEXT_MESSAGE_RECEIVED"; private static final String SCREEN_SHARE_TOGGLED_NAME = "SCREEN_SHARE_TOGGLED"; private static final String PARTICIPANTS_INFO_RETRIEVED_NAME = "PARTICIPANTS_INFO_RETRIEVED"; + private static final String CHAT_MESSAGE_RECEIVED_NAME = "CHAT_MESSAGE_RECEIVED"; + private static final String CHAT_TOGGLED_NAME = "CHAT_TOGGLED"; private final String action; @@ -134,6 +138,10 @@ public class BroadcastEvent { return SCREEN_SHARE_TOGGLED; case PARTICIPANTS_INFO_RETRIEVED_NAME: return PARTICIPANTS_INFO_RETRIEVED; + case CHAT_MESSAGE_RECEIVED_NAME: + return CHAT_MESSAGE_RECEIVED; + case CHAT_TOGGLED_NAME: + return CHAT_TOGGLED; } return null; diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/BroadcastIntentHelper.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/BroadcastIntentHelper.java index b471edf24..388a17c76 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/BroadcastIntentHelper.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/BroadcastIntentHelper.java @@ -23,4 +23,21 @@ public class BroadcastIntentHelper { public static Intent buildToggleScreenShareIntent() { return new Intent(BroadcastAction.Type.TOGGLE_SCREEN_SHARE.getAction()); } + + public static Intent buildOpenChatIntent(String participantId) { + Intent intent = new Intent(BroadcastAction.Type.OPEN_CHAT.getAction()); + intent.putExtra("to", participantId); + return intent; + } + + public static Intent buildCloseChatIntent() { + return new Intent(BroadcastAction.Type.CLOSE_CHAT.getAction()); + } + + public static Intent buildSendChatMessageIntent(String participantId, String message) { + Intent intent = new Intent(BroadcastAction.Type.SEND_CHAT_MESSAGE.getAction()); + intent.putExtra("to", participantId); + intent.putExtra("message", message); + return intent; + } } diff --git a/android/sdk/src/main/java/org/jitsi/meet/sdk/ExternalAPIModule.java b/android/sdk/src/main/java/org/jitsi/meet/sdk/ExternalAPIModule.java index 17f5d6ff6..3a149a6bf 100644 --- a/android/sdk/src/main/java/org/jitsi/meet/sdk/ExternalAPIModule.java +++ b/android/sdk/src/main/java/org/jitsi/meet/sdk/ExternalAPIModule.java @@ -82,6 +82,9 @@ class ExternalAPIModule constants.put("SEND_ENDPOINT_TEXT_MESSAGE", BroadcastAction.Type.SEND_ENDPOINT_TEXT_MESSAGE.getAction()); constants.put("TOGGLE_SCREEN_SHARE", BroadcastAction.Type.TOGGLE_SCREEN_SHARE.getAction()); constants.put("RETRIEVE_PARTICIPANTS_INFO", BroadcastAction.Type.RETRIEVE_PARTICIPANTS_INFO.getAction()); + constants.put("OPEN_CHAT", BroadcastAction.Type.OPEN_CHAT.getAction()); + constants.put("CLOSE_CHAT", BroadcastAction.Type.CLOSE_CHAT.getAction()); + constants.put("SEND_CHAT_MESSAGE", BroadcastAction.Type.SEND_CHAT_MESSAGE.getAction()); return constants; } diff --git a/ios/app/src/ViewController.m b/ios/app/src/ViewController.m index feb606363..9884f8c51 100644 --- a/ios/app/src/ViewController.m +++ b/ios/app/src/ViewController.m @@ -123,6 +123,14 @@ NSLog(@"%@%@", @"Screen share toggled: ", data); } +- (void)chatMessageReceived:(NSDictionary *)data { + NSLog(@"%@%@", @"Chat message received: ", data); +} + +- (void)chatToggled:(NSDictionary *)data { + NSLog(@"%@%@", @"Chat toggled: ", data); +} + #pragma mark - Helpers - (void)terminate { diff --git a/ios/sdk/src/ExternalAPI.h b/ios/sdk/src/ExternalAPI.h index 7c2ed8187..2adaa34ce 100644 --- a/ios/sdk/src/ExternalAPI.h +++ b/ios/sdk/src/ExternalAPI.h @@ -19,9 +19,12 @@ @interface ExternalAPI : RCTEventEmitter - (void)sendHangUp; -- (void)sendSetAudioMuted: (BOOL)muted; +- (void)sendSetAudioMuted:(BOOL)muted; - (void)sendEndpointTextMessage:(NSString*)to :(NSString*)message; - (void)toggleScreenShare; - (void)retrieveParticipantsInfo:(void (^)(NSArray*))completion; +- (void)openChat:(NSString*)to; +- (void)closeChat; +- (void)sendChatMessage:(NSString*)to :(NSString*)message; @end diff --git a/ios/sdk/src/ExternalAPI.m b/ios/sdk/src/ExternalAPI.m index 4dbc8e979..c62529fb1 100644 --- a/ios/sdk/src/ExternalAPI.m +++ b/ios/sdk/src/ExternalAPI.m @@ -23,6 +23,9 @@ static NSString * const setAudioMutedAction = @"org.jitsi.meet.SET_AUDIO_MUTED"; static NSString * const sendEndpointTextMessageAction = @"org.jitsi.meet.SEND_ENDPOINT_TEXT_MESSAGE"; static NSString * const toggleScreenShareAction = @"org.jitsi.meet.TOGGLE_SCREEN_SHARE"; static NSString * const retrieveParticipantsInfoAction = @"org.jitsi.meet.RETRIEVE_PARTICIPANTS_INFO"; +static NSString * const openChatAction = @"org.jitsi.meet.OPEN_CHAT"; +static NSString * const closeChatAction = @"org.jitsi.meet.CLOSE_CHAT"; +static NSString * const sendChatMessageAction = @"org.jitsi.meet.SEND_CHAT_MESSAGE"; @implementation ExternalAPI @@ -41,7 +44,10 @@ RCT_EXPORT_MODULE(); @"SET_AUDIO_MUTED" : setAudioMutedAction, @"SEND_ENDPOINT_TEXT_MESSAGE": sendEndpointTextMessageAction, @"TOGGLE_SCREEN_SHARE": toggleScreenShareAction, - @"RETRIEVE_PARTICIPANTS_INFO": retrieveParticipantsInfoAction + @"RETRIEVE_PARTICIPANTS_INFO": retrieveParticipantsInfoAction, + @"OPEN_CHAT": openChatAction, + @"CLOSE_CHAT": closeChatAction, + @"SEND_CHAT_MESSAGE": sendChatMessageAction }; }; @@ -61,7 +67,11 @@ RCT_EXPORT_MODULE(); setAudioMutedAction, sendEndpointTextMessageAction, toggleScreenShareAction, - retrieveParticipantsInfoAction]; + retrieveParticipantsInfoAction, + openChatAction, + closeChatAction, + sendChatMessageAction + ]; } /** @@ -144,10 +154,9 @@ RCT_EXPORT_METHOD(sendEvent:(NSString *)name } - (void)sendEndpointTextMessage:(NSString*)to :(NSString*)message { - NSDictionary *data = @{ - @"to": to, - @"message": message - }; + NSMutableDictionary *data = [[NSMutableDictionary alloc] init]; + data[@"to"] = to; + data[@"message"] = message; [self sendEventWithName:sendEndpointTextMessageAction body:data]; } @@ -164,4 +173,24 @@ RCT_EXPORT_METHOD(sendEvent:(NSString *)name [self sendEventWithName:retrieveParticipantsInfoAction body:data]; } + +- (void)openChat:(NSString*)to { + NSMutableDictionary *data = [[NSMutableDictionary alloc] init]; + data[@"to"] = to; + + [self sendEventWithName:openChatAction body:data]; +} + +- (void)closeChat { + [self sendEventWithName:closeChatAction body:nil]; +} + +- (void)sendChatMessage:(NSString*)to :(NSString*)message { + NSMutableDictionary *data = [[NSMutableDictionary alloc] init]; + data[@"to"] = to; + data[@"message"] = message; + + [self sendEventWithName:sendChatMessageAction body:data]; +} + @end diff --git a/ios/sdk/src/JitsiMeetView.h b/ios/sdk/src/JitsiMeetView.h index 9a5cbdc2d..447de36ad 100644 --- a/ios/sdk/src/JitsiMeetView.h +++ b/ios/sdk/src/JitsiMeetView.h @@ -36,15 +36,13 @@ * Leaves the currently active conference. */ - (void)leave; - - (void)hangUp; - - (void)setAudioMuted:(BOOL)muted; - - (void)sendEndpointTextMessage:(NSString*)to :(NSString*)message; - - (void)toggleScreenShare; - - (void)retrieveParticipantsInfo:(void (^)(NSArray*))completionHandler; +- (void)openChat:(NSString*)to; +- (void)closeChat; +- (void)sendChatMessage:(NSString*)to :(NSString*)message; @end diff --git a/ios/sdk/src/JitsiMeetView.m b/ios/sdk/src/JitsiMeetView.m index ebdecbbfd..1bff175bc 100644 --- a/ios/sdk/src/JitsiMeetView.m +++ b/ios/sdk/src/JitsiMeetView.m @@ -140,6 +140,21 @@ static void initializeViewsMap() { [externalAPI retrieveParticipantsInfo:completionHandler]; } +- (void)openChat:(NSString*)to { + ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI]; + [externalAPI openChat:to]; +} + +- (void)closeChat { + ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI]; + [externalAPI closeChat]; +} + +- (void)sendChatMessage:(NSString*)to :(NSString*)message { + ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI]; + [externalAPI sendChatMessage:to :message]; +} + #pragma mark Private methods /** diff --git a/ios/sdk/src/JitsiMeetViewDelegate.h b/ios/sdk/src/JitsiMeetViewDelegate.h index 83e219b36..eb14e6f22 100644 --- a/ios/sdk/src/JitsiMeetViewDelegate.h +++ b/ios/sdk/src/JitsiMeetViewDelegate.h @@ -90,4 +90,18 @@ */ - (void)screenShareToggled:(NSDictionary *)data; +/** + * Called when a chat message is received. + * + * The `data` dictionary contains `message`, `senderId` and `isPrivate` keys. + */ +- (void)chatMessaageReceived:(NSDictionary *)data; + +/** + * Called when the chat dialog is displayed/hidden. + * + * The `data` dictionary contains a `isOpen` key. + */ +- (void)chatToggled:(NSDictionary *)data; + @end diff --git a/react/features/chat/middleware.js b/react/features/chat/middleware.js index dcc4ac373..f1929f01f 100644 --- a/react/features/chat/middleware.js +++ b/react/features/chat/middleware.js @@ -104,6 +104,8 @@ MiddlewareRegistry.register(store => next => action => { if (typeof APP !== 'undefined') { APP.API.notifyChatUpdated(unreadCount, true); } + + dispatch(setActiveModalId()); break; case SEND_MESSAGE: { diff --git a/react/features/mobile/external-api/middleware.js b/react/features/mobile/external-api/middleware.js index 2d7af2b2d..4e8836501 100644 --- a/react/features/mobile/external-api/middleware.js +++ b/react/features/mobile/external-api/middleware.js @@ -27,9 +27,12 @@ import { } from '../../base/connection'; import { JitsiConferenceEvents } from '../../base/lib-jitsi-meet'; import { SET_AUDIO_MUTED } from '../../base/media/actionTypes'; -import { PARTICIPANT_JOINED, PARTICIPANT_LEFT, getParticipants } from '../../base/participants'; +import { PARTICIPANT_JOINED, PARTICIPANT_LEFT, getParticipants, getParticipantById } from '../../base/participants'; import { MiddlewareRegistry, StateListenerRegistry } from '../../base/redux'; import { toggleScreensharing } from '../../base/tracks'; +import { OPEN_CHAT, CLOSE_CHAT } from '../../chat'; +import { openChat } from '../../chat/actions'; +import { sendMessage, setPrivateMessageRecipient, closeChat } from '../../chat/actions.any'; import { muteLocal } from '../../remote-video-menu/actions'; import { ENTER_PICTURE_IN_PICTURE } from '../picture-in-picture'; @@ -37,6 +40,17 @@ import { setParticipantsWithScreenShare } from './actions'; import { sendEvent } from './functions'; import logger from './logger'; +/** + * Event which will be emitted on the native side when a chat message is received + * through the channel. + */ +const CHAT_MESSAGE_RECEIVED = 'CHAT_MESSAGE_RECEIVED'; + +/** + * Event which will be emitted on the native side when the chat dialog is displayed/closed. + */ +const CHAT_TOGGLED = 'CHAT_TOGGLED'; + /** * Event which will be emitted on the native side to indicate the conference * has ended either by user request or because an error was produced. @@ -152,6 +166,17 @@ MiddlewareRegistry.register(store => next => action => { break; } + case OPEN_CHAT: + case CLOSE_CHAT: { + sendEvent( + store, + CHAT_TOGGLED, + /* data */ { + isOpen: action.type === OPEN_CHAT + }); + break; + } + case PARTICIPANT_JOINED: case PARTICIPANT_LEFT: { const { participant } = action; @@ -237,7 +262,9 @@ StateListenerRegistry.register( * @private * @returns {void} */ -function _registerForNativeEvents({ getState, dispatch }) { +function _registerForNativeEvents(store) { + const { getState, dispatch } = store; + eventEmitter.addListener(ExternalAPI.HANG_UP, () => { dispatch(appNavigate(undefined)); }); @@ -264,7 +291,6 @@ function _registerForNativeEvents({ getState, dispatch }) { }); eventEmitter.addListener(ExternalAPI.RETRIEVE_PARTICIPANTS_INFO, ({ requestId }) => { - const store = getState(); const participantsInfo = getParticipants(store).map(participant => { return { @@ -286,6 +312,27 @@ function _registerForNativeEvents({ getState, dispatch }) { requestId }); }); + + eventEmitter.addListener(ExternalAPI.OPEN_CHAT, ({ to }) => { + const participant = getParticipantById(store, to); + + dispatch(openChat(participant)); + }); + + eventEmitter.addListener(ExternalAPI.CLOSE_CHAT, () => { + dispatch(closeChat()); + }); + + eventEmitter.addListener(ExternalAPI.SEND_CHAT_MESSAGE, ({ message, to }) => { + const participant = getParticipantById(store, to); + + if (participant) { + dispatch(setPrivateMessageRecipient(participant)); + } + + dispatch(sendMessage(message)); + }); + } /** @@ -315,6 +362,36 @@ function _registerForEndpointTextMessages(store) { } } }); + + conference.on( + JitsiConferenceEvents.MESSAGE_RECEIVED, + (id, message, timestamp) => { + sendEvent( + store, + CHAT_MESSAGE_RECEIVED, + /* data */ { + senderId: id, + message, + isPrivate: false, + timestamp + }); + } + ); + + conference.on( + JitsiConferenceEvents.PRIVATE_MESSAGE_RECEIVED, + (id, message, timestamp) => { + sendEvent( + store, + CHAT_MESSAGE_RECEIVED, + /* data */ { + senderId: id, + message, + isPrivate: true, + timestamp + }); + } + ); } /**