Add broken URI handling

Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
2023-07-26 16:10:45 +03:00
parent 083e798fdf
commit acba17462f
17 changed files with 370 additions and 91 deletions

View File

@@ -1,5 +1,6 @@
export { default as MemesList } from './memesList/memesList';
export { default as MemeEditor } from './memeEditor';
export { default as MemeFail } from './memeFail';
export { default as MemesHeader } from './memesHeader';
export { default as MemeTagSearchModal } from './memeTagSearchModal';
export { default as MemeTagSelector } from './memeTagSelector';

View File

@@ -1,12 +1,12 @@
import React from 'react';
import React, { useEffect } from 'react';
import { HelperText, TextInput } from 'react-native-paper';
import { Image } from 'react-native';
import { useSafeAreaFrame } from 'react-native-safe-area-context';
import { useImageDimensions } from '@react-native-community/hooks/lib/useImageDimensions';
import LoadingView from '../loadingView';
import { MemeTagSelector } from '.';
import { MemeFail, MemeTagSelector } from '.';
import { Tag } from '../../database';
import { StringValidationResult, validateMemeTitle } from '../../utilities';
import { useImageDimensions } from '@react-native-community/hooks';
const memeEditorStyles = {
image: {
@@ -23,12 +23,16 @@ const memeEditorStyles = {
const MemeEditor = ({
memeUri,
memeUriError,
setMemeUriError,
memeTitle,
setMemeTitle,
memeTags,
setMemeTags,
}: {
memeUri: string;
memeUriError: Error | undefined;
setMemeUriError: (error: Error | undefined) => void;
memeTitle: StringValidationResult;
setMemeTitle: (name: StringValidationResult) => void;
memeTags: Map<string, Tag>;
@@ -37,8 +41,9 @@ const MemeEditor = ({
const { width } = useSafeAreaFrame();
const { dimensions, loading, error } = useImageDimensions({ uri: memeUri });
setMemeUriError(error);
if (loading || error || !dimensions) return <LoadingView />;
if (!memeUriError && (loading || !dimensions)) return <LoadingView />;
return (
<>
@@ -53,23 +58,36 @@ const MemeEditor = ({
<HelperText type="error" visible={!memeTitle.valid}>
{memeTitle.error}
</HelperText>
<Image
source={{ uri: memeUri }}
style={[
{
width: width * 0.92,
height: Math.max(
Math.min(
((width * 0.92) / dimensions.width) * dimensions.height,
500,
{memeUriError || !dimensions ? (
<MemeFail
style={[
{
width: width * 0.92,
height: width * 0.92,
},
memeEditorStyles.image,
]}
iconSize={50}
/>
) : (
<Image
source={{ uri: memeUri }}
style={[
{
width: width * 0.92,
height: Math.max(
Math.min(
((width * 0.92) / dimensions.width) * dimensions.height,
500,
),
100,
),
100,
),
},
memeEditorStyles.image,
]}
resizeMode="contain"
/>
},
memeEditorStyles.image,
]}
resizeMode="contain"
/>
)}
<MemeTagSelector
memeTags={memeTags}
setMemeTags={setMemeTags}

View File

@@ -0,0 +1,41 @@
import React, { ComponentProps } from 'react';
import { StyleSheet, View } from 'react-native';
import { useTheme } from 'react-native-paper';
import FontAwesome5 from 'react-native-vector-icons/FontAwesome5';
import { rgbToRgba } from '../../utilities';
const memeFailStyles = StyleSheet.create({
view: {
alignItems: 'center',
justifyContent: 'center',
},
});
const MemeFail = ({
iconSize,
...props
}: {
iconSize?: number;
} & ComponentProps<typeof View>) => {
const { colors } = useTheme();
return (
<View
{...props}
style={[
props.style,
memeFailStyles.view,
{
backgroundColor: rgbToRgba(colors.error, 0.2),
},
]}>
<FontAwesome5
name="exclamation-triangle"
size={iconSize}
color={colors.error}
/>
</View>
);
};
export default MemeFail;

View File

@@ -5,6 +5,7 @@ import { useSafeAreaFrame } from 'react-native-safe-area-context';
import { useImageDimensions } from '@react-native-community/hooks';
import LoadingView from '../loadingView';
import { Meme } from '../../database';
import MemeFail from './memeFail';
const memeViewItemStyles = StyleSheet.create({
view: {
@@ -18,25 +19,42 @@ const MemeViewItem = ({ meme }: { meme: Meme }) => {
const { dimensions, loading, error } = useImageDimensions({ uri: meme.uri });
if (loading || error || !dimensions) return <LoadingView />;
if (!error && (loading || !dimensions)) {
return (
<View style={{ width, height }}>
<LoadingView />
</View>
);
}
return (
<View style={[{ width, height }, memeViewItemStyles.view]}>
<ImageZoom
source={{ uri: meme.uri }}
style={
dimensions.aspectRatio > width / (height - 128)
? {
width,
height: width / (dimensions.width / dimensions.height),
}
: {
width: (height - 128) * (dimensions.width / dimensions.height),
height: height - 128,
}
}
minScale={0.5}
/>
{error || !dimensions ? (
<MemeFail
style={{
width: Math.min(width, height - 128),
height: Math.min(width, height - 128),
}}
iconSize={50}
/>
) : (
<ImageZoom
source={{ uri: meme.uri }}
style={
dimensions.aspectRatio > width / (height - 128)
? {
width,
height: width / (dimensions.width / dimensions.height),
}
: {
width:
(height - 128) * (dimensions.width / dimensions.height),
height: height - 128,
}
}
minScale={0.5}
/>
)}
</View>
);
};

View File

@@ -5,6 +5,8 @@ import { useSafeAreaFrame } from 'react-native-safe-area-context';
import { useImageDimensions } from '@react-native-community/hooks';
import { Meme } from '../../../database';
import { RootState } from '../../../state';
import { MemeFail } from '..';
import { getFontAwesome5IconSize } from '../../../utilities';
const MemesGridItem = ({
meme,
@@ -22,19 +24,29 @@ const MemesGridItem = ({
const { dimensions, loading, error } = useImageDimensions({ uri: meme.uri });
if (loading || error || !dimensions) return <></>;
if (!error && (loading || !dimensions)) return <></>;
return (
<TouchableHighlight onPress={() => focusMeme(index)}>
<Image
source={{ uri: meme.uri }}
style={[
{
{error ? (
<MemeFail
style={{
width: (width * 0.92 - 5) / gridColumns,
height: (width * 0.92 - 5) / gridColumns,
},
]}
/>
}}
iconSize={getFontAwesome5IconSize(gridColumns)}
/>
) : (
<Image
source={{ uri: meme.uri }}
style={[
{
width: (width * 0.92 - 5) / gridColumns,
height: (width * 0.92 - 5) / gridColumns,
},
]}
/>
)}
</TouchableHighlight>
);
};

View File

@@ -4,6 +4,7 @@ import { Text, TouchableRipple } from 'react-native-paper';
import { useSafeAreaFrame } from 'react-native-safe-area-context';
import { useImageDimensions } from '@react-native-community/hooks';
import { Meme } from '../../../database';
import { MemeFail } from '..';
const memesListItemStyles = StyleSheet.create({
view: {
@@ -42,14 +43,18 @@ const MemesListItem = ({
const { dimensions, loading, error } = useImageDimensions({ uri: meme.uri });
if (loading || error || !dimensions) return <></>;
if (!error && (loading || !dimensions)) return <></>;
return (
<TouchableRipple
onPress={() => focusMeme(index)}
style={memesListItemStyles.view}>
<>
<Image source={{ uri: meme.uri }} style={memesListItemStyles.image} />
{error ? (
<MemeFail style={memesListItemStyles.image} />
) : (
<Image source={{ uri: meme.uri }} style={memesListItemStyles.image} />
)}
<View
style={[
memesListItemStyles.detailsView,

View File

@@ -5,6 +5,8 @@ import { useSafeAreaFrame } from 'react-native-safe-area-context';
import { Meme } from '../../../database';
import { RootState } from '../../../state';
import { useImageDimensions } from '@react-native-community/hooks';
import { MemeFail } from '..';
import { getFontAwesome5IconSize } from '../../../utilities';
const memeMasonryItemStyles = StyleSheet.create({
view: {
@@ -32,23 +34,36 @@ const MemesMasonryItem = ({
const { dimensions, loading, error } = useImageDimensions({ uri: meme.uri });
if (loading || error || !dimensions) return <></>;
if (!error && (loading || !dimensions)) return <></>;
return (
<TouchableHighlight
onPress={() => focusMeme(index)}
style={memeMasonryItemStyles.view}>
<Image
source={{ uri: meme.uri }}
style={[
memeMasonryItemStyles.image,
{
width: (width * 0.92) / masonryColumns - 5,
height:
((width * 0.92) / masonryColumns - 5) / dimensions.aspectRatio,
},
]}
/>
{error || !dimensions ? (
<MemeFail
style={[
memeMasonryItemStyles.image,
{
width: (width * 0.92) / masonryColumns - 5,
height: (width * 0.92) / masonryColumns - 5,
},
]}
iconSize={getFontAwesome5IconSize(masonryColumns)}
/>
) : (
<Image
source={{ uri: meme.uri }}
style={[
memeMasonryItemStyles.image,
{
width: (width * 0.92) / masonryColumns - 5,
height:
((width * 0.92) / masonryColumns - 5) / dimensions.aspectRatio,
},
]}
/>
)}
</TouchableHighlight>
);
};