Compare commits
9 Commits
android-sd
...
android-19
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e368c76c70 | ios: set version to 19.5.1 | ||
|
|
1502cee6cc |
android: unmute microphone on the ConnectionService handler
This shouldn't be needed, as ConnectionService should take care of it, but we suspect some devices don't do it since we got reports of people not hearing users, and the problem went away when CS was disabled. |
||
|
|
932b34c24c | android: set version to 19.5.1 | ||
|
|
0c8589779d |
deps: react-native-webrtc@1.75.3
Fixes datachannels not working. |
||
|
|
30108b3c06 |
android: handle ConnectionService failures more resiliently
Fallback to the non-ConnectionService case for any error. Also, handle errors when registering the phone account; Pixel C devices throw UnsupportedException. |
||
|
|
3cb5d4ae60 |
android: handle exception when unregistering account
Pixel C devices have been seen crashing here, oh well. |
||
|
|
41af049193 |
android,ios: add store screenshots
While Fastlane recommends automagic screenshots, we cannot really do that since we require a specific setup for a video call and so on. |
||
|
|
dede23f5b4 |
ios: fix SDK build after dropping iOS 10
Since we only support iOS 11, 32 bit architectures must not be built. |
||
|
|
c669075265 | feat: add swipe handler to entire bottom sheet |
6
.gitignore
vendored
|
|
@@ -61,14 +61,8 @@ buck-out/
|
|||
|
||||
# fastlane
|
||||
#
|
||||
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
|
||||
# screenshots whenever they are needed.
|
||||
# For more information about the recommended setup visit:
|
||||
# https://docs.fastlane.tools/best-practices/source-control/
|
||||
|
||||
*/fastlane/report.xml
|
||||
*/fastlane/Preview.html
|
||||
*/fastlane/screenshots
|
||||
|
||||
# Build artifacts
|
||||
*.jsbundle
|
||||
|
|
|
|||
BIN
android/fastlane/screenshots/Feature-Graphic-1024x500-1-1.png
Normal file
|
After Width: | Height: | Size: 512 KiB |
BIN
android/fastlane/screenshots/Feature-Graphic-1024x500-1.png
Normal file
|
After Width: | Height: | Size: 396 KiB |
BIN
android/fastlane/screenshots/Feature-Graphic-1024x500-2.png
Normal file
|
After Width: | Height: | Size: 265 KiB |
BIN
android/fastlane/screenshots/Feature-Graphic-1024x500-3.png
Normal file
|
After Width: | Height: | Size: 279 KiB |
BIN
android/fastlane/screenshots/GroupCall.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
android/fastlane/screenshots/GroupCall_framed.png
Normal file
|
After Width: | Height: | Size: 2.8 MiB |
BIN
android/fastlane/screenshots/More Menu.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
android/fastlane/screenshots/More Menu_framed.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
android/fastlane/screenshots/Nexus 9 Body.png
Normal file
|
After Width: | Height: | Size: 6.0 MiB |
BIN
android/fastlane/screenshots/Nexus-9-Landscape.png
Normal file
|
After Width: | Height: | Size: 4.0 MiB |
BIN
android/fastlane/screenshots/Nexus-9-Portrait.png
Normal file
|
After Width: | Height: | Size: 6.0 MiB |
BIN
android/fastlane/screenshots/Video-Call-1-1024x768.png
Normal file
|
After Width: | Height: | Size: 948 KiB |
BIN
android/fastlane/screenshots/Video-Call-1-1280x720.png
Normal file
|
After Width: | Height: | Size: 983 KiB |
BIN
android/fastlane/screenshots/Video-Call-2-1024x768.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
android/fastlane/screenshots/Video-Call-2-1280x720.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
android/fastlane/screenshots/WelcomePage-Calendar.png
Normal file
|
After Width: | Height: | Size: 2.7 MiB |
BIN
android/fastlane/screenshots/WelcomePage-Calendar_framed.png
Normal file
|
After Width: | Height: | Size: 2.1 MiB |
BIN
android/fastlane/screenshots/WelcomeScreen-1024x768.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
android/fastlane/screenshots/WelcomeScreen-1280x720.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
|
|
@@ -20,5 +20,5 @@
|
|||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
|
||||
appVersion=19.5.0
|
||||
appVersion=19.5.1
|
||||
sdkVersion=2.5.0
|
||||
|
|
|
|||
|
|
@@ -17,6 +17,7 @@
|
|||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Build;
|
||||
import android.telecom.CallAudioState;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
|
@@ -38,6 +39,11 @@ class AudioDeviceHandlerConnectionService implements
|
|||
|
||||
private final static String TAG = AudioDeviceHandlerConnectionService.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* {@link AudioManager} instance used to interact with the Android audio subsystem.
|
||||
*/
|
||||
private AudioManager audioManager;
|
||||
|
||||
/**
|
||||
* Reference to the main {@code AudioModeModule}.
|
||||
*/
|
||||
|
|
@@ -134,6 +140,8 @@ class AudioDeviceHandlerConnectionService implements
|
|||
JitsiMeetLogger.i("Using " + TAG + " as the audio device handler");
|
||||
|
||||
module = audioModeModule;
|
||||
audioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
|
||||
|
||||
RNConnectionService rcs = ReactInstanceManagerHolder.getNativeModule(RNConnectionService.class);
|
||||
if (rcs != null) {
|
||||
rcs.setCallAudioStateListener(this);
|
||||
|
|
@@ -160,6 +168,16 @@ class AudioDeviceHandlerConnectionService implements
|
|||
|
||||
@Override
|
||||
public boolean setMode(int mode) {
|
||||
if (mode != AudioModeModule.DEFAULT) {
|
||||
// This shouldn't be needed when using ConnectionService, but some devices have been
|
||||
// observed not doing it.
|
||||
try {
|
||||
audioManager.setMicrophoneMute(false);
|
||||
} catch (Throwable tr) {
|
||||
JitsiMeetLogger.w(tr, TAG + " Failed to unmute the microphone");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@@ -89,9 +89,17 @@ class RNConnectionService extends ReactContextBaseJavaModule {
|
|||
ReactApplicationContext ctx = getReactApplicationContext();
|
||||
|
||||
Uri address = Uri.fromParts(PhoneAccount.SCHEME_SIP, handle, null);
|
||||
PhoneAccountHandle accountHandle
|
||||
= ConnectionService.registerPhoneAccount(
|
||||
getReactApplicationContext(), address, callUUID);
|
||||
PhoneAccountHandle accountHandle;
|
||||
|
||||
try {
|
||||
accountHandle
|
||||
= ConnectionService.registerPhoneAccount(getReactApplicationContext(), address, callUUID);
|
||||
} catch (Throwable tr) {
|
||||
JitsiMeetLogger.e(tr, TAG + " error in startCall");
|
||||
|
||||
promise.reject(tr);
|
||||
return;
|
||||
}
|
||||
|
||||
Bundle extras = new Bundle();
|
||||
extras.putParcelable(
|
||||
|
|
@@ -110,17 +118,18 @@ class RNConnectionService extends ReactContextBaseJavaModule {
|
|||
try {
|
||||
tm = (TelecomManager) ctx.getSystemService(Context.TELECOM_SERVICE);
|
||||
tm.placeCall(address, extras);
|
||||
} catch (Exception e) {
|
||||
JitsiMeetLogger.e(e, TAG + " error in startCall");
|
||||
} catch (Throwable tr) {
|
||||
JitsiMeetLogger.e(tr, TAG + " error in startCall");
|
||||
if (tm != null) {
|
||||
tm.unregisterPhoneAccount(accountHandle);
|
||||
try {
|
||||
tm.unregisterPhoneAccount(accountHandle);
|
||||
} catch (Throwable tr1) {
|
||||
// UnsupportedOperationException: System does not support feature android.software.connectionservice
|
||||
// was observed here. Ignore.
|
||||
}
|
||||
}
|
||||
ConnectionService.unregisterStartCallPromise(callUUID);
|
||||
if (e instanceof SecurityException) {
|
||||
promise.reject("SECURITY_ERROR", "Required permissions not granted.");
|
||||
} else {
|
||||
promise.reject(e);
|
||||
}
|
||||
promise.reject(tr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@@ -274,7 +274,7 @@ PODS:
|
|||
- React
|
||||
- react-native-netinfo (4.1.5):
|
||||
- React
|
||||
- react-native-webrtc (1.75.2):
|
||||
- react-native-webrtc (1.75.3):
|
||||
- React
|
||||
- react-native-webview (7.4.1):
|
||||
- React
|
||||
|
|
@@ -534,7 +534,7 @@ SPEC CHECKSUMS:
|
|||
react-native-calendar-events: 2fe35a9294af05de0ed819d3a1b5dac048d2c010
|
||||
react-native-keep-awake: eba3137546b10003361b37c761f6c429b59814ae
|
||||
react-native-netinfo: 8d8db463bcc5db66a8ac5c48a7d86beb3b92f61a
|
||||
react-native-webrtc: f6783727706d8bec5fb302b76eda60c33dfe3191
|
||||
react-native-webrtc: 86d841823e66d68cc1f86712db1c2956056bf0c2
|
||||
react-native-webview: 4dbc1d2a4a6b9c5e9e723c62651917aa2b5e579e
|
||||
React-RCTActionSheet: 94671eef55b01a93be735605822ef712d5ea208e
|
||||
React-RCTAnimation: 524ae33e73de9c0fe6501a7a4bda8e01d26499d9
|
||||
|
|
|
|||
|
|
@@ -17,7 +17,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>19.5.0</string>
|
||||
<string>19.5.1</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
|
|
|
|||
|
|
@@ -17,7 +17,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>19.5.0</string>
|
||||
<string>19.5.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
|
|
|
|||
|
|
@@ -17,7 +17,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>19.5.0</string>
|
||||
<string>19.5.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>CLKComplicationPrincipalClass</key>
|
||||
|
|
|
|||
BIN
ios/fastlane/screenshots/Feature-Graphic-1024x500-1-1.png
Normal file
|
After Width: | Height: | Size: 512 KiB |
BIN
ios/fastlane/screenshots/Feature-Graphic-1024x500-1.png
Normal file
|
After Width: | Height: | Size: 396 KiB |
BIN
ios/fastlane/screenshots/Feature-Graphic-1024x500-2.png
Normal file
|
After Width: | Height: | Size: 265 KiB |
BIN
ios/fastlane/screenshots/Feature-Graphic-1024x500-3.png
Normal file
|
After Width: | Height: | Size: 279 KiB |
BIN
ios/fastlane/screenshots/GroupCallIphone8Plus.png
Normal file
|
After Width: | Height: | Size: 3.3 MiB |
BIN
ios/fastlane/screenshots/GroupCallIphone8PlusDevice.png
Normal file
|
After Width: | Height: | Size: 5.4 MiB |
BIN
ios/fastlane/screenshots/MoreMenu8Plus.png
Normal file
|
After Width: | Height: | Size: 779 KiB |
BIN
ios/fastlane/screenshots/MoreMenu8PlusDevice.png
Normal file
|
After Width: | Height: | Size: 888 KiB |
BIN
ios/fastlane/screenshots/WelcomePage8Plus.png
Normal file
|
After Width: | Height: | Size: 2.2 MiB |
BIN
ios/fastlane/screenshots/WelcomePage8PlusDevice.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
ios/fastlane/screenshots/iPad-9.7-inch-In-Call-1.png
Normal file
|
After Width: | Height: | Size: 3.3 MiB |
BIN
ios/fastlane/screenshots/iPad-9.7-inch-In-Call-2.png
Normal file
|
After Width: | Height: | Size: 5.1 MiB |
BIN
ios/fastlane/screenshots/iPad-9.7-inch-Welcome.png
Normal file
|
After Width: | Height: | Size: 5.0 MiB |
BIN
ios/fastlane/screenshots/iPadCall.png
Normal file
|
After Width: | Height: | Size: 11 MiB |
BIN
ios/fastlane/screenshots/iPadCallDevice.png
Normal file
|
After Width: | Height: | Size: 6.4 MiB |
BIN
ios/fastlane/screenshots/iPhone 8 Plus Calendar.png
Normal file
|
After Width: | Height: | Size: 2.7 MiB |
BIN
ios/fastlane/screenshots/iPhone 8 Plus Group Call.png
Normal file
|
After Width: | Height: | Size: 4.0 MiB |
BIN
ios/fastlane/screenshots/iPhone 8 Plus More.png
Normal file
|
After Width: | Height: | Size: 2.2 MiB |
BIN
ios/fastlane/screenshots/iPhone-5.5-inch-In-Call-2.png
Normal file
|
After Width: | Height: | Size: 4.5 MiB |
BIN
ios/fastlane/screenshots/iPhone-5.5-inch-In-Call.png
Normal file
|
After Width: | Height: | Size: 3.0 MiB |
BIN
ios/fastlane/screenshots/iPhone-5.5-inch-Welcome.png
Normal file
|
After Width: | Height: | Size: 4.4 MiB |
|
|
@@ -77,7 +77,7 @@
|
|||
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
|
||||
<ActionContent
|
||||
title = "Run Script"
|
||||
scriptText = "exec > /tmp/${PROJECT_NAME}_archive.log 2>&1 UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal if [ "true" == ${ALREADYINVOKED:-false} ] then echo "RECURSION: Detected, stopping" else export ALREADYINVOKED="true" # make sure the output directory exists mkdir -p "${UNIVERSAL_OUTPUTFOLDER}" echo "Building for iPhoneSimulator" xcodebuild -workspace "${WORKSPACE_PATH}" -scheme "${TARGET_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 8' ONLY_ACTIVE_ARCH=NO ARCHS='i386 x86_64' BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" ENABLE_BITCODE=YES OTHER_CFLAGS="-fembed-bitcode" BITCODE_GENERATION_MODE=bitcode build # Step 1. Copy the framework structure (from iphoneos build) to the universal folder echo "Copying to output folder" cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FULL_PRODUCT_NAME}" "${UNIVERSAL_OUTPUTFOLDER}/" # Step 2. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule/." if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule" fi # Step 3. Create universal binary file using lipo and place the combined executable in the copied framework directory echo "Combining executables" lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${EXECUTABLE_PATH}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${EXECUTABLE_PATH}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${EXECUTABLE_PATH}" # Step 4. Create universal binaries for embedded frameworks #for SUB_FRAMEWORK in $( ls "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Frameworks" ); do #BINARY_NAME="${SUB_FRAMEWORK%.*}" #lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${SUB_FRAMEWORK}/${BINARY_NAME}" "${ARCHIVE_PRODUCTS_PATH}${INSTALL_PATH}/${TARGET_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}" #done # Step 5. Convenience step to copy the framework to the project's directory echo "Copying to project dir" yes | cp -Rf "${UNIVERSAL_OUTPUTFOLDER}/${FULL_PRODUCT_NAME}" "${PROJECT_DIR}" fi ">
|
||||
scriptText = "exec > /tmp/${PROJECT_NAME}_archive.log 2>&1 UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal if [ "true" == ${ALREADYINVOKED:-false} ] then echo "RECURSION: Detected, stopping" else export ALREADYINVOKED="true" # make sure the output directory exists mkdir -p "${UNIVERSAL_OUTPUTFOLDER}" echo "Building for iPhoneSimulator" xcodebuild -workspace "${WORKSPACE_PATH}" -scheme "${TARGET_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 8' ONLY_ACTIVE_ARCH=NO ARCHS='x86_64' BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" ENABLE_BITCODE=YES OTHER_CFLAGS="-fembed-bitcode" BITCODE_GENERATION_MODE=bitcode build # Step 1. Copy the framework structure (from iphoneos build) to the universal folder echo "Copying to output folder" cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FULL_PRODUCT_NAME}" "${UNIVERSAL_OUTPUTFOLDER}/" # Step 2. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule/." if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule" fi # Step 3. Create universal binary file using lipo and place the combined executable in the copied framework directory echo "Combining executables" lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${EXECUTABLE_PATH}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${EXECUTABLE_PATH}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${EXECUTABLE_PATH}" fi # Step 4. Convenience step to copy the framework to the project&apos;s directory echo "Copying to project dir&quot" yes | cp -Rf ${UNIVERSAL_OUTPUTFOLDER}/${FULL_PRODUCT_NAME} ${PROJECT_DIR} ">
|
||||
<EnvironmentBuildable>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
|
|
|
|||
11
package-lock.json
generated
|
|
@@ -14872,11 +14872,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"react-native-swipe-gestures": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/react-native-swipe-gestures/-/react-native-swipe-gestures-1.0.4.tgz",
|
||||
"integrity": "sha512-C/vz0KPHNyqHk3uF4Cz/jzd/0N8z34ZgsjAZUh/RsXPH2FtJJf3Fw73pQDWJSoCMtvVadlztb8xQ+/aEQrll7w=="
|
||||
},
|
||||
"react-native-swipeout": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/react-native-swipeout/-/react-native-swipeout-2.3.6.tgz",
|
||||
|
|
@@ -14893,9 +14888,9 @@
|
|||
"integrity": "sha512-l3Quzbb+qa4in2U5RSt/lT0/pHrIpEChT1NnqrVAAXNrjkXjVOsxduaaEDdDhTzNJQEm/PcAcoyrFmgvGOohxw=="
|
||||
},
|
||||
"react-native-webrtc": {
|
||||
"version": "1.75.2",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-1.75.2.tgz",
|
||||
"integrity": "sha512-mdEukmHNhiyVIiwdooxk4kVXWG83OOENFV9YIkC7dtGU/sOdL81vDzynqd6Af9YbGMeOr0xdpFuEGsc1OFnKZg==",
|
||||
"version": "1.75.3",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-1.75.3.tgz",
|
||||
"integrity": "sha512-WIQu7jpH4osb4IMdjkpr62UYwt9kHIU4vWvvTHMxSqkGZwMGpTyFW/E+Y0T7If1azAvhq3GBuQjI3npxIXGbSQ==",
|
||||
"requires": {
|
||||
"base64-js": "^1.1.2",
|
||||
"event-target-shim": "^1.0.5",
|
||||
|
|
|
|||
|
|
@@ -78,10 +78,9 @@
|
|||
"react-native-sound": "0.11.0",
|
||||
"react-native-svg": "9.7.1",
|
||||
"react-native-svg-transformer": "0.13.0",
|
||||
"react-native-swipe-gestures": "1.0.4",
|
||||
"react-native-swipeout": "2.3.6",
|
||||
"react-native-watch-connectivity": "0.2.0",
|
||||
"react-native-webrtc": "1.75.2",
|
||||
"react-native-webrtc": "1.75.3",
|
||||
"react-native-webview": "7.4.1",
|
||||
"react-redux": "7.1.0",
|
||||
"react-textarea-autosize": "7.1.0",
|
||||
|
|
|
|||
|
|
@@ -1,7 +1,7 @@
|
|||
// @flow
|
||||
|
||||
import React, { PureComponent, type Node } from 'react';
|
||||
import { SafeAreaView, ScrollView, View } from 'react-native';
|
||||
import { PanResponder, SafeAreaView, ScrollView, View } from 'react-native';
|
||||
|
||||
import { ColorSchemeRegistry } from '../../../color-scheme';
|
||||
import { SlidingView } from '../../../react';
|
||||
|
|
@@ -10,6 +10,16 @@ import { StyleType } from '../../../styles';
|
|||
|
||||
import { bottomSheetStyles as styles } from './styles';
|
||||
|
||||
/**
|
||||
* Minimal distance that needs to be moved by the finger to consider it a swipe.
|
||||
*/
|
||||
const GESTURE_DISTANCE_THRESHOLD = 5;
|
||||
|
||||
/**
|
||||
* The minimal speed needed to be achieved by the finger to consider it as a swipe.
|
||||
*/
|
||||
const GESTURE_SPEED_THRESHOLD = 0.2;
|
||||
|
||||
/**
|
||||
* The type of {@code BottomSheet}'s React {@code Component} prop types.
|
||||
*/
|
||||
|
|
@@ -31,6 +41,11 @@ type Props = {
|
|||
*/
|
||||
onCancel: ?Function,
|
||||
|
||||
/**
|
||||
* Callback to be attached to the custom swipe event of the BottomSheet.
|
||||
*/
|
||||
onSwipe?: Function,
|
||||
|
||||
/**
|
||||
* Function to render a bottom sheet header element, if necessary.
|
||||
*/
|
||||
|
|
@@ -41,6 +56,23 @@ type Props = {
|
|||
* A component emulating Android's BottomSheet.
|
||||
*/
|
||||
class BottomSheet extends PureComponent<Props> {
|
||||
panResponder: Object;
|
||||
|
||||
/**
|
||||
* Instantiates a new component.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.panResponder = PanResponder.create({
|
||||
onStartShouldSetPanResponder: this._onShouldSetResponder.bind(this),
|
||||
onMoveShouldSetPanResponder: this._onShouldSetResponder.bind(this),
|
||||
onPanResponderRelease: this._onGestureEnd.bind(this)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
|
|
@@ -66,7 +98,8 @@ class BottomSheet extends PureComponent<Props> {
|
|||
style = { [
|
||||
styles.sheetItemContainer,
|
||||
_styles.sheet
|
||||
] }>
|
||||
] }
|
||||
{ ...this.panResponder.panHandlers }>
|
||||
<ScrollView
|
||||
bounces = { false }
|
||||
showsVerticalScrollIndicator = { false }
|
||||
|
|
@@ -78,6 +111,48 @@ class BottomSheet extends PureComponent<Props> {
|
|||
</SlidingView>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to handle a gesture end event.
|
||||
*
|
||||
* @param {Object} evt - The native gesture event.
|
||||
* @param {Object} gestureState - The gesture state.
|
||||
* @returns {void}
|
||||
*/
|
||||
_onGestureEnd(evt, gestureState) {
|
||||
const verticalSwipe = Math.abs(gestureState.vy) > Math.abs(gestureState.vx)
|
||||
&& Math.abs(gestureState.vy) > GESTURE_SPEED_THRESHOLD;
|
||||
|
||||
if (verticalSwipe) {
|
||||
const direction = gestureState.vy > 0 ? 'down' : 'up';
|
||||
const { onCancel, onSwipe } = this.props;
|
||||
let isSwipeHandled = false;
|
||||
|
||||
if (onSwipe) {
|
||||
isSwipeHandled = onSwipe(direction);
|
||||
}
|
||||
|
||||
if (direction === 'down' && !isSwipeHandled) {
|
||||
// Swipe down is a special gesture that can be used to close the
|
||||
// BottomSheet, so if the swipe is not handled by the parent
|
||||
// component, we consider it as a request to close.
|
||||
onCancel && onCancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the pan responder should activate, false otherwise.
|
||||
*
|
||||
* @param {Object} evt - The native gesture event.
|
||||
* @param {Object} gestureState - The gesture state.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_onShouldSetResponder({ nativeEvent }, gestureState) {
|
||||
return nativeEvent.touches.length === 1
|
||||
&& Math.abs(gestureState.dx) > GESTURE_DISTANCE_THRESHOLD
|
||||
&& Math.abs(gestureState.dy) > GESTURE_DISTANCE_THRESHOLD;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@@ -194,16 +194,14 @@ function _conferenceJoined({ getState }, next, action) {
|
|||
_updateCallIntegrationMuted(action.conference, getState());
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
// Currently this error code is emitted only by Android.
|
||||
.catch(() => {
|
||||
// Currently errors here are only emitted by Android.
|
||||
//
|
||||
if (error.code === 'CONNECTION_NOT_FOUND_ERROR') {
|
||||
// Some Samsung devices will fail to fully engage ConnectionService if no SIM card
|
||||
// was ever installed on the device. We could check for it, but it would require
|
||||
// the CALL_PHONE permission, which is not something we want to do, so fallback to
|
||||
// not using ConnectionService.
|
||||
_handleConnectionServiceFailure(getState());
|
||||
}
|
||||
// Some Samsung devices will fail to fully engage ConnectionService if no SIM card
|
||||
// was ever installed on the device. We could check for it, but it would require
|
||||
// the CALL_PHONE permission, which is not something we want to do, so fallback to
|
||||
// not using ConnectionService.
|
||||
_handleConnectionServiceFailure(getState());
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@@ -304,9 +302,11 @@ function _conferenceWillJoin({ dispatch, getState }, next, action) {
|
|||
{ text: 'OK' }
|
||||
],
|
||||
{ cancelable: false });
|
||||
} else if (error.code === 'SECURITY_ERROR') {
|
||||
} else {
|
||||
// Some devices fail because the CALL_PHONE permission is not granted, which is
|
||||
// nonsense, because it's not needed for self-managed connections.
|
||||
// Some other devices fail because ConnectionService is not supported.
|
||||
// Be that as it may, fallback to non-ConnectionService audio device handling.
|
||||
|
||||
_handleConnectionServiceFailure(state);
|
||||
}
|
||||
|
|
|
|||
|
|
@@ -1,9 +1,8 @@
|
|||
// @flow
|
||||
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Platform, TouchableOpacity } from 'react-native';
|
||||
import { Platform, TouchableOpacity, View } from 'react-native';
|
||||
import Collapsible from 'react-native-collapsible';
|
||||
import GestureRecognizer, { swipeDirections } from 'react-native-swipe-gestures';
|
||||
|
||||
import { ColorSchemeRegistry } from '../../../base/color-scheme';
|
||||
import { BottomSheet, hideDialog, isDialogOpen } from '../../../base/dialog';
|
||||
|
|
@@ -59,6 +58,11 @@ type Props = {
|
|||
|
||||
type State = {
|
||||
|
||||
/**
|
||||
* True if the bottom scheet is scrolled to the top.
|
||||
*/
|
||||
scrolledToTop: boolean,
|
||||
|
||||
/**
|
||||
* True if the 'more' button set needas to be rendered.
|
||||
*/
|
||||
|
|
@@ -88,6 +92,7 @@ class OverflowMenu extends PureComponent<Props, State> {
|
|||
super(props);
|
||||
|
||||
this.state = {
|
||||
scrolledToTop: true,
|
||||
showMore: false
|
||||
};
|
||||
|
||||
|
|
@@ -117,6 +122,7 @@ class OverflowMenu extends PureComponent<Props, State> {
|
|||
return (
|
||||
<BottomSheet
|
||||
onCancel = { this._onCancel }
|
||||
onSwipe = { this._onSwipe }
|
||||
renderHeader = { this._renderMenuExpandToggle }>
|
||||
<AudioRouteButton { ...buttonProps } />
|
||||
<ToggleCameraButton { ...buttonProps } />
|
||||
|
|
@@ -152,12 +158,7 @@ class OverflowMenu extends PureComponent<Props, State> {
|
|||
*/
|
||||
_renderMenuExpandToggle() {
|
||||
return (
|
||||
<GestureRecognizer
|
||||
config = {{
|
||||
velocityThreshold: 0.1,
|
||||
directionalOffsetThreshold: 30
|
||||
}}
|
||||
onSwipe = { this._onSwipe }
|
||||
<View
|
||||
style = { [
|
||||
this.props._bottomSheetStyles.sheet,
|
||||
styles.expandMenuContainer
|
||||
|
|
@@ -166,7 +167,7 @@ class OverflowMenu extends PureComponent<Props, State> {
|
|||
{ /* $FlowFixMeProps */ }
|
||||
<IconDragHandle style = { this.props._bottomSheetStyles.expandIcon } />
|
||||
</TouchableOpacity>
|
||||
</GestureRecognizer>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@@ -188,34 +189,31 @@ class OverflowMenu extends PureComponent<Props, State> {
|
|||
return false;
|
||||
}
|
||||
|
||||
_onSwipe: (string) => void;
|
||||
_onSwipe: string => void;
|
||||
|
||||
/**
|
||||
* Callback to be invoked when a swipe gesture is detected on the menu.
|
||||
* Callback to be invoked when swipe gesture is detected on the menu. Returns true
|
||||
* if the swipe gesture is handled by the menu, false otherwise.
|
||||
*
|
||||
* @param {string} gestureName - The name of the swipe gesture.
|
||||
* @returns {void}
|
||||
* @param {string} direction - Direction of 'up' or 'down'.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_onSwipe(gestureName) {
|
||||
_onSwipe(direction) {
|
||||
const { showMore } = this.state;
|
||||
|
||||
switch (gestureName) {
|
||||
case swipeDirections.SWIPE_UP:
|
||||
switch (direction) {
|
||||
case 'up':
|
||||
!showMore && this.setState({
|
||||
showMore: true
|
||||
});
|
||||
break;
|
||||
case swipeDirections.SWIPE_DOWN:
|
||||
if (showMore) {
|
||||
// If the menu is expanded, we collapse it.
|
||||
this.setState({
|
||||
showMore: false
|
||||
});
|
||||
} else {
|
||||
// If the menu is not expanded, we close the menu
|
||||
this._onCancel();
|
||||
}
|
||||
break;
|
||||
|
||||
return !showMore;
|
||||
case 'down':
|
||||
showMore && this.setState({
|
||||
showMore: false
|
||||
});
|
||||
|
||||
return showMore;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@@ -60,6 +60,11 @@ const styles = {
|
|||
flexDirection: 'column'
|
||||
},
|
||||
|
||||
sheetGestureRecognizer: {
|
||||
alignItems: 'stretch',
|
||||
flexDirection: 'column'
|
||||
},
|
||||
|
||||
/**
|
||||
* The style of the toolbar.
|
||||
*/
|
||||
|
|
|
|||