feat: minimized bottom menu
This commit is contained in:
parent
0a64bf2068
commit
411bafb5a6
|
@ -14830,6 +14830,39 @@
|
||||||
"jssha": "^2.2.0"
|
"jssha": "^2.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-native-collapsible": {
|
||||||
|
"version": "1.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-native-collapsible/-/react-native-collapsible-1.5.1.tgz",
|
||||||
|
"integrity": "sha512-uQQ2s6l+7+L/pzJroisWsDsyVYVF5bQ+jGbLATNioRh/03SpEL8pcQEVKqVWswcNNR0B9GENixHaLzmuZIwpQg==",
|
||||||
|
"requires": {
|
||||||
|
"prop-types": "^15.6.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"loose-envify": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||||
|
"requires": {
|
||||||
|
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"prop-types": {
|
||||||
|
"version": "15.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
|
||||||
|
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
|
||||||
|
"requires": {
|
||||||
|
"loose-envify": "^1.4.0",
|
||||||
|
"object-assign": "^4.1.1",
|
||||||
|
"react-is": "^16.8.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"react-is": {
|
||||||
|
"version": "16.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz",
|
||||||
|
"integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-native-immersive": {
|
"react-native-immersive": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-native-immersive/-/react-native-immersive-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-immersive/-/react-native-immersive-2.0.0.tgz",
|
||||||
|
@ -14871,6 +14904,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"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": {
|
"react-native-swipeout": {
|
||||||
"version": "2.3.6",
|
"version": "2.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/react-native-swipeout/-/react-native-swipeout-2.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-swipeout/-/react-native-swipeout-2.3.6.tgz",
|
||||||
|
|
|
@ -72,12 +72,14 @@
|
||||||
"react-native-background-timer": "2.1.1",
|
"react-native-background-timer": "2.1.1",
|
||||||
"react-native-calendar-events": "github:jitsi/react-native-calendar-events#902e6e92d6bae450a6052f76ba4d02f977ffd8f2",
|
"react-native-calendar-events": "github:jitsi/react-native-calendar-events#902e6e92d6bae450a6052f76ba4d02f977ffd8f2",
|
||||||
"react-native-callstats": "3.61.0",
|
"react-native-callstats": "3.61.0",
|
||||||
|
"react-native-collapsible": "1.5.1",
|
||||||
"react-native-immersive": "2.0.0",
|
"react-native-immersive": "2.0.0",
|
||||||
"react-native-keep-awake": "4.0.0",
|
"react-native-keep-awake": "4.0.0",
|
||||||
"react-native-linear-gradient": "2.5.6",
|
"react-native-linear-gradient": "2.5.6",
|
||||||
"react-native-sound": "0.11.0",
|
"react-native-sound": "0.11.0",
|
||||||
"react-native-svg": "9.7.1",
|
"react-native-svg": "9.7.1",
|
||||||
"react-native-svg-transformer": "0.13.0",
|
"react-native-svg-transformer": "0.13.0",
|
||||||
|
"react-native-swipe-gestures": "1.0.4",
|
||||||
"react-native-swipeout": "2.3.6",
|
"react-native-swipeout": "2.3.6",
|
||||||
"react-native-watch-connectivity": "0.2.0",
|
"react-native-watch-connectivity": "0.2.0",
|
||||||
"react-native-webrtc": "1.75.2",
|
"react-native-webrtc": "1.75.2",
|
||||||
|
|
|
@ -29,7 +29,12 @@ type Props = {
|
||||||
* Handler for the cancel event, which happens when the user dismisses
|
* Handler for the cancel event, which happens when the user dismisses
|
||||||
* the sheet.
|
* the sheet.
|
||||||
*/
|
*/
|
||||||
onCancel: ?Function
|
onCancel: ?Function,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to render a bottom sheet header element, if necessary.
|
||||||
|
*/
|
||||||
|
renderHeader: ?Function
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -43,7 +48,7 @@ class BottomSheet extends PureComponent<Props> {
|
||||||
* @returns {ReactElement}
|
* @returns {ReactElement}
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
const { _styles } = this.props;
|
const { _styles, renderHeader } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SlidingView
|
<SlidingView
|
||||||
|
@ -56,19 +61,19 @@ class BottomSheet extends PureComponent<Props> {
|
||||||
<View
|
<View
|
||||||
pointerEvents = 'box-none'
|
pointerEvents = 'box-none'
|
||||||
style = { styles.sheetAreaCover } />
|
style = { styles.sheetAreaCover } />
|
||||||
<View
|
{ renderHeader && renderHeader() }
|
||||||
|
<SafeAreaView
|
||||||
style = { [
|
style = { [
|
||||||
styles.sheetItemContainer,
|
styles.sheetItemContainer,
|
||||||
_styles.sheet
|
_styles.sheet
|
||||||
] }>
|
] }>
|
||||||
<SafeAreaView>
|
<ScrollView
|
||||||
<ScrollView
|
bounces = { false }
|
||||||
bounces = { false }
|
showsVerticalScrollIndicator = { false }
|
||||||
showsVerticalScrollIndicator = { false } >
|
style = { styles.scrollView } >
|
||||||
{ this.props.children }
|
{ this.props.children }
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
</SlidingView>
|
</SlidingView>
|
||||||
);
|
);
|
||||||
|
|
|
@ -33,6 +33,10 @@ export const bottomSheetStyles = {
|
||||||
flex: 1
|
flex: 1
|
||||||
},
|
},
|
||||||
|
|
||||||
|
scrollView: {
|
||||||
|
paddingHorizontal: MD_ITEM_MARGIN_PADDING
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Style for the container of the sheet.
|
* Style for the container of the sheet.
|
||||||
*/
|
*/
|
||||||
|
@ -44,9 +48,7 @@ export const bottomSheetStyles = {
|
||||||
},
|
},
|
||||||
|
|
||||||
sheetItemContainer: {
|
sheetItemContainer: {
|
||||||
flex: -1,
|
flex: -1
|
||||||
maxHeight: '60%',
|
|
||||||
paddingHorizontal: MD_ITEM_MARGIN_PADDING
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -135,23 +137,45 @@ export const inputDialog = {
|
||||||
* {@link https://material.io/guidelines/components/bottom-sheets.html}.
|
* {@link https://material.io/guidelines/components/bottom-sheets.html}.
|
||||||
*/
|
*/
|
||||||
ColorSchemeRegistry.register('BottomSheet', {
|
ColorSchemeRegistry.register('BottomSheet', {
|
||||||
/**
|
buttons: {
|
||||||
* Style for the {@code Icon} element in a generic item of the menu.
|
/**
|
||||||
*/
|
* Style for the {@code Icon} element in a generic item of the menu.
|
||||||
iconStyle: {
|
*/
|
||||||
color: schemeColor('icon'),
|
iconStyle: {
|
||||||
fontSize: 24
|
color: schemeColor('icon'),
|
||||||
|
fontSize: 24
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Style for the label in a generic item rendered in the menu.
|
||||||
|
*/
|
||||||
|
labelStyle: {
|
||||||
|
color: schemeColor('text'),
|
||||||
|
flexShrink: 1,
|
||||||
|
fontSize: MD_FONT_SIZE,
|
||||||
|
marginLeft: 32,
|
||||||
|
opacity: 0.90
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Container style for a generic item rendered in the menu.
|
||||||
|
*/
|
||||||
|
style: {
|
||||||
|
alignItems: 'center',
|
||||||
|
flexDirection: 'row',
|
||||||
|
height: MD_ITEM_HEIGHT
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Additional style that is not directly used as a style object.
|
||||||
|
*/
|
||||||
|
underlayColor: ColorPalette.overflowMenuItemUnderlay
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
expandIcon: {
|
||||||
* Style for the label in a generic item rendered in the menu.
|
color: schemeColor('icon'),
|
||||||
*/
|
fontSize: 16,
|
||||||
labelStyle: {
|
opacity: 0.7
|
||||||
color: schemeColor('text'),
|
|
||||||
flexShrink: 1,
|
|
||||||
fontSize: MD_FONT_SIZE,
|
|
||||||
marginLeft: 32,
|
|
||||||
opacity: 0.90
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -159,21 +183,7 @@ ColorSchemeRegistry.register('BottomSheet', {
|
||||||
*/
|
*/
|
||||||
sheet: {
|
sheet: {
|
||||||
backgroundColor: schemeColor('background')
|
backgroundColor: schemeColor('background')
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Container style for a generic item rendered in the menu.
|
|
||||||
*/
|
|
||||||
style: {
|
|
||||||
alignItems: 'center',
|
|
||||||
flexDirection: 'row',
|
|
||||||
height: MD_ITEM_HEIGHT
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Additional style that is not directly used as a style object.
|
|
||||||
*/
|
|
||||||
underlayColor: ColorPalette.overflowMenuItemUnderlay
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24"><defs><path id="a" d="M0 0h24v24H0V0z"/></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"/></clipPath><path clip-path="url(#b)" d="M20 9H4v2h16V9zM4 15h16v-2H4v2z"/></svg>
|
After Width: | Height: | Size: 311 B |
|
@ -25,6 +25,7 @@ export { default as IconDeviceHeadphone } from './headset.svg';
|
||||||
export { default as IconDeviceSpeaker } from './volume.svg';
|
export { default as IconDeviceSpeaker } from './volume.svg';
|
||||||
export { default as IconDominantSpeaker } from './dominant-speaker.svg';
|
export { default as IconDominantSpeaker } from './dominant-speaker.svg';
|
||||||
export { default as IconDownload } from './download.svg';
|
export { default as IconDownload } from './download.svg';
|
||||||
|
export { default as IconDragHandle } from './drag-handle.svg';
|
||||||
export { default as IconEventNote } from './event_note.svg';
|
export { default as IconEventNote } from './event_note.svg';
|
||||||
export { default as IconExitFullScreen } from './exit-full-screen.svg';
|
export { default as IconExitFullScreen } from './exit-full-screen.svg';
|
||||||
export { default as IconFeedback } from './feedback.svg';
|
export { default as IconFeedback } from './feedback.svg';
|
||||||
|
|
|
@ -270,8 +270,8 @@ class AudioRoutePickerDialog extends Component<Props, State> {
|
||||||
<View style = { styles.deviceRow } >
|
<View style = { styles.deviceRow } >
|
||||||
<Icon
|
<Icon
|
||||||
src = { icon }
|
src = { icon }
|
||||||
style = { [ styles.deviceIcon, _bottomSheetStyles.iconStyle, selectedStyle ] } />
|
style = { [ styles.deviceIcon, _bottomSheetStyles.buttons.iconStyle, selectedStyle ] } />
|
||||||
<Text style = { [ styles.deviceText, _bottomSheetStyles.labelStyle, selectedStyle ] } >
|
<Text style = { [ styles.deviceText, _bottomSheetStyles.buttons.labelStyle, selectedStyle ] } >
|
||||||
{ text }
|
{ text }
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
|
@ -292,8 +292,8 @@ class AudioRoutePickerDialog extends Component<Props, State> {
|
||||||
<View style = { styles.deviceRow } >
|
<View style = { styles.deviceRow } >
|
||||||
<Icon
|
<Icon
|
||||||
src = { deviceInfoMap.SPEAKER.icon }
|
src = { deviceInfoMap.SPEAKER.icon }
|
||||||
style = { [ styles.deviceIcon, _bottomSheetStyles.iconStyle ] } />
|
style = { [ styles.deviceIcon, _bottomSheetStyles.buttons.iconStyle ] } />
|
||||||
<Text style = { [ styles.deviceText, _bottomSheetStyles.labelStyle ] } >
|
<Text style = { [ styles.deviceText, _bottomSheetStyles.buttons.labelStyle ] } >
|
||||||
{ t('audioDevices.none') }
|
{ t('audioDevices.none') }
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -80,7 +80,7 @@ class RemoteVideoMenu extends Component<Props> {
|
||||||
afterClick: this._onCancel,
|
afterClick: this._onCancel,
|
||||||
showLabel: true,
|
showLabel: true,
|
||||||
participantID: participant.id,
|
participantID: participant.id,
|
||||||
styles: this.props._bottomSheetStyles
|
styles: this.props._bottomSheetStyles.buttons
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import { Platform } from 'react-native';
|
import { Platform, TouchableOpacity } from 'react-native';
|
||||||
|
import Collapsible from 'react-native-collapsible';
|
||||||
|
import GestureRecognizer, { swipeDirections } from 'react-native-swipe-gestures';
|
||||||
|
|
||||||
import { ColorSchemeRegistry } from '../../../base/color-scheme';
|
import { ColorSchemeRegistry } from '../../../base/color-scheme';
|
||||||
import { BottomSheet, hideDialog, isDialogOpen } from '../../../base/dialog';
|
import { BottomSheet, hideDialog, isDialogOpen } from '../../../base/dialog';
|
||||||
|
import { IconDragHandle } from '../../../base/icons';
|
||||||
import { CHAT_ENABLED, IOS_RECORDING_ENABLED, getFeatureFlag } from '../../../base/flags';
|
import { CHAT_ENABLED, IOS_RECORDING_ENABLED, getFeatureFlag } from '../../../base/flags';
|
||||||
import { connect } from '../../../base/redux';
|
import { connect } from '../../../base/redux';
|
||||||
import { StyleType } from '../../../base/styles';
|
import { StyleType } from '../../../base/styles';
|
||||||
|
@ -16,10 +19,12 @@ import { RoomLockButton } from '../../../room-lock';
|
||||||
import { ClosedCaptionButton } from '../../../subtitles';
|
import { ClosedCaptionButton } from '../../../subtitles';
|
||||||
import { TileViewButton } from '../../../video-layout';
|
import { TileViewButton } from '../../../video-layout';
|
||||||
|
|
||||||
import AudioOnlyButton from './AudioOnlyButton';
|
|
||||||
import HelpButton from '../HelpButton';
|
import HelpButton from '../HelpButton';
|
||||||
|
|
||||||
|
import AudioOnlyButton from './AudioOnlyButton';
|
||||||
import RaiseHandButton from './RaiseHandButton';
|
import RaiseHandButton from './RaiseHandButton';
|
||||||
import ToggleCameraButton from './ToggleCameraButton';
|
import ToggleCameraButton from './ToggleCameraButton';
|
||||||
|
import styles from './styles';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the React {@code Component} props of {@link OverflowMenu}.
|
* The type of the React {@code Component} props of {@link OverflowMenu}.
|
||||||
|
@ -52,6 +57,14 @@ type Props = {
|
||||||
dispatch: Function
|
dispatch: Function
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if the 'more' button set needas to be rendered.
|
||||||
|
*/
|
||||||
|
showMore: boolean
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The exported React {@code Component}. We need it to execute
|
* The exported React {@code Component}. We need it to execute
|
||||||
* {@link hideDialog}.
|
* {@link hideDialog}.
|
||||||
|
@ -65,7 +78,7 @@ let OverflowMenu_; // eslint-disable-line prefer-const
|
||||||
* Implements a React {@code Component} with some extra actions in addition to
|
* Implements a React {@code Component} with some extra actions in addition to
|
||||||
* those in the toolbar.
|
* those in the toolbar.
|
||||||
*/
|
*/
|
||||||
class OverflowMenu extends Component<Props> {
|
class OverflowMenu extends PureComponent<Props, State> {
|
||||||
/**
|
/**
|
||||||
* Initializes a new {@code OverflowMenu} instance.
|
* Initializes a new {@code OverflowMenu} instance.
|
||||||
*
|
*
|
||||||
|
@ -74,8 +87,15 @@ class OverflowMenu extends Component<Props> {
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
showMore: false
|
||||||
|
};
|
||||||
|
|
||||||
// Bind event handlers so they are only bound once per instance.
|
// Bind event handlers so they are only bound once per instance.
|
||||||
this._onCancel = this._onCancel.bind(this);
|
this._onCancel = this._onCancel.bind(this);
|
||||||
|
this._onSwipe = this._onSwipe.bind(this);
|
||||||
|
this._onToggleMenu = this._onToggleMenu.bind(this);
|
||||||
|
this._renderMenuExpandToggle = this._renderMenuExpandToggle.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -85,37 +105,71 @@ class OverflowMenu extends Component<Props> {
|
||||||
* @returns {ReactElement}
|
* @returns {ReactElement}
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
|
const { _bottomSheetStyles } = this.props;
|
||||||
|
const { showMore } = this.state;
|
||||||
|
|
||||||
const buttonProps = {
|
const buttonProps = {
|
||||||
afterClick: this._onCancel,
|
afterClick: this._onCancel,
|
||||||
showLabel: true,
|
showLabel: true,
|
||||||
styles: this.props._bottomSheetStyles
|
styles: _bottomSheetStyles.buttons
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BottomSheet onCancel = { this._onCancel }>
|
<BottomSheet
|
||||||
|
onCancel = { this._onCancel }
|
||||||
|
renderHeader = { this._renderMenuExpandToggle }>
|
||||||
<AudioRouteButton { ...buttonProps } />
|
<AudioRouteButton { ...buttonProps } />
|
||||||
<ToggleCameraButton { ...buttonProps } />
|
<ToggleCameraButton { ...buttonProps } />
|
||||||
<AudioOnlyButton { ...buttonProps } />
|
<AudioOnlyButton { ...buttonProps } />
|
||||||
<RoomLockButton { ...buttonProps } />
|
<Collapsible collapsed = { !showMore }>
|
||||||
<ClosedCaptionButton { ...buttonProps } />
|
<RoomLockButton { ...buttonProps } />
|
||||||
{
|
<ClosedCaptionButton { ...buttonProps } />
|
||||||
this.props._recordingEnabled
|
{
|
||||||
&& <RecordButton { ...buttonProps } />
|
this.props._recordingEnabled
|
||||||
}
|
&& <RecordButton { ...buttonProps } />
|
||||||
<LiveStreamButton { ...buttonProps } />
|
}
|
||||||
<TileViewButton { ...buttonProps } />
|
<LiveStreamButton { ...buttonProps } />
|
||||||
<InviteButton { ...buttonProps } />
|
<TileViewButton { ...buttonProps } />
|
||||||
{
|
<InviteButton { ...buttonProps } />
|
||||||
this.props._chatEnabled
|
{
|
||||||
&& <InfoDialogButton { ...buttonProps } />
|
this.props._chatEnabled
|
||||||
}
|
&& <InfoDialogButton { ...buttonProps } />
|
||||||
<RaiseHandButton { ...buttonProps } />
|
}
|
||||||
<SharedDocumentButton { ...buttonProps } />
|
<RaiseHandButton { ...buttonProps } />
|
||||||
<HelpButton { ...buttonProps } />
|
<SharedDocumentButton { ...buttonProps } />
|
||||||
|
<HelpButton { ...buttonProps } />
|
||||||
|
</Collapsible>
|
||||||
</BottomSheet>
|
</BottomSheet>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_renderMenuExpandToggle: () => React$Element<any>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to render the menu toggle in the bottom sheet header area.
|
||||||
|
*
|
||||||
|
* @returns {React$Element}
|
||||||
|
*/
|
||||||
|
_renderMenuExpandToggle() {
|
||||||
|
return (
|
||||||
|
<GestureRecognizer
|
||||||
|
config = {{
|
||||||
|
velocityThreshold: 0.1,
|
||||||
|
directionalOffsetThreshold: 30
|
||||||
|
}}
|
||||||
|
onSwipe = { this._onSwipe }
|
||||||
|
style = { [
|
||||||
|
this.props._bottomSheetStyles.sheet,
|
||||||
|
styles.expandMenuContainer
|
||||||
|
] }>
|
||||||
|
<TouchableOpacity onPress = { this._onToggleMenu }>
|
||||||
|
{ /* $FlowFixMeProps */ }
|
||||||
|
<IconDragHandle style = { this.props._bottomSheetStyles.expandIcon } />
|
||||||
|
</TouchableOpacity>
|
||||||
|
</GestureRecognizer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
_onCancel: () => boolean;
|
_onCancel: () => boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -133,6 +187,50 @@ class OverflowMenu extends Component<Props> {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onSwipe: (string) => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback to be invoked when a swipe gesture is detected on the menu.
|
||||||
|
*
|
||||||
|
* @param {string} gestureName - The name of the swipe gesture.
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
_onSwipe(gestureName) {
|
||||||
|
const { showMore } = this.state;
|
||||||
|
|
||||||
|
switch (gestureName) {
|
||||||
|
case swipeDirections.SWIPE_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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_onToggleMenu: () => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback to be invoked when the expand menu button is pressed.
|
||||||
|
*
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
_onToggleMenu() {
|
||||||
|
this.setState({
|
||||||
|
showMore: !this.state.showMore
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -55,6 +55,11 @@ const whiteToolbarButtonIcon = {
|
||||||
*/
|
*/
|
||||||
const styles = {
|
const styles = {
|
||||||
|
|
||||||
|
expandMenuContainer: {
|
||||||
|
alignItems: 'center',
|
||||||
|
flexDirection: 'column'
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The style of the toolbar.
|
* The style of the toolbar.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue