Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
665931f7b9 | |||
d2054b028a |
16
package-lock.json
generated
16
package-lock.json
generated
@@ -12,6 +12,7 @@
|
|||||||
"@bankify/redux-persist-realm": "^0.1.3",
|
"@bankify/redux-persist-realm": "^0.1.3",
|
||||||
"@react-native-clipboard/clipboard": "^1.11.2",
|
"@react-native-clipboard/clipboard": "^1.11.2",
|
||||||
"@react-native-community/hooks": "^3.0.0",
|
"@react-native-community/hooks": "^3.0.0",
|
||||||
|
"@react-native-ml-kit/text-recognition": "^1.2.1",
|
||||||
"@react-navigation/bottom-tabs": "^6.5.8",
|
"@react-navigation/bottom-tabs": "^6.5.8",
|
||||||
"@react-navigation/native": "^6.1.7",
|
"@react-navigation/native": "^6.1.7",
|
||||||
"@react-navigation/native-stack": "^6.9.13",
|
"@react-navigation/native-stack": "^6.9.13",
|
||||||
@@ -4113,6 +4114,15 @@
|
|||||||
"react-native": ">=0.65"
|
"react-native": ">=0.65"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@react-native-ml-kit/text-recognition": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-native-ml-kit/text-recognition/-/text-recognition-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-pJrnf8AvihzYdPAZoZZEeKbOUOMjdsetDjHlleXOoVcoPo6qjfh6Il/Q0ey3boIQuO3HglvNjcMPGEPThF3sPA==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8.1",
|
||||||
|
"react-native": ">=0.60.0-rc.0 <1.0.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@react-native/assets-registry": {
|
"node_modules/@react-native/assets-registry": {
|
||||||
"version": "0.72.0",
|
"version": "0.72.0",
|
||||||
"resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.72.0.tgz",
|
"resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.72.0.tgz",
|
||||||
@@ -18799,6 +18809,12 @@
|
|||||||
"integrity": "sha512-g2OyxXHfwIytXUJitBR6Z/ISoOfp0WKx5FOv+NqJ/CrWjRDcTw6zXE5I1C9axfuh30kJqzWchVfCDrkzZYTxqg==",
|
"integrity": "sha512-g2OyxXHfwIytXUJitBR6Z/ISoOfp0WKx5FOv+NqJ/CrWjRDcTw6zXE5I1C9axfuh30kJqzWchVfCDrkzZYTxqg==",
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
|
"@react-native-ml-kit/text-recognition": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-native-ml-kit/text-recognition/-/text-recognition-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-pJrnf8AvihzYdPAZoZZEeKbOUOMjdsetDjHlleXOoVcoPo6qjfh6Il/Q0ey3boIQuO3HglvNjcMPGEPThF3sPA==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"@react-native/assets-registry": {
|
"@react-native/assets-registry": {
|
||||||
"version": "0.72.0",
|
"version": "0.72.0",
|
||||||
"resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.72.0.tgz",
|
"resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.72.0.tgz",
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
"@bankify/redux-persist-realm": "^0.1.3",
|
"@bankify/redux-persist-realm": "^0.1.3",
|
||||||
"@react-native-clipboard/clipboard": "^1.11.2",
|
"@react-native-clipboard/clipboard": "^1.11.2",
|
||||||
"@react-native-community/hooks": "^3.0.0",
|
"@react-native-community/hooks": "^3.0.0",
|
||||||
|
"@react-native-ml-kit/text-recognition": "^1.2.1",
|
||||||
"@react-navigation/bottom-tabs": "^6.5.8",
|
"@react-navigation/bottom-tabs": "^6.5.8",
|
||||||
"@react-navigation/native": "^6.1.7",
|
"@react-navigation/native": "^6.1.7",
|
||||||
"@react-navigation/native-stack": "^6.9.13",
|
"@react-navigation/native-stack": "^6.9.13",
|
||||||
|
@@ -1,15 +1,8 @@
|
|||||||
export {
|
|
||||||
MemesList,
|
|
||||||
MemeEditor,
|
|
||||||
MemeFail,
|
|
||||||
MemesHeader,
|
|
||||||
MemeTagSelector,
|
|
||||||
MemeViewItem,
|
|
||||||
} from './memes';
|
|
||||||
export { TagChip, TagEditor, TagPreview, TagRow, TagsHeader } from './tags';
|
|
||||||
export { default as AnimatedImage } from './animatedImage';
|
export { default as AnimatedImage } from './animatedImage';
|
||||||
export { default as FloatingActionButton } from './floatingActionButton';
|
export { default as FloatingActionButton } from './floatingActionButton';
|
||||||
export { default as HideableBottomNavigationBar } from './hideableBottomNavigationBar';
|
export { default as HideableBottomNavigationBar } from './hideableBottomNavigationBar';
|
||||||
export { default as HideableHeader } from './hideableHeader';
|
export { default as HideableHeader } from './hideableHeader';
|
||||||
export { default as LoadingView } from './loadingView';
|
export { default as LoadingView } from './loadingView';
|
||||||
export { default as storageLocationChangeDialog } from './storageLocationChangeDialog';
|
export { default as MemeFail } from './memeFail';
|
||||||
|
export { default as TagChip } from './tagChip';
|
||||||
|
export { default as TextOverlay } from './textOverlay';
|
||||||
|
@@ -2,7 +2,7 @@ import React, { ComponentProps } from 'react';
|
|||||||
import { StyleSheet, View } from 'react-native';
|
import { StyleSheet, View } from 'react-native';
|
||||||
import { useTheme } from 'react-native-paper';
|
import { useTheme } from 'react-native-paper';
|
||||||
import FontAwesome5 from 'react-native-vector-icons/FontAwesome5';
|
import FontAwesome5 from 'react-native-vector-icons/FontAwesome5';
|
||||||
import { rgbToRgba } from '../../utilities';
|
import { rgbToRgba } from '../utilities';
|
||||||
|
|
||||||
const memeFailStyles = StyleSheet.create({
|
const memeFailStyles = StyleSheet.create({
|
||||||
view: {
|
view: {
|
@@ -1,6 +0,0 @@
|
|||||||
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 MemeTagSelector } from './memeTagSelector/memeTagSelector';
|
|
||||||
export { default as MemeViewItem } from './memeViewItem';
|
|
@@ -1,9 +1,9 @@
|
|||||||
import React, { ComponentProps, useMemo } from 'react';
|
import React, { ComponentProps, useMemo } from 'react';
|
||||||
import { getContrastColor } from '../../utilities';
|
|
||||||
import { Chip, useTheme } from 'react-native-paper';
|
import { Chip, useTheme } from 'react-native-paper';
|
||||||
import { Tag } from '../../database';
|
|
||||||
import FontAwesome5 from 'react-native-vector-icons/FontAwesome5';
|
import FontAwesome5 from 'react-native-vector-icons/FontAwesome5';
|
||||||
import { StyleSheet } from 'react-native';
|
import { StyleSheet } from 'react-native';
|
||||||
|
import { getContrastColor } from '../utilities';
|
||||||
|
import { Tag } from '../database';
|
||||||
|
|
||||||
const tagChipStyles = StyleSheet.create({
|
const tagChipStyles = StyleSheet.create({
|
||||||
chip: {
|
chip: {
|
@@ -1,5 +0,0 @@
|
|||||||
export { default as TagChip } from './tagChip';
|
|
||||||
export { default as TagEditor } from './tagEditor';
|
|
||||||
export { default as TagPreview } from './tagPreview';
|
|
||||||
export { default as TagRow } from './tagRow';
|
|
||||||
export { default as TagsHeader } from './tagsHeader';
|
|
64
src/components/textOverlay.tsx
Normal file
64
src/components/textOverlay.tsx
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { TextBlock } from '@react-native-ml-kit/text-recognition';
|
||||||
|
import { TouchableRipple, useTheme } from 'react-native-paper';
|
||||||
|
import { StyleSheet } from 'react-native';
|
||||||
|
import { Dimensions } from '../types';
|
||||||
|
|
||||||
|
const textOverlayStyles = StyleSheet.create({
|
||||||
|
touchable: {
|
||||||
|
position: 'absolute',
|
||||||
|
borderWidth: 1,
|
||||||
|
zIndex: 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const TextOverlay = ({
|
||||||
|
blocks,
|
||||||
|
onTextPress,
|
||||||
|
onTextLongPress,
|
||||||
|
imageDimensions,
|
||||||
|
frameDimensions,
|
||||||
|
}: {
|
||||||
|
blocks: TextBlock[];
|
||||||
|
onTextPress: (text: string) => void;
|
||||||
|
onTextLongPress: (text: string) => void;
|
||||||
|
imageDimensions: Dimensions;
|
||||||
|
frameDimensions: Dimensions;
|
||||||
|
}) => {
|
||||||
|
const { colors } = useTheme();
|
||||||
|
|
||||||
|
const widthScale = frameDimensions.width / imageDimensions.width;
|
||||||
|
const heightScale = frameDimensions.height / imageDimensions.height;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{blocks.map(
|
||||||
|
(block, index) =>
|
||||||
|
block.frame && (
|
||||||
|
<TouchableRipple
|
||||||
|
key={index}
|
||||||
|
style={[
|
||||||
|
textOverlayStyles.touchable,
|
||||||
|
{
|
||||||
|
top: block.frame.top * heightScale - 5,
|
||||||
|
left: block.frame.left * widthScale - 5,
|
||||||
|
width: block.frame.width * widthScale + 10,
|
||||||
|
height: block.frame.height * heightScale + 10,
|
||||||
|
borderColor: colors.error,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
onPress={() =>
|
||||||
|
onTextPress(block.text.replaceAll('\n', ' ').trim())
|
||||||
|
}
|
||||||
|
onLongPress={() =>
|
||||||
|
onTextLongPress(block.text.replaceAll('\n', ' ').trim())
|
||||||
|
}>
|
||||||
|
<></>
|
||||||
|
</TouchableRipple>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TextOverlay;
|
@@ -1,5 +1,5 @@
|
|||||||
import { BSON, Object, ObjectSchema } from 'realm';
|
import { BSON, Object, ObjectSchema } from 'realm';
|
||||||
import { Tag } from './tag';
|
import { Tag } from '.';
|
||||||
|
|
||||||
enum MEME_TYPE {
|
enum MEME_TYPE {
|
||||||
IMAGE = 'Image',
|
IMAGE = 'Image',
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { BSON, Object, ObjectSchema } from 'realm';
|
import { BSON, Object, ObjectSchema } from 'realm';
|
||||||
import { Meme } from './meme';
|
import { Meme } from '.';
|
||||||
import { generateRandomColor } from '../utilities';
|
import { generateRandomColor } from '../utilities';
|
||||||
|
|
||||||
class Tag extends Object<Tag> {
|
class Tag extends Object<Tag> {
|
||||||
|
@@ -15,17 +15,17 @@ import {
|
|||||||
ROUTE,
|
ROUTE,
|
||||||
RootStackParamList,
|
RootStackParamList,
|
||||||
StagingMeme,
|
StagingMeme,
|
||||||
} from '../../types';
|
} from '../../../types';
|
||||||
import { Meme, Tag } from '../../database';
|
import { Meme, Tag } from '../../../database';
|
||||||
import { RootState } from '../../state';
|
import { RootState } from '../../../state';
|
||||||
import {
|
import {
|
||||||
allowedMimeTypes,
|
allowedMimeTypes,
|
||||||
getMemeTypeFromMimeType,
|
getMemeTypeFromMimeType,
|
||||||
guessMimeType,
|
guessMimeType,
|
||||||
validateMemeTitle,
|
validateMemeTitle,
|
||||||
} from '../../utilities';
|
} from '../../../utilities';
|
||||||
import { MemeEditor } from '../../components';
|
import MemeEditor from './memeEditor';
|
||||||
import editorStyles from './editorStyles';
|
import editorStyles from '../editorStyles';
|
||||||
|
|
||||||
const AddMeme = ({
|
const AddMeme = ({
|
||||||
route,
|
route,
|
@@ -6,12 +6,12 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack';
|
|||||||
import { useObject, useRealm } from '@realm/react';
|
import { useObject, useRealm } from '@realm/react';
|
||||||
import { useDeviceOrientation } from '@react-native-community/hooks';
|
import { useDeviceOrientation } from '@react-native-community/hooks';
|
||||||
import { BSON } from 'realm';
|
import { BSON } from 'realm';
|
||||||
import { RootStackParamList, ROUTE, StagingMeme } from '../../types';
|
|
||||||
import { pickSingle } from 'react-native-document-picker';
|
import { pickSingle } from 'react-native-document-picker';
|
||||||
import { AndroidScoped, FileSystem } from 'react-native-file-access';
|
import { AndroidScoped, FileSystem } from 'react-native-file-access';
|
||||||
import { extension } from 'react-native-mime-types';
|
import { extension } from 'react-native-mime-types';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { Meme } from '../../database';
|
import { RootStackParamList, ROUTE, StagingMeme } from '../../../types';
|
||||||
|
import { Meme } from '../../../database';
|
||||||
import {
|
import {
|
||||||
allowedMimeTypes,
|
allowedMimeTypes,
|
||||||
deleteMeme,
|
deleteMeme,
|
||||||
@@ -20,10 +20,10 @@ import {
|
|||||||
guessMimeType,
|
guessMimeType,
|
||||||
noOp,
|
noOp,
|
||||||
validateMemeTitle,
|
validateMemeTitle,
|
||||||
} from '../../utilities';
|
} from '../../../utilities';
|
||||||
import { MemeEditor } from '../../components';
|
import { RootState } from '../../../state';
|
||||||
import editorStyles from './editorStyles';
|
import MemeEditor from './memeEditor';
|
||||||
import { RootState } from '../../state';
|
import editorStyles from '../editorStyles';
|
||||||
|
|
||||||
const EditMeme = ({
|
const EditMeme = ({
|
||||||
route,
|
route,
|
@@ -1,17 +1,21 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useEffect, useMemo, useState } from 'react';
|
||||||
import { HelperText, Text, TextInput, useTheme } from 'react-native-paper';
|
import { HelperText, Text, TextInput, useTheme } from 'react-native-paper';
|
||||||
import { Image, LayoutAnimation } from 'react-native';
|
import { Image, LayoutAnimation, View } from 'react-native';
|
||||||
import { useSafeAreaFrame } from 'react-native-safe-area-context';
|
import { useSafeAreaFrame } from 'react-native-safe-area-context';
|
||||||
import { LoadingView, MemeFail, MemeTagSelector } from '..';
|
import Video from 'react-native-video';
|
||||||
|
import { LoadingView, MemeFail, TextOverlay } from '../../../components';
|
||||||
import {
|
import {
|
||||||
getFilenameFromUri,
|
getFilenameFromUri,
|
||||||
getMemeTypeFromMimeType,
|
getMemeTypeFromMimeType,
|
||||||
validateMemeTitle,
|
validateMemeTitle,
|
||||||
} from '../../utilities';
|
} from '../../../utilities';
|
||||||
import { StagingMeme } from '../../types';
|
import { StagingMeme } from '../../../types';
|
||||||
import { useMemeDimensions } from '../../hooks';
|
import { useMemeDimensions } from '../../../hooks';
|
||||||
import { MEME_TYPE } from '../../database';
|
import { MEME_TYPE } from '../../../database';
|
||||||
import Video from 'react-native-video';
|
import MemeTagSelector from './memeTagSelector/memeTagSelector';
|
||||||
|
import TextRecognition, {
|
||||||
|
TextRecognitionResult,
|
||||||
|
} from '@react-native-ml-kit/text-recognition';
|
||||||
|
|
||||||
const memeEditorStyles = {
|
const memeEditorStyles = {
|
||||||
media: {
|
media: {
|
||||||
@@ -65,8 +69,15 @@ const MemeEditor = ({
|
|||||||
useMemo(() => (errorIn: Error) => setError(errorIn), [setError]),
|
useMemo(() => (errorIn: Error) => setError(errorIn), [setError]),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const [recognizedText, setRecognizedText] = useState<TextRecognitionResult>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!uri || !mimeType || !mimeType.startsWith('image')) return;
|
||||||
|
void TextRecognition.recognize(uri).then(setRecognizedText);
|
||||||
|
}, [mimeType, uri]);
|
||||||
|
|
||||||
const mediaComponent = useMemo(() => {
|
const mediaComponent = useMemo(() => {
|
||||||
if (!mimeType || !dimensions) return <></>;
|
if (!mimeType || !dimensions || !staging) return <></>;
|
||||||
|
|
||||||
const dimensionStyles = {
|
const dimensionStyles = {
|
||||||
width: width * 0.92,
|
width: width * 0.92,
|
||||||
@@ -83,11 +94,35 @@ const MemeEditor = ({
|
|||||||
case MEME_TYPE.IMAGE:
|
case MEME_TYPE.IMAGE:
|
||||||
case MEME_TYPE.GIF: {
|
case MEME_TYPE.GIF: {
|
||||||
return (
|
return (
|
||||||
<Image
|
<View>
|
||||||
source={{ uri }}
|
<Image
|
||||||
style={[memeEditorStyles.media, dimensionStyles]}
|
source={{ uri }}
|
||||||
resizeMode="contain"
|
style={[memeEditorStyles.media, dimensionStyles]}
|
||||||
/>
|
resizeMode="contain"
|
||||||
|
/>
|
||||||
|
{recognizedText && (
|
||||||
|
<TextOverlay
|
||||||
|
blocks={recognizedText.blocks}
|
||||||
|
onTextPress={text =>
|
||||||
|
setStaging({
|
||||||
|
...staging,
|
||||||
|
title: validateMemeTitle(text),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
onTextLongPress={text =>
|
||||||
|
setStaging({
|
||||||
|
...staging,
|
||||||
|
title: validateMemeTitle(`${staging.title.parsed} ${text}`),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
imageDimensions={dimensions}
|
||||||
|
frameDimensions={{
|
||||||
|
...dimensionStyles,
|
||||||
|
aspectRatio: dimensionStyles.width / dimensionStyles.height,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
case MEME_TYPE.VIDEO: {
|
case MEME_TYPE.VIDEO: {
|
||||||
@@ -104,7 +139,7 @@ const MemeEditor = ({
|
|||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [dimensions, mimeType, uri, width]);
|
}, [dimensions, mimeType, recognizedText, setStaging, staging, uri, width]);
|
||||||
|
|
||||||
if (!uri || !mimeType || !staging) return <LoadingView />;
|
if (!uri || !mimeType || !staging) return <LoadingView />;
|
||||||
|
|
@@ -4,10 +4,10 @@ import { Chip, Modal, Portal, Searchbar, useTheme } from 'react-native-paper';
|
|||||||
import { LayoutAnimation, StyleSheet } from 'react-native';
|
import { LayoutAnimation, StyleSheet } from 'react-native';
|
||||||
import { FlashList } from '@shopify/flash-list';
|
import { FlashList } from '@shopify/flash-list';
|
||||||
import { useSafeAreaFrame } from 'react-native-safe-area-context';
|
import { useSafeAreaFrame } from 'react-native-safe-area-context';
|
||||||
import { TAG_SORT, tagSortQuery } from '../../../types';
|
import { TAG_SORT, tagSortQuery } from '../../../../types';
|
||||||
import { TagChip } from '../../tags';
|
import { TagChip } from '../../../../components';
|
||||||
import { Tag } from '../../../database';
|
import { Tag } from '../../../../database';
|
||||||
import { validateTagName } from '../../../utilities';
|
import { validateTagName } from '../../../../utilities';
|
||||||
|
|
||||||
const memeTagSearchModalStyles = StyleSheet.create({
|
const memeTagSearchModalStyles = StyleSheet.create({
|
||||||
modal: {
|
modal: {
|
@@ -3,8 +3,8 @@ import { LayoutAnimation, StyleSheet, View } from 'react-native';
|
|||||||
import { Chip } from 'react-native-paper';
|
import { Chip } from 'react-native-paper';
|
||||||
import { FlashList } from '@shopify/flash-list';
|
import { FlashList } from '@shopify/flash-list';
|
||||||
import { useSafeAreaFrame } from 'react-native-safe-area-context';
|
import { useSafeAreaFrame } from 'react-native-safe-area-context';
|
||||||
import { TagChip } from '../../tags';
|
import { TagChip } from '../../../../components';
|
||||||
import { Tag } from '../../../database';
|
import { Tag } from '../../../../database';
|
||||||
import MemeTagSearchModal from './memeTagSearchModal';
|
import MemeTagSearchModal from './memeTagSearchModal';
|
||||||
|
|
||||||
const memeTagSelectorStyles = StyleSheet.create({
|
const memeTagSelectorStyles = StyleSheet.create({
|
@@ -8,11 +8,11 @@ import {
|
|||||||
generateRandomColor,
|
generateRandomColor,
|
||||||
validateColor,
|
validateColor,
|
||||||
validateTagName,
|
validateTagName,
|
||||||
} from '../../utilities';
|
} from '../../../utilities';
|
||||||
import { Tag } from '../../database';
|
import { Tag } from '../../../database';
|
||||||
import { TagEditor } from '../../components';
|
import { StagingTag } from '../../../types';
|
||||||
import editorStyles from './editorStyles';
|
import TagEditor from './tagEditor';
|
||||||
import { StagingTag } from '../../types';
|
import editorStyles from '../editorStyles';
|
||||||
|
|
||||||
const AddTag = () => {
|
const AddTag = () => {
|
||||||
const { goBack } = useNavigation();
|
const { goBack } = useNavigation();
|
@@ -6,11 +6,11 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack';
|
|||||||
import { BSON } from 'realm';
|
import { BSON } from 'realm';
|
||||||
import { useObject, useRealm } from '@realm/react';
|
import { useObject, useRealm } from '@realm/react';
|
||||||
import { useDeviceOrientation } from '@react-native-community/hooks';
|
import { useDeviceOrientation } from '@react-native-community/hooks';
|
||||||
import { TagEditor } from '../../components';
|
import { ROUTE, RootStackParamList, StagingTag } from '../../../types';
|
||||||
import { ROUTE, RootStackParamList, StagingTag } from '../../types';
|
import { Tag } from '../../../database';
|
||||||
import { Tag } from '../../database';
|
import { deleteTag, validateColor, validateTagName } from '../../../utilities';
|
||||||
import { deleteTag, validateColor, validateTagName } from '../../utilities';
|
import TagEditor from './tagEditor';
|
||||||
import editorStyles from './editorStyles';
|
import editorStyles from '../editorStyles';
|
||||||
|
|
||||||
const EditTag = ({
|
const EditTag = ({
|
||||||
route,
|
route,
|
@@ -1,12 +1,12 @@
|
|||||||
import React, { useEffect, useRef } from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
import { HelperText, TextInput } from 'react-native-paper';
|
import { HelperText, TextInput } from 'react-native-paper';
|
||||||
import TagPreview from './tagPreview';
|
|
||||||
import {
|
import {
|
||||||
generateRandomColor,
|
generateRandomColor,
|
||||||
validateColor,
|
validateColor,
|
||||||
validateTagName,
|
validateTagName,
|
||||||
} from '../../utilities';
|
} from '../../../utilities';
|
||||||
import { StagingTag } from '../../types';
|
import { StagingTag } from '../../../types';
|
||||||
|
import TagPreview from './tagPreview';
|
||||||
|
|
||||||
const TagEditor = ({
|
const TagEditor = ({
|
||||||
staging,
|
staging,
|
@@ -2,7 +2,7 @@ import React, { useMemo } from 'react';
|
|||||||
import { StyleSheet, View } from 'react-native';
|
import { StyleSheet, View } from 'react-native';
|
||||||
import FontAwesome5 from 'react-native-vector-icons/FontAwesome5';
|
import FontAwesome5 from 'react-native-vector-icons/FontAwesome5';
|
||||||
import { Chip, useTheme } from 'react-native-paper';
|
import { Chip, useTheme } from 'react-native-paper';
|
||||||
import { getContrastColor } from '../../utilities';
|
import { getContrastColor } from '../../../utilities';
|
||||||
|
|
||||||
const tagPreviewStyles = StyleSheet.create({
|
const tagPreviewStyles = StyleSheet.create({
|
||||||
view: {
|
view: {
|
@@ -1,9 +1,9 @@
|
|||||||
export { default as AddMeme } from './editors/addMeme';
|
export { default as AddMeme } from './editors/meme/addMeme';
|
||||||
export { default as AddTag } from './editors/addTag';
|
export { default as AddTag } from './editors/tag/addTag';
|
||||||
export { default as EditMeme } from './editors/editMeme';
|
export { default as EditMeme } from './editors/meme/editMeme';
|
||||||
export { default as EditTag } from './editors/editTag';
|
export { default as EditTag } from './editors/tag/editTag';
|
||||||
export { default as Memes } from './memes';
|
export { default as Memes } from './memes/memes';
|
||||||
export { default as MemeView } from './memeView';
|
export { default as MemeView } from './memeView/memeView';
|
||||||
export { default as Settings } from './settings';
|
export { default as Settings } from './settings/settings';
|
||||||
export { default as Tags } from './tags';
|
export { default as Tags } from './tags/tags';
|
||||||
export { default as Welcome } from './welcome';
|
export { default as Welcome } from './welcome';
|
||||||
|
@@ -12,9 +12,9 @@ import {
|
|||||||
RootStackParamList,
|
RootStackParamList,
|
||||||
ROUTE,
|
ROUTE,
|
||||||
SORT_DIRECTION,
|
SORT_DIRECTION,
|
||||||
} from '../types';
|
} from '../../types';
|
||||||
import { Meme } from '../database';
|
import { Meme } from '../../database';
|
||||||
import { LoadingView, MemeViewItem } from '../components';
|
import { LoadingView } from '../../components';
|
||||||
import {
|
import {
|
||||||
copyMeme,
|
copyMeme,
|
||||||
deleteMeme,
|
deleteMeme,
|
||||||
@@ -22,8 +22,9 @@ import {
|
|||||||
favoriteMeme,
|
favoriteMeme,
|
||||||
multipleIdQuery,
|
multipleIdQuery,
|
||||||
shareMeme,
|
shareMeme,
|
||||||
} from '../utilities';
|
} from '../../utilities';
|
||||||
import { RootState } from '../state';
|
import { RootState } from '../../state';
|
||||||
|
import MemeViewItem from './memeViewItem';
|
||||||
|
|
||||||
const memeViewStyles = StyleSheet.create({
|
const memeViewStyles = StyleSheet.create({
|
||||||
// eslint-disable-next-line react-native/no-color-literals
|
// eslint-disable-next-line react-native/no-color-literals
|
@@ -3,11 +3,11 @@ import { StyleSheet, View } from 'react-native';
|
|||||||
import { useSafeAreaFrame } from 'react-native-safe-area-context';
|
import { useSafeAreaFrame } from 'react-native-safe-area-context';
|
||||||
import { AndroidScoped } from 'react-native-file-access';
|
import { AndroidScoped } from 'react-native-file-access';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
|
import Video from 'react-native-video';
|
||||||
import { MEME_TYPE, Meme } from '../../database';
|
import { MEME_TYPE, Meme } from '../../database';
|
||||||
import { RootState } from '../../state';
|
import { RootState } from '../../state';
|
||||||
import { AnimatedImage, LoadingView, MemeFail } from '..';
|
import { AnimatedImage, LoadingView, MemeFail } from '../../components';
|
||||||
import { useMemeDimensions } from '../../hooks';
|
import { useMemeDimensions } from '../../hooks';
|
||||||
import Video from 'react-native-video';
|
|
||||||
|
|
||||||
const memeViewItemStyles = StyleSheet.create({
|
const memeViewItemStyles = StyleSheet.create({
|
||||||
view: {
|
view: {
|
@@ -17,11 +17,13 @@ import {
|
|||||||
useNavigation,
|
useNavigation,
|
||||||
} from '@react-navigation/native';
|
} from '@react-navigation/native';
|
||||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||||
import { ROUTE, SORT_DIRECTION, memesSortQuery } from '../types';
|
|
||||||
import { RootState, setNavVisible } from '../state';
|
|
||||||
import { Meme } from '../database';
|
|
||||||
import { HideableHeader, MemesHeader, MemesList } from '../components';
|
|
||||||
import { useDeviceOrientation } from '@react-native-community/hooks';
|
import { useDeviceOrientation } from '@react-native-community/hooks';
|
||||||
|
import { ROUTE, SORT_DIRECTION, memesSortQuery } from '../../types';
|
||||||
|
import { RootState, setNavVisible } from '../../state';
|
||||||
|
import { Meme } from '../../database';
|
||||||
|
import { HideableHeader } from '../../components';
|
||||||
|
import MemesHeader from './memesHeader';
|
||||||
|
import MemesList from './memesList/memesList';
|
||||||
|
|
||||||
const memesStyles = StyleSheet.create({
|
const memesStyles = StyleSheet.create({
|
||||||
listView: {
|
listView: {
|
@@ -5,7 +5,7 @@ import { useSafeAreaFrame } from 'react-native-safe-area-context';
|
|||||||
import { AndroidScoped } from 'react-native-file-access';
|
import { AndroidScoped } from 'react-native-file-access';
|
||||||
import { MEME_TYPE, Meme } from '../../../database';
|
import { MEME_TYPE, Meme } from '../../../database';
|
||||||
import { RootState } from '../../../state';
|
import { RootState } from '../../../state';
|
||||||
import { MemeFail } from '..';
|
import { MemeFail } from '../../../components';
|
||||||
import { getFontAwesome5IconSize } from '../../../utilities';
|
import { getFontAwesome5IconSize } from '../../../utilities';
|
||||||
import { useMemeDimensions } from '../../../hooks';
|
import { useMemeDimensions } from '../../../hooks';
|
||||||
|
|
@@ -5,7 +5,7 @@ import { useSafeAreaFrame } from 'react-native-safe-area-context';
|
|||||||
import { AndroidScoped } from 'react-native-file-access';
|
import { AndroidScoped } from 'react-native-file-access';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { MEME_TYPE, Meme } from '../../../database';
|
import { MEME_TYPE, Meme } from '../../../database';
|
||||||
import { MemeFail } from '..';
|
import { MemeFail } from '../../../components';
|
||||||
import { RootState } from '../../../state';
|
import { RootState } from '../../../state';
|
||||||
import { useMemeDimensions } from '../../../hooks';
|
import { useMemeDimensions } from '../../../hooks';
|
||||||
|
|
@@ -5,7 +5,7 @@ import { useSafeAreaFrame } from 'react-native-safe-area-context';
|
|||||||
import { AndroidScoped } from 'react-native-file-access';
|
import { AndroidScoped } from 'react-native-file-access';
|
||||||
import { MEME_TYPE, Meme } from '../../../database';
|
import { MEME_TYPE, Meme } from '../../../database';
|
||||||
import { RootState } from '../../../state';
|
import { RootState } from '../../../state';
|
||||||
import { MemeFail } from '..';
|
import { MemeFail } from '../../../components';
|
||||||
import { getFontAwesome5IconSize } from '../../../utilities';
|
import { getFontAwesome5IconSize } from '../../../utilities';
|
||||||
import { useMemeDimensions } from '../../../hooks';
|
import { useMemeDimensions } from '../../../hooks';
|
||||||
|
|
@@ -11,6 +11,8 @@ import {
|
|||||||
} from 'react-native-paper';
|
} from 'react-native-paper';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import type {} from 'redux-thunk/extend-redux';
|
import type {} from 'redux-thunk/extend-redux';
|
||||||
|
import { useRealm } from '@realm/react';
|
||||||
|
import { FileSystem, FileStat } from 'react-native-file-access';
|
||||||
import {
|
import {
|
||||||
RootState,
|
RootState,
|
||||||
setAutofocusMemesSearch,
|
setAutofocusMemesSearch,
|
||||||
@@ -19,11 +21,9 @@ import {
|
|||||||
setMasonryColumns,
|
setMasonryColumns,
|
||||||
setNoMedia,
|
setNoMedia,
|
||||||
setSnackbarMessage,
|
setSnackbarMessage,
|
||||||
} from '../state';
|
} from '../../state';
|
||||||
import StorageLocationChangeDialog from '../components/storageLocationChangeDialog';
|
import { Meme } from '../../database';
|
||||||
import { useRealm } from '@realm/react';
|
import StorageLocationChangeDialog from './storageLocationChangeDialog';
|
||||||
import { FileSystem, FileStat } from 'react-native-file-access';
|
|
||||||
import { Meme } from '../database';
|
|
||||||
|
|
||||||
const settingsStyles = StyleSheet.create({
|
const settingsStyles = StyleSheet.create({
|
||||||
scrollView: {
|
scrollView: {
|
@@ -4,8 +4,8 @@ import { Dialog, ProgressBar, Text } from 'react-native-paper';
|
|||||||
import { openDocumentTree } from 'react-native-scoped-storage';
|
import { openDocumentTree } from 'react-native-scoped-storage';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { AndroidScoped, FileSystem } from 'react-native-file-access';
|
import { AndroidScoped, FileSystem } from 'react-native-file-access';
|
||||||
import { RootState, setStorageUri } from '../state';
|
import { RootState, setStorageUri } from '../../state';
|
||||||
import { clearPermissions, isPermissionForPath, noOp } from '../utilities';
|
import { clearPermissions, isPermissionForPath, noOp } from '../../utilities';
|
||||||
|
|
||||||
const storageLocationChangeDialogStyles = StyleSheet.create({
|
const storageLocationChangeDialogStyles = StyleSheet.create({
|
||||||
progressBar: {
|
progressBar: {
|
@@ -13,10 +13,12 @@ import { FlashList } from '@shopify/flash-list';
|
|||||||
import { useFocusEffect } from '@react-navigation/native';
|
import { useFocusEffect } from '@react-navigation/native';
|
||||||
import { useDeviceOrientation } from '@react-native-community/hooks';
|
import { useDeviceOrientation } from '@react-native-community/hooks';
|
||||||
import { useSafeAreaFrame } from 'react-native-safe-area-context';
|
import { useSafeAreaFrame } from 'react-native-safe-area-context';
|
||||||
import { HideableHeader, TagRow, TagsHeader } from '../components';
|
import { HideableHeader } from '../../components';
|
||||||
import { Tag } from '../database';
|
import { Tag } from '../../database';
|
||||||
import { RootState, setNavVisible } from '../state';
|
import { RootState, setNavVisible } from '../../state';
|
||||||
import { SORT_DIRECTION, tagSortQuery } from '../types';
|
import { SORT_DIRECTION, tagSortQuery } from '../../types';
|
||||||
|
import TagsHeader from './tagsHeader';
|
||||||
|
import TagRow from './tagsList/tagRow';
|
||||||
|
|
||||||
const tagsStyles = StyleSheet.create({
|
const tagsStyles = StyleSheet.create({
|
||||||
listView: {
|
listView: {
|
@@ -2,9 +2,9 @@ import React from 'react';
|
|||||||
import { StyleSheet, View } from 'react-native';
|
import { StyleSheet, View } from 'react-native';
|
||||||
import { TouchableRipple, Text } from 'react-native-paper';
|
import { TouchableRipple, Text } from 'react-native-paper';
|
||||||
import { useNavigation, NavigationProp } from '@react-navigation/native';
|
import { useNavigation, NavigationProp } from '@react-navigation/native';
|
||||||
import { Tag } from '../../database';
|
import { Tag } from '../../../database';
|
||||||
import { ROUTE, RootStackParamList } from '../../types';
|
import { ROUTE, RootStackParamList } from '../../../types';
|
||||||
import { TagChip } from '.';
|
import { TagChip } from '../../../components';
|
||||||
|
|
||||||
const tagRowStyles = StyleSheet.create({
|
const tagRowStyles = StyleSheet.create({
|
||||||
view: {
|
view: {
|
@@ -1,6 +1,6 @@
|
|||||||
import { DocumentPickerResponse } from 'react-native-document-picker';
|
import { DocumentPickerResponse } from 'react-native-document-picker';
|
||||||
import { getFilenameFromUri } from '../utilities';
|
import { getFilenameFromUri } from '../utilities';
|
||||||
import { SharedItem } from './share';
|
import { SharedItem } from '.';
|
||||||
|
|
||||||
enum ROUTE {
|
enum ROUTE {
|
||||||
MAIN = 'Main',
|
MAIN = 'Main',
|
||||||
|
@@ -4,7 +4,7 @@ import Share from 'react-native-share';
|
|||||||
import Clipboard from '@react-native-clipboard/clipboard';
|
import Clipboard from '@react-native-clipboard/clipboard';
|
||||||
import { Meme } from '../database';
|
import { Meme } from '../database';
|
||||||
import { ROUTE, RootStackParamList } from '../types';
|
import { ROUTE, RootStackParamList } from '../types';
|
||||||
import { noOp } from './constants';
|
import { noOp } from '.';
|
||||||
|
|
||||||
const favoriteMeme = (realm: Realm, meme: Meme) => {
|
const favoriteMeme = (realm: Realm, meme: Meme) => {
|
||||||
realm.write(() => {
|
realm.write(() => {
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { isHexColor, isRgbColor } from './color';
|
import { isHexColor, isRgbColor } from '.';
|
||||||
|
|
||||||
interface StringValidationResult {
|
interface StringValidationResult {
|
||||||
valid: boolean;
|
valid: boolean;
|
||||||
|
Reference in New Issue
Block a user