Chore: Migrate ShareView to Typescript (#3481)
This commit is contained in:
parent
8e55032118
commit
2b3542d4ae
|
@ -1,5 +1,3 @@
|
|||
// @ts-ignore
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
export * from './ImageViewer';
|
||||
export * from './types';
|
||||
export * from './ImageComponent';
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
import I18n from '../../i18n';
|
||||
|
@ -35,7 +34,13 @@ const styles = StyleSheet.create({
|
|||
}
|
||||
});
|
||||
|
||||
const Header = React.memo(({ room, thread, theme }) => {
|
||||
interface IHeader {
|
||||
room: { prid?: string; t?: string };
|
||||
thread: { id?: string };
|
||||
theme: string;
|
||||
}
|
||||
|
||||
const Header = React.memo(({ room, thread, theme }: IHeader) => {
|
||||
let type;
|
||||
if (thread?.id) {
|
||||
type = 'thread';
|
||||
|
@ -88,10 +93,5 @@ const Header = React.memo(({ room, thread, theme }) => {
|
|||
</View>
|
||||
);
|
||||
});
|
||||
Header.propTypes = {
|
||||
room: PropTypes.object,
|
||||
thread: PropTypes.object,
|
||||
theme: PropTypes.string
|
||||
};
|
||||
|
||||
export default withTheme(Header);
|
|
@ -1,5 +1,4 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Video } from 'expo-av';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { ScrollView, StyleSheet, Text } from 'react-native';
|
||||
|
@ -15,6 +14,7 @@ import I18n from '../../i18n';
|
|||
import { isAndroid } from '../../utils/deviceInfo';
|
||||
import { allowPreview } from './utils';
|
||||
import { THUMBS_HEIGHT } from './constants';
|
||||
import { IAttachment, IUseDimensions } from './interfaces';
|
||||
|
||||
const MESSAGEBOX_HEIGHT = 56;
|
||||
|
||||
|
@ -35,7 +35,17 @@ const styles = StyleSheet.create({
|
|||
}
|
||||
});
|
||||
|
||||
const IconPreview = React.memo(({ iconName, title, description, theme, width, height, danger }) => (
|
||||
interface IIconPreview {
|
||||
iconName: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
theme: string;
|
||||
width: number;
|
||||
height: number;
|
||||
danger?: boolean;
|
||||
}
|
||||
|
||||
const IconPreview = React.memo(({ iconName, title, description, theme, width, height, danger }: IIconPreview) => (
|
||||
<ScrollView
|
||||
style={{ backgroundColor: themes[theme].auxiliaryBackground }}
|
||||
contentContainerStyle={[styles.fileContainer, { width, height }]}>
|
||||
|
@ -45,9 +55,16 @@ const IconPreview = React.memo(({ iconName, title, description, theme, width, he
|
|||
</ScrollView>
|
||||
));
|
||||
|
||||
const Preview = React.memo(({ item, theme, isShareExtension, length }) => {
|
||||
interface IPreview {
|
||||
item: IAttachment;
|
||||
theme: string;
|
||||
isShareExtension: boolean;
|
||||
length: number;
|
||||
}
|
||||
|
||||
const Preview = React.memo(({ item, theme, isShareExtension, length }: IPreview) => {
|
||||
const type = item?.mime;
|
||||
const { width, height } = useDimensions();
|
||||
const { width, height } = useDimensions() as IUseDimensions;
|
||||
const { isLandscape } = useOrientation();
|
||||
const insets = useSafeAreaInsets();
|
||||
const headerHeight = getHeaderHeight(isLandscape);
|
||||
|
@ -111,21 +128,5 @@ const Preview = React.memo(({ item, theme, isShareExtension, length }) => {
|
|||
/>
|
||||
);
|
||||
});
|
||||
Preview.propTypes = {
|
||||
item: PropTypes.object,
|
||||
theme: PropTypes.string,
|
||||
isShareExtension: PropTypes.bool,
|
||||
length: PropTypes.number
|
||||
};
|
||||
|
||||
IconPreview.propTypes = {
|
||||
iconName: PropTypes.string,
|
||||
title: PropTypes.string,
|
||||
description: PropTypes.string,
|
||||
theme: PropTypes.string,
|
||||
width: PropTypes.number,
|
||||
height: PropTypes.number,
|
||||
danger: PropTypes.bool
|
||||
};
|
||||
|
||||
export default Preview;
|
|
@ -1,5 +1,4 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FlatList, Image, StyleSheet, View } from 'react-native';
|
||||
import { RectButton, TouchableNativeFeedback, TouchableOpacity } from 'react-native-gesture-handler';
|
||||
|
||||
|
@ -9,6 +8,7 @@ import { CustomIcon } from '../../lib/Icons';
|
|||
import { isIOS } from '../../utils/deviceInfo';
|
||||
import { THUMBS_HEIGHT } from './constants';
|
||||
import { allowPreview } from './utils';
|
||||
import { IAttachment } from './interfaces';
|
||||
|
||||
const THUMB_SIZE = 64;
|
||||
|
||||
|
@ -60,22 +60,34 @@ const styles = StyleSheet.create({
|
|||
}
|
||||
});
|
||||
|
||||
const ThumbButton = isIOS ? TouchableOpacity : TouchableNativeFeedback;
|
||||
interface IThumbContent {
|
||||
item: IAttachment;
|
||||
theme: string;
|
||||
isShareExtension: boolean;
|
||||
}
|
||||
|
||||
const ThumbContent = React.memo(({ item, theme, isShareExtension }) => {
|
||||
interface IThumb extends IThumbContent {
|
||||
onPress(item: IAttachment): void;
|
||||
onRemove(item: IAttachment): void;
|
||||
}
|
||||
|
||||
interface IThumbs extends Omit<IThumb, 'item'> {
|
||||
attachments: IAttachment[];
|
||||
}
|
||||
|
||||
const ThumbContent = React.memo(({ item, theme, isShareExtension }: IThumbContent) => {
|
||||
const type = item?.mime;
|
||||
|
||||
if (type?.match(/image/)) {
|
||||
// Disallow preview of images too big in order to prevent memory issues on iOS share extension
|
||||
if (allowPreview(isShareExtension, item?.size)) {
|
||||
return <Image source={{ uri: item.path }} style={[styles.thumb, { borderColor: themes[theme].borderColor }]} />;
|
||||
} else {
|
||||
return (
|
||||
<View style={[styles.thumb, { borderColor: themes[theme].borderColor }]}>
|
||||
<CustomIcon name='image' size={30} color={themes[theme].tintColor} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<View style={[styles.thumb, { borderColor: themes[theme].borderColor }]}>
|
||||
<CustomIcon name='image' size={30} color={themes[theme].tintColor} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
if (type?.match(/video/)) {
|
||||
|
@ -85,22 +97,23 @@ const ThumbContent = React.memo(({ item, theme, isShareExtension }) => {
|
|||
<CustomIcon name='camera' size={30} color={themes[theme].tintColor} />
|
||||
</View>
|
||||
);
|
||||
} else {
|
||||
const { uri } = item;
|
||||
return (
|
||||
<>
|
||||
<Image source={{ uri }} style={styles.thumb} />
|
||||
<CustomIcon name='camera-filled' size={20} color={themes[theme].buttonText} style={styles.videoThumbIcon} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
const { uri } = item;
|
||||
return (
|
||||
<>
|
||||
<Image source={{ uri }} style={styles.thumb} />
|
||||
<CustomIcon name='camera-filled' size={20} color={themes[theme].buttonText} style={styles.videoThumbIcon} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// Multiple files upload of files different than image/video is not implemented, so there's no thumb
|
||||
return null;
|
||||
});
|
||||
|
||||
const Thumb = ({ item, theme, isShareExtension, onPress, onRemove }) => (
|
||||
const ThumbButton: typeof React.Component = isIOS ? TouchableOpacity : TouchableNativeFeedback;
|
||||
|
||||
const Thumb = ({ item, theme, isShareExtension, onPress, onRemove }: IThumb) => (
|
||||
<ThumbButton style={styles.item} onPress={() => onPress(item)} activeOpacity={0.7}>
|
||||
<>
|
||||
<ThumbContent item={item} theme={theme} isShareExtension={isShareExtension} />
|
||||
|
@ -121,7 +134,7 @@ const Thumb = ({ item, theme, isShareExtension, onPress, onRemove }) => (
|
|||
</ThumbButton>
|
||||
);
|
||||
|
||||
const Thumbs = React.memo(({ attachments, theme, isShareExtension, onPress, onRemove }) => {
|
||||
const Thumbs = React.memo(({ attachments, theme, isShareExtension, onPress, onRemove }: IThumbs) => {
|
||||
if (attachments?.length > 1) {
|
||||
return (
|
||||
<FlatList
|
||||
|
@ -143,24 +156,5 @@ const Thumbs = React.memo(({ attachments, theme, isShareExtension, onPress, onRe
|
|||
}
|
||||
return null;
|
||||
});
|
||||
Thumbs.propTypes = {
|
||||
attachments: PropTypes.array,
|
||||
theme: PropTypes.string,
|
||||
isShareExtension: PropTypes.bool,
|
||||
onPress: PropTypes.func,
|
||||
onRemove: PropTypes.func
|
||||
};
|
||||
Thumb.propTypes = {
|
||||
item: PropTypes.object,
|
||||
theme: PropTypes.string,
|
||||
isShareExtension: PropTypes.bool,
|
||||
onPress: PropTypes.func,
|
||||
onRemove: PropTypes.func
|
||||
};
|
||||
ThumbContent.propTypes = {
|
||||
item: PropTypes.object,
|
||||
theme: PropTypes.string,
|
||||
isShareExtension: PropTypes.bool
|
||||
};
|
||||
|
||||
export default Thumbs;
|
|
@ -1,5 +1,6 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack';
|
||||
import { RouteProp } from '@react-navigation/native';
|
||||
import { NativeModules, Text, View } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import ShareExtension from 'rn-extensions-share';
|
||||
|
@ -24,9 +25,61 @@ import Thumbs from './Thumbs';
|
|||
import Preview from './Preview';
|
||||
import Header from './Header';
|
||||
import styles from './styles';
|
||||
import { IAttachment, IServer } from './interfaces';
|
||||
|
||||
class ShareView extends Component {
|
||||
constructor(props) {
|
||||
interface IShareViewState {
|
||||
selected: IAttachment;
|
||||
loading: boolean;
|
||||
readOnly: boolean;
|
||||
attachments: IAttachment[];
|
||||
text: string;
|
||||
// TODO: Refactor when migrate room
|
||||
room: any;
|
||||
thread: any;
|
||||
maxFileSize: number;
|
||||
mediaAllowList: number;
|
||||
}
|
||||
|
||||
interface IShareViewProps {
|
||||
// TODO: Refactor after react-navigation
|
||||
navigation: StackNavigationProp<any, 'ShareView'>;
|
||||
route: RouteProp<
|
||||
{
|
||||
ShareView: {
|
||||
attachments: IAttachment[];
|
||||
isShareView?: boolean;
|
||||
isShareExtension: boolean;
|
||||
serverInfo: IServer;
|
||||
text: string;
|
||||
room: any;
|
||||
thread: any; // change
|
||||
};
|
||||
},
|
||||
'ShareView'
|
||||
>;
|
||||
theme: string;
|
||||
user: {
|
||||
id: string;
|
||||
username: string;
|
||||
token: string;
|
||||
};
|
||||
server: string;
|
||||
FileUpload_MediaTypeWhiteList?: number;
|
||||
FileUpload_MaxFileSize?: number;
|
||||
}
|
||||
|
||||
interface IMessageBoxShareView {
|
||||
text: string;
|
||||
forceUpdate(): void;
|
||||
}
|
||||
|
||||
class ShareView extends Component<IShareViewProps, IShareViewState> {
|
||||
private messagebox: React.RefObject<IMessageBoxShareView>;
|
||||
private files: any[];
|
||||
private isShareExtension: boolean;
|
||||
private serverInfo: any;
|
||||
|
||||
constructor(props: IShareViewProps) {
|
||||
super(props);
|
||||
this.messagebox = React.createRef();
|
||||
this.files = props.route.params?.attachments ?? [];
|
||||
|
@ -34,7 +87,7 @@ class ShareView extends Component {
|
|||
this.serverInfo = props.route.params?.serverInfo ?? {};
|
||||
|
||||
this.state = {
|
||||
selected: {},
|
||||
selected: {} as IAttachment,
|
||||
loading: false,
|
||||
readOnly: false,
|
||||
attachments: [],
|
||||
|
@ -61,7 +114,7 @@ class ShareView extends Component {
|
|||
const { room, thread, readOnly, attachments } = this.state;
|
||||
const { navigation, theme } = this.props;
|
||||
|
||||
const options = {
|
||||
const options: StackNavigationOptions = {
|
||||
headerTitle: () => <Header room={room} thread={thread} />,
|
||||
headerTitleAlign: 'left',
|
||||
headerTintColor: themes[theme].previewTintColor
|
||||
|
@ -69,9 +122,7 @@ class ShareView extends Component {
|
|||
|
||||
// if is share extension show default back button
|
||||
if (!this.isShareExtension) {
|
||||
options.headerLeft = () => (
|
||||
<HeaderButton.CloseModal navigation={navigation} buttonStyle={{ color: themes[theme].previewTintColor }} />
|
||||
);
|
||||
options.headerLeft = () => <HeaderButton.CloseModal navigation={navigation} />;
|
||||
}
|
||||
|
||||
if (!attachments.length && !readOnly) {
|
||||
|
@ -203,10 +254,10 @@ class ShareView extends Component {
|
|||
}
|
||||
};
|
||||
|
||||
selectFile = item => {
|
||||
selectFile = (item: IAttachment) => {
|
||||
const { attachments, selected } = this.state;
|
||||
if (attachments.length > 0) {
|
||||
const { text } = this.messagebox.current;
|
||||
const text = this.messagebox.current?.text;
|
||||
const newAttachments = attachments.map(att => {
|
||||
if (att.path === selected.path) {
|
||||
att.description = text;
|
||||
|
@ -217,7 +268,7 @@ class ShareView extends Component {
|
|||
}
|
||||
};
|
||||
|
||||
removeFile = item => {
|
||||
removeFile = (item: IAttachment) => {
|
||||
const { selected, attachments } = this.state;
|
||||
let newSelected;
|
||||
if (item.path === selected.path) {
|
||||
|
@ -235,7 +286,7 @@ class ShareView extends Component {
|
|||
});
|
||||
};
|
||||
|
||||
onChangeText = text => {
|
||||
onChangeText = (text: string) => {
|
||||
this.setState({ text });
|
||||
};
|
||||
|
||||
|
@ -318,21 +369,7 @@ class ShareView extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
ShareView.propTypes = {
|
||||
navigation: PropTypes.object,
|
||||
route: PropTypes.object,
|
||||
theme: PropTypes.string,
|
||||
user: PropTypes.shape({
|
||||
id: PropTypes.string.isRequired,
|
||||
username: PropTypes.string.isRequired,
|
||||
token: PropTypes.string.isRequired
|
||||
}),
|
||||
server: PropTypes.string,
|
||||
FileUpload_MediaTypeWhiteList: PropTypes.string,
|
||||
FileUpload_MaxFileSize: PropTypes.string
|
||||
};
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
const mapStateToProps = (state: any) => ({
|
||||
user: getUserSelector(state),
|
||||
server: state.share.server.server || state.server.server,
|
||||
FileUpload_MediaTypeWhiteList: state.settings.FileUpload_MediaTypeWhiteList,
|
|
@ -0,0 +1,33 @@
|
|||
export interface IAttachment {
|
||||
filename: string;
|
||||
description?: string;
|
||||
size: number;
|
||||
mime?: string;
|
||||
path: string;
|
||||
canUpload: boolean;
|
||||
error?: any;
|
||||
uri: string;
|
||||
}
|
||||
|
||||
export interface IUseDimensions {
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
// TODO: move this to specific folder
|
||||
export interface IServer {
|
||||
name: string;
|
||||
iconURL: string;
|
||||
useRealName: boolean;
|
||||
FileUpload_MediaTypeWhiteList: string;
|
||||
FileUpload_MaxFileSize: number;
|
||||
roomsUpdatedAt: Date;
|
||||
version: string;
|
||||
lastLocalAuthenticatedSession: Date;
|
||||
autoLock: boolean;
|
||||
autoLockTime: number | null;
|
||||
biometry: boolean | null;
|
||||
uniqueID: string;
|
||||
enterpriseModules: string;
|
||||
E2E_Enable: boolean;
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
import { isAndroid } from '../../utils/deviceInfo';
|
||||
|
||||
// Limit preview to 3MB on iOS share extension
|
||||
export const allowPreview = (isShareExtension, size) => isAndroid || !isShareExtension || size < 3000000;
|
|
@ -0,0 +1,5 @@
|
|||
import { isAndroid } from '../../utils/deviceInfo';
|
||||
|
||||
// Limit preview to 3MB on iOS share extension
|
||||
export const allowPreview = (isShareExtension: boolean, size: number): boolean =>
|
||||
isAndroid || !isShareExtension || size < 3000000;
|
Loading…
Reference in New Issue