This repository has been archived on 2025-07-31. You can view files and clone it, but cannot push or open issues or pull requests.
Files
terminally-online/src/screens/editors/meme/memeEditor.tsx
Nikolaos Karaolidis d2054b028a Reorganize files
Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
2023-08-01 14:53:10 +03:00

160 lines
3.8 KiB
TypeScript

import React, { useMemo } from 'react';
import { HelperText, Text, TextInput, useTheme } from 'react-native-paper';
import { Image, LayoutAnimation } from 'react-native';
import { useSafeAreaFrame } from 'react-native-safe-area-context';
import Video from 'react-native-video';
import { LoadingView, MemeFail } from '../../../components';
import {
getFilenameFromUri,
getMemeTypeFromMimeType,
validateMemeTitle,
} from '../../../utilities';
import { StagingMeme } from '../../../types';
import { useMemeDimensions } from '../../../hooks';
import { MEME_TYPE } from '../../../database';
import MemeTagSelector from './memeTagSelector/memeTagSelector';
const memeEditorStyles = {
media: {
marginBottom: 15,
borderRadius: 5,
},
uri: {
marginBottom: 15,
marginHorizontal: 5,
},
memeTagSelector: {
marginBottom: 10,
},
description: {
marginBottom: 10,
},
};
const MemeEditor = ({
uri,
mimeType,
loading,
setLoading,
error,
setError,
staging,
setStaging,
}: {
uri?: string;
mimeType?: string;
loading: boolean;
setLoading: (loading: boolean) => void;
error: Error | undefined;
setError: (error: Error | undefined) => void;
staging?: StagingMeme;
setStaging: (staging: StagingMeme) => void;
}) => {
const { width } = useSafeAreaFrame();
const { colors } = useTheme();
const { dimensions } = useMemeDimensions(
uri,
mimeType,
useMemo(
() => () => {
setLoading(false);
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
},
[setLoading],
),
useMemo(() => (errorIn: Error) => setError(errorIn), [setError]),
);
const mediaComponent = useMemo(() => {
if (!mimeType || !dimensions) return <></>;
const dimensionStyles = {
width: width * 0.92,
height: Math.max(
Math.min((width * 0.92) / dimensions.aspectRatio, 500),
100,
),
};
const memeType = getMemeTypeFromMimeType(mimeType);
if (!memeType) return <></>;
switch (memeType) {
case MEME_TYPE.IMAGE:
case MEME_TYPE.GIF: {
return (
<Image
source={{ uri }}
style={[memeEditorStyles.media, dimensionStyles]}
resizeMode="contain"
/>
);
}
case MEME_TYPE.VIDEO: {
return (
<Video
source={{ uri }}
style={[memeEditorStyles.media, dimensionStyles]}
resizeMode="contain"
controls
/>
);
}
default: {
return <></>;
}
}
}, [dimensions, mimeType, uri, width]);
if (!uri || !mimeType || !staging) return <LoadingView />;
return (
<>
<TextInput
mode="outlined"
label="Title"
value={staging.title.raw}
onChangeText={title =>
setStaging({ ...staging, title: validateMemeTitle(title) })
}
error={!staging.title.valid}
selectTextOnFocus
/>
<HelperText type="error" visible={!staging.title.valid}>
{staging.title.error}
</HelperText>
{error ? (
<MemeFail
style={[
{
width: width * 0.92,
height: width * 0.92,
},
memeEditorStyles.media,
]}
iconSize={50}
/>
) : // eslint-disable-next-line unicorn/no-nested-ternary
loading || !dimensions ? (
<></>
) : (
mediaComponent
)}
<Text
variant="bodySmall"
style={[memeEditorStyles.uri, { color: colors.onSurfaceDisabled }]}
numberOfLines={1}>
{getFilenameFromUri(uri)}
</Text>
<MemeTagSelector
memeTags={staging.tags}
setMemeTags={tags => setStaging({ ...staging, tags })}
style={memeEditorStyles.memeTagSelector}
/>
</>
);
};
export default MemeEditor;