[RN] Reduce maintenance
JitsiMeetViewListener currently has methods of one and the same pattern so adding new methods i.e. events i.e. redux action types is a question of repetition in the Java source code. Speed up the support of new events by trying to deal with them in a generic way. The same goes for JitsiMeetViewDelegate.
This commit is contained in:
parent
6982506acc
commit
1d8ee9d32f
|
@ -25,7 +25,12 @@ import com.facebook.react.bridge.ReadableMapKeySetIterator;
|
||||||
import org.jitsi.meet.sdk.JitsiMeetView;
|
import org.jitsi.meet.sdk.JitsiMeetView;
|
||||||
import org.jitsi.meet.sdk.JitsiMeetViewListener;
|
import org.jitsi.meet.sdk.JitsiMeetViewListener;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module implementing a simple API to enable a proximity sensor-controlled
|
* Module implementing a simple API to enable a proximity sensor-controlled
|
||||||
|
@ -35,10 +40,60 @@ import java.util.HashMap;
|
||||||
*/
|
*/
|
||||||
class ExternalAPIModule extends ReactContextBaseJavaModule {
|
class ExternalAPIModule extends ReactContextBaseJavaModule {
|
||||||
/**
|
/**
|
||||||
* React Native module name.
|
* The {@code Method}s of {@code JitsiMeetViewListener} by event name i.e.
|
||||||
|
* redux action types.
|
||||||
|
*/
|
||||||
|
private static final Map<String, Method> JITSI_MEET_VIEW_LISTENER_METHODS
|
||||||
|
= new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of this module to be used in the React Native bridge.
|
||||||
*/
|
*/
|
||||||
private static final String MODULE_NAME = "ExternalAPI";
|
private static final String MODULE_NAME = "ExternalAPI";
|
||||||
|
|
||||||
|
static {
|
||||||
|
// Figure out the mapping between the JitsiMeetViewListener methods
|
||||||
|
// and the events i.e. redux action types.
|
||||||
|
Pattern onPattern = Pattern.compile("^on[A-Z]+");
|
||||||
|
Pattern camelcasePattern = Pattern.compile("([a-z0-9]+)([A-Z0-9]+)");
|
||||||
|
|
||||||
|
for (Method method : JitsiMeetViewListener.class.getDeclaredMethods()) {
|
||||||
|
// * The method must be public (because it is declared by an
|
||||||
|
// interface).
|
||||||
|
// * The method must be/return void.
|
||||||
|
if (!Modifier.isPublic(method.getModifiers())
|
||||||
|
|| !Void.TYPE.equals(method.getReturnType())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// * The method name must start with "on" followed by a
|
||||||
|
// capital/uppercase letter (in agreement with the camelcase
|
||||||
|
// coding style customary to Java in general and the projects of
|
||||||
|
// the Jitsi community in particular).
|
||||||
|
String name = method.getName();
|
||||||
|
|
||||||
|
if (!onPattern.matcher(name).find()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// * The method must accept/have exactly 1 parameter of a type
|
||||||
|
// assignable from HashMap.
|
||||||
|
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||||
|
|
||||||
|
if (parameterTypes.length != 1
|
||||||
|
|| !parameterTypes[0].isAssignableFrom(HashMap.class)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the method name to an event name.
|
||||||
|
name
|
||||||
|
= camelcasePattern.matcher(name.substring(2))
|
||||||
|
.replaceAll("$1_$2")
|
||||||
|
.toUpperCase(Locale.ROOT);
|
||||||
|
JITSI_MEET_VIEW_LISTENER_METHODS.put(name, method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a new module instance. There shall be a single instance of
|
* Initializes a new module instance. There shall be a single instance of
|
||||||
* this module throughout the lifetime of the application.
|
* this module throughout the lifetime of the application.
|
||||||
|
@ -85,26 +140,14 @@ class ExternalAPIModule extends ReactContextBaseJavaModule {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (name) {
|
Method method = JITSI_MEET_VIEW_LISTENER_METHODS.get(name);
|
||||||
case "CONFERENCE_FAILED":
|
|
||||||
listener.onConferenceFailed(toHashMap(data));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "CONFERENCE_JOINED":
|
if (method != null) {
|
||||||
listener.onConferenceJoined(toHashMap(data));
|
try {
|
||||||
break;
|
method.invoke(listener, toHashMap(data));
|
||||||
|
} catch (ReflectiveOperationException roe) {
|
||||||
case "CONFERENCE_LEFT":
|
throw new RuntimeException(roe);
|
||||||
listener.onConferenceLeft(toHashMap(data));
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case "CONFERENCE_WILL_JOIN":
|
|
||||||
listener.onConferenceWillJoin(toHashMap(data));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "CONFERENCE_WILL_LEAVE":
|
|
||||||
listener.onConferenceWillLeave(toHashMap(data));
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,26 +52,33 @@ RCT_EXPORT_METHOD(sendEvent:(NSString *)name
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([name isEqualToString:@"CONFERENCE_FAILED"]
|
SEL sel = NSSelectorFromString([self methodNameFromEventName:name]);
|
||||||
&& [delegate respondsToSelector:@selector(conferenceFailed:)]) {
|
|
||||||
[delegate conferenceFailed:data];
|
|
||||||
|
|
||||||
} else if ([name isEqualToString:@"CONFERENCE_JOINED"]
|
if (sel && [delegate respondsToSelector:sel]) {
|
||||||
&& [delegate respondsToSelector:@selector(conferenceJoined:)]) {
|
[delegate performSelector:sel withObject:data];
|
||||||
[delegate conferenceJoined:data];
|
|
||||||
|
|
||||||
} else if ([name isEqualToString:@"CONFERENCE_LEFT"]
|
|
||||||
&& [delegate respondsToSelector:@selector(conferenceLeft:)]) {
|
|
||||||
[delegate conferenceLeft:data];
|
|
||||||
|
|
||||||
} else if ([name isEqualToString:@"CONFERENCE_WILL_JOIN"]
|
|
||||||
&& [delegate respondsToSelector:@selector(conferenceWillJoin:)]) {
|
|
||||||
[delegate conferenceWillJoin:data];
|
|
||||||
|
|
||||||
} else if ([name isEqualToString:@"CONFERENCE_WILL_LEAVE"]
|
|
||||||
&& [delegate respondsToSelector:@selector(conferenceWillLeave:)]) {
|
|
||||||
[delegate conferenceWillLeave:data];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a specific event name i.e. redux action type description to a
|
||||||
|
* method name.
|
||||||
|
*
|
||||||
|
* @param eventName The event name to convert to a method name.
|
||||||
|
* @return A method name constructed from the specified {@code eventName}.
|
||||||
|
*/
|
||||||
|
- (NSString *)methodNameFromEventName:(NSString *)eventName {
|
||||||
|
NSMutableString *methodName
|
||||||
|
= [NSMutableString stringWithCapacity:eventName.length];
|
||||||
|
|
||||||
|
for (NSString *c in [eventName componentsSeparatedByString:@"_"]) {
|
||||||
|
if (c.length) {
|
||||||
|
[methodName appendString:
|
||||||
|
methodName.length ? c.capitalizedString : c.lowercaseString];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[methodName appendString:@":"];
|
||||||
|
|
||||||
|
return methodName;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
Loading…
Reference in New Issue