diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 8130afc8..a672c0e2 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -3,13 +3,8 @@ package="chat.rocket.reactnative"> - - + diff --git a/android/app/src/main/java/chat/rocket/reactnative/generated/BasePackageList.java b/android/app/src/main/java/chat/rocket/reactnative/generated/BasePackageList.java index 80778aba..724f732a 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/generated/BasePackageList.java +++ b/android/app/src/main/java/chat/rocket/reactnative/generated/BasePackageList.java @@ -15,6 +15,7 @@ public class BasePackageList { new expo.modules.keepawake.KeepAwakePackage(), new expo.modules.localauthentication.LocalAuthenticationPackage(), new expo.modules.permissions.PermissionsPackage(), + new expo.modules.videothumbnails.VideoThumbnailsPackage(), new expo.modules.webbrowser.WebBrowserPackage() ); } diff --git a/app/constants/colors.js b/app/constants/colors.js index 22025481..7b9d5676 100644 --- a/app/constants/colors.js +++ b/app/constants/colors.js @@ -53,7 +53,9 @@ export const themes = { passcodePrimary: '#2F343D', passcodeSecondary: '#6C727A', passcodeDotEmpty: '#CBCED1', - passcodeDotFull: '#6C727A' + passcodeDotFull: '#6C727A', + previewBackground: '#1F2329', + previewTintColor: '#ffffff' }, dark: { backgroundColor: '#030b1b', @@ -95,7 +97,9 @@ export const themes = { passcodePrimary: '#FFFFFF', passcodeSecondary: '#CBCED1', passcodeDotEmpty: '#CBCED1', - passcodeDotFull: '#6C727A' + passcodeDotFull: '#6C727A', + previewBackground: '#030b1b', + previewTintColor: '#ffffff' }, black: { backgroundColor: '#000000', @@ -137,6 +141,8 @@ export const themes = { passcodePrimary: '#FFFFFF', passcodeSecondary: '#CBCED1', passcodeDotEmpty: '#CBCED1', - passcodeDotFull: '#6C727A' + passcodeDotFull: '#6C727A', + previewBackground: '#000000', + previewTintColor: '#ffffff' } }; diff --git a/app/containers/ActionSheet/Provider.js b/app/containers/ActionSheet/Provider.js index 3dfcd0dc..3708e674 100644 --- a/app/containers/ActionSheet/Provider.js +++ b/app/containers/ActionSheet/Provider.js @@ -1,5 +1,4 @@ -import React, { useRef, useContext } from 'react'; -import hoistNonReactStatics from 'hoist-non-react-statics'; +import React, { useRef, useContext, forwardRef } from 'react'; import PropTypes from 'prop-types'; import ActionSheet from './ActionSheet'; @@ -14,15 +13,11 @@ export const useActionSheet = () => useContext(context); const { Provider, Consumer } = context; -export const withActionSheet = (Component) => { - const ConnectedActionSheet = props => ( - - {contexts => } - - ); - hoistNonReactStatics(ConnectedActionSheet, Component); - return ConnectedActionSheet; -}; +export const withActionSheet = Component => forwardRef((props, ref) => ( + + {contexts => } + +)); export const ActionSheetProvider = React.memo(({ children }) => { const ref = useRef(); diff --git a/app/containers/Header/index.js b/app/containers/Header/index.js index 2b61c79d..249b832e 100644 --- a/app/containers/Header/index.js +++ b/app/containers/Header/index.js @@ -4,11 +4,22 @@ import { SafeAreaView } from 'react-native-safe-area-context'; import { View, StyleSheet } from 'react-native'; import { themes } from '../../constants/colors'; import { themedHeader } from '../../utils/navigation'; -import { isIOS } from '../../utils/deviceInfo'; +import { isIOS, isTablet } from '../../utils/deviceInfo'; // Get from https://github.com/react-navigation/react-navigation/blob/master/packages/stack/src/views/Header/HeaderSegment.tsx#L69 export const headerHeight = isIOS ? 44 : 56; +export const getHeaderHeight = (isLandscape) => { + if (isIOS) { + if (isLandscape && !isTablet) { + return 32; + } else { + return 44; + } + } + return 56; +}; + const styles = StyleSheet.create({ container: { height: headerHeight, diff --git a/app/containers/HeaderButton.js b/app/containers/HeaderButton.js index 6782ec99..3ac44d45 100644 --- a/app/containers/HeaderButton.js +++ b/app/containers/HeaderButton.js @@ -36,9 +36,11 @@ export const DrawerButton = React.memo(({ navigation, testID, ...otherProps }) = )); -export const CloseModalButton = React.memo(({ navigation, testID, onPress = () => navigation.pop() }) => ( +export const CloseModalButton = React.memo(({ + navigation, testID, onPress = () => navigation.pop(), ...props +}) => ( - + )); @@ -57,9 +59,9 @@ export const MoreButton = React.memo(({ onPress, testID }) => ( )); -export const SaveButton = React.memo(({ onPress, testID }) => ( +export const SaveButton = React.memo(({ onPress, testID, ...props }) => ( - + )); diff --git a/app/containers/MessageBox/LeftButtons.ios.js b/app/containers/MessageBox/LeftButtons.ios.js index e00d1b8d..29c03846 100644 --- a/app/containers/MessageBox/LeftButtons.ios.js +++ b/app/containers/MessageBox/LeftButtons.ios.js @@ -1,22 +1,28 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { View } from 'react-native'; import { CancelEditingButton, ActionsButton } from './buttons'; +import styles from './styles'; const LeftButtons = React.memo(({ - theme, showMessageBoxActions, editing, editCancel + theme, showMessageBoxActions, editing, editCancel, isActionsEnabled }) => { if (editing) { return ; } - return ; + if (isActionsEnabled) { + return ; + } + return ; }); LeftButtons.propTypes = { theme: PropTypes.string, showMessageBoxActions: PropTypes.func.isRequired, editing: PropTypes.bool, - editCancel: PropTypes.func.isRequired + editCancel: PropTypes.func.isRequired, + isActionsEnabled: PropTypes.bool }; export default LeftButtons; diff --git a/app/containers/MessageBox/Recording.js b/app/containers/MessageBox/Recording.js index 7611cdc9..d71724fb 100644 --- a/app/containers/MessageBox/Recording.js +++ b/app/containers/MessageBox/Recording.js @@ -6,7 +6,7 @@ import { import { AudioRecorder, AudioUtils } from 'react-native-audio'; import { BorderlessButton } from 'react-native-gesture-handler'; import { activateKeepAwake, deactivateKeepAwake } from 'expo-keep-awake'; -import RNFetchBlob from 'rn-fetch-blob'; +import * as FileSystem from 'expo-file-system'; import styles from './styles'; import I18n from '../../i18n'; @@ -113,7 +113,7 @@ export default class extends React.PureComponent { this.recording = false; const filePath = await AudioRecorder.stopRecording(); if (isAndroid) { - const data = await RNFetchBlob.fs.stat(decodeURIComponent(filePath)); + const data = await FileSystem.getInfoAsync(decodeURIComponent(filePath), { size: true }); this.finishRecording(true, filePath, data.size); } } catch (err) { diff --git a/app/containers/MessageBox/RightButtons.android.js b/app/containers/MessageBox/RightButtons.android.js index b351dde7..88d6e728 100644 --- a/app/containers/MessageBox/RightButtons.android.js +++ b/app/containers/MessageBox/RightButtons.android.js @@ -1,23 +1,25 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { View } from 'react-native'; import { SendButton, AudioButton, ActionsButton } from './buttons'; +import styles from './styles'; const RightButtons = React.memo(({ - theme, showSend, submit, recordAudioMessage, recordAudioMessageEnabled, showMessageBoxActions + theme, showSend, submit, recordAudioMessage, recordAudioMessageEnabled, showMessageBoxActions, isActionsEnabled }) => { if (showSend) { return ; } - if (recordAudioMessageEnabled) { + if (recordAudioMessageEnabled || isActionsEnabled) { return ( <> - - + {recordAudioMessageEnabled ? : null} + {isActionsEnabled ? : null} ); } - return ; + return ; }); RightButtons.propTypes = { @@ -26,7 +28,8 @@ RightButtons.propTypes = { submit: PropTypes.func.isRequired, recordAudioMessage: PropTypes.func.isRequired, recordAudioMessageEnabled: PropTypes.bool, - showMessageBoxActions: PropTypes.func.isRequired + showMessageBoxActions: PropTypes.func.isRequired, + isActionsEnabled: PropTypes.bool }; export default RightButtons; diff --git a/app/containers/MessageBox/UploadModal.js b/app/containers/MessageBox/UploadModal.js deleted file mode 100644 index dd248e6a..00000000 --- a/app/containers/MessageBox/UploadModal.js +++ /dev/null @@ -1,249 +0,0 @@ -import React, { Component } from 'react'; -import { - View, Text, StyleSheet, Image, ScrollView, TouchableHighlight -} from 'react-native'; -import PropTypes from 'prop-types'; -import Modal from 'react-native-modal'; -import equal from 'deep-equal'; - -import TextInput from '../TextInput'; -import Button from '../Button'; -import I18n from '../../i18n'; -import sharedStyles from '../../views/Styles'; -import { isIOS } from '../../utils/deviceInfo'; -import { themes } from '../../constants/colors'; -import { CustomIcon } from '../../lib/Icons'; -import { withTheme } from '../../theme'; -import { withDimensions } from '../../dimensions'; - -const styles = StyleSheet.create({ - modal: { - width: '100%', - alignItems: 'center', - margin: 0 - }, - titleContainer: { - flexDirection: 'row', - paddingHorizontal: 16, - paddingTop: 16 - }, - title: { - fontSize: 14, - ...sharedStyles.textBold - }, - container: { - height: 430, - flexDirection: 'column' - }, - scrollView: { - flex: 1, - padding: 16 - }, - image: { - height: 150, - flex: 1, - marginBottom: 16, - resizeMode: 'contain' - }, - bigPreview: { - height: 250 - }, - buttonContainer: { - flexDirection: 'row', - justifyContent: 'space-between', - padding: 16 - }, - button: { - marginBottom: 0 - }, - androidButton: { - paddingHorizontal: 15, - justifyContent: 'center', - height: 48, - borderRadius: 2 - }, - androidButtonText: { - fontSize: 18, - textAlign: 'center' - }, - fileIcon: { - margin: 20, - flex: 1, - textAlign: 'center' - }, - video: { - flex: 1, - borderRadius: 4, - height: 150, - marginBottom: 6, - alignItems: 'center', - justifyContent: 'center' - } - -}); - -class UploadModal extends Component { - static propTypes = { - isVisible: PropTypes.bool, - file: PropTypes.object, - close: PropTypes.func, - submit: PropTypes.func, - width: PropTypes.number, - theme: PropTypes.string, - isMasterDetail: PropTypes.bool - } - - state = { - name: '', - description: '', - file: {} - }; - - static getDerivedStateFromProps(props, state) { - if (!equal(props.file, state.file) && props.file && props.file.path) { - return { - file: props.file, - name: props.file.filename || 'Filename', - description: '' - }; - } - return null; - } - - shouldComponentUpdate(nextProps, nextState) { - const { name, description, file } = this.state; - const { width, isVisible, theme } = this.props; - - if (nextState.name !== name) { - return true; - } - if (nextProps.theme !== theme) { - return true; - } - if (nextState.description !== description) { - return true; - } - if (nextProps.isVisible !== isVisible) { - return true; - } - if (nextProps.width !== width) { - return true; - } - if (!equal(nextState.file, file)) { - return true; - } - return false; - } - - submit = () => { - const { file, submit } = this.props; - const { name, description } = this.state; - submit({ ...file, name, description }); - } - - renderButtons = () => { - const { close, theme } = this.props; - if (isIOS) { - return ( - -