Add meme-adding logic
Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
141
src/screens/addMeme.tsx
Normal file
141
src/screens/addMeme.tsx
Normal file
@@ -0,0 +1,141 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Appbar, Button, useTheme } from 'react-native-paper';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { useDimensions } from '../contexts';
|
||||
import { ScrollView, View } from 'react-native';
|
||||
import { NativeStackScreenProps } from '@react-navigation/native-stack';
|
||||
import { useRealm } from '@realm/react';
|
||||
import { BSON } from 'realm';
|
||||
import { AndroidScoped, FileSystem } from 'react-native-file-access';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { extension } from 'react-native-mime-types';
|
||||
import styles from '../styles';
|
||||
import { ROUTE, RootStackParamList } from '../types';
|
||||
import { MEME_TYPE, Meme, Tag } from '../database';
|
||||
import { RootState } from '../state';
|
||||
import { getMemeType } from '../utilities';
|
||||
import { MemeEditor } from '../components';
|
||||
|
||||
const AddMeme = ({
|
||||
route,
|
||||
}: NativeStackScreenProps<RootStackParamList, ROUTE.ADD_MEME>) => {
|
||||
const navigation = useNavigation();
|
||||
const { colors } = useTheme();
|
||||
const { orientation } = useDimensions();
|
||||
const realm = useRealm();
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const storageUri = useSelector(
|
||||
(state: RootState) => state.settings.storageUri,
|
||||
)!;
|
||||
|
||||
const { uri } = route.params;
|
||||
|
||||
const memeType =
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
uri.length > 1 ? MEME_TYPE.ALBUM : getMemeType(uri[0].type!);
|
||||
|
||||
const [memeTitle, setMemeTitle] = useState('New Meme');
|
||||
const [memeDescription, setMemeDescription] = useState('');
|
||||
const [memeIsFavorite, setMemeIsFavorite] = useState(false);
|
||||
const [memeTags, setMemeTags] = useState(new Map<string, Tag>());
|
||||
|
||||
const [memeTitleError, setMemeTitleError] = useState<string | undefined>();
|
||||
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
const handleSave = async () => {
|
||||
setIsSaving(true);
|
||||
|
||||
const uuid = new BSON.UUID();
|
||||
const savedUri: string[] = [];
|
||||
const hash: string[] = [];
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const fileExtension = extension(uri[0].type!);
|
||||
if (!fileExtension) navigation.goBack();
|
||||
|
||||
savedUri.push(
|
||||
AndroidScoped.appendPath(
|
||||
storageUri,
|
||||
`${uuid.toHexString()}.${fileExtension as string}`,
|
||||
),
|
||||
);
|
||||
|
||||
await FileSystem.cp(uri[0].uri, savedUri[0]);
|
||||
const { size } = await FileSystem.stat(savedUri[0]);
|
||||
hash.push(await FileSystem.hash(savedUri[0], 'MD5'));
|
||||
|
||||
realm.write(() => {
|
||||
const meme: Meme | undefined = realm.create<Meme>(Meme.schema.name, {
|
||||
id: uuid,
|
||||
type: memeType,
|
||||
uri: savedUri,
|
||||
size,
|
||||
hash,
|
||||
title: memeTitle,
|
||||
description: memeDescription,
|
||||
isFavorite: memeIsFavorite,
|
||||
tags: [...memeTags.values()],
|
||||
tagsLength: memeTags.size,
|
||||
});
|
||||
|
||||
meme.tags.forEach(tag => {
|
||||
tag.dateModified = new Date();
|
||||
const memes = tag.memes as Set<Meme>;
|
||||
memes.add(meme);
|
||||
tag.memesLength = memes.size;
|
||||
});
|
||||
});
|
||||
|
||||
setIsSaving(false);
|
||||
navigation.goBack();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Appbar.Header>
|
||||
<Appbar.BackAction onPress={() => navigation.goBack()} />
|
||||
<Appbar.Content title={'Add Meme'} />
|
||||
<Appbar.Action
|
||||
icon={memeIsFavorite ? 'heart' : 'heart-outline'}
|
||||
onPress={() => setMemeIsFavorite(!memeIsFavorite)}
|
||||
/>
|
||||
</Appbar.Header>
|
||||
<ScrollView
|
||||
contentContainerStyle={[
|
||||
orientation == 'portrait' && styles.paddingVertical,
|
||||
orientation == 'landscape' && styles.smallPaddingVertical,
|
||||
styles.paddingHorizontal,
|
||||
styles.flexGrow,
|
||||
styles.flexColumnSpaceBetween,
|
||||
{ backgroundColor: colors.background },
|
||||
]}>
|
||||
<View style={[styles.flex, styles.justifyStart]}>
|
||||
<MemeEditor
|
||||
imageUri={uri.map(uriIn => uriIn.uri)}
|
||||
memeTitle={memeTitle}
|
||||
setMemeTitle={setMemeTitle}
|
||||
memeDescription={memeDescription}
|
||||
setMemeDescription={setMemeDescription}
|
||||
memeTags={memeTags}
|
||||
setMemeTags={setMemeTags}
|
||||
memeTitleError={memeTitleError}
|
||||
setMemeTitleError={setMemeTitleError}
|
||||
/>
|
||||
</View>
|
||||
<View style={[styles.flex, styles.justifyEnd]}>
|
||||
<Button
|
||||
mode="contained"
|
||||
icon="floppy"
|
||||
onPress={handleSave}
|
||||
disabled={!!memeTitleError || isSaving}
|
||||
loading={isSaving}>
|
||||
Save
|
||||
</Button>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddMeme;
|
79
src/screens/addTag.tsx
Normal file
79
src/screens/addTag.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
import React, { useState } from 'react';
|
||||
import { ScrollView, View } from 'react-native';
|
||||
import { Appbar, Button, useTheme } from 'react-native-paper';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { useRealm } from '@realm/react';
|
||||
import styles from '../styles';
|
||||
import { generateRandomColor } from '../utilities';
|
||||
import { useDimensions } from '../contexts';
|
||||
import { Tag } from '../database';
|
||||
import { TagEditor } from '../components';
|
||||
|
||||
const AddTag = () => {
|
||||
const navigation = useNavigation();
|
||||
const { colors } = useTheme();
|
||||
const { orientation } = useDimensions();
|
||||
const realm = useRealm();
|
||||
|
||||
const [tagName, setTagName] = useState('newTag');
|
||||
const [tagColor, setTagColor] = useState(generateRandomColor());
|
||||
const [validatedTagColor, setValidatedTagColor] = useState(tagColor);
|
||||
|
||||
const [tagNameError, setTagNameError] = useState<string | undefined>();
|
||||
const [tagColorError, setTagColorError] = useState<string | undefined>();
|
||||
|
||||
const handleSave = () => {
|
||||
realm.write(() => {
|
||||
realm.create(Tag.schema.name, {
|
||||
name: tagName,
|
||||
color: tagColor,
|
||||
});
|
||||
});
|
||||
|
||||
navigation.goBack();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Appbar.Header>
|
||||
<Appbar.BackAction onPress={() => navigation.goBack()} />
|
||||
<Appbar.Content title={'Add Tag'} />
|
||||
</Appbar.Header>
|
||||
<ScrollView
|
||||
contentContainerStyle={[
|
||||
orientation == 'portrait' && styles.paddingVertical,
|
||||
orientation == 'landscape' && styles.smallPaddingVertical,
|
||||
styles.paddingHorizontal,
|
||||
styles.flexGrow,
|
||||
styles.flexColumnSpaceBetween,
|
||||
{ backgroundColor: colors.background },
|
||||
]}>
|
||||
<View style={[styles.flex, styles.justifyStart]}>
|
||||
<TagEditor
|
||||
tagName={tagName}
|
||||
setTagName={setTagName}
|
||||
tagColor={tagColor}
|
||||
setTagColor={setTagColor}
|
||||
validatedTagColor={validatedTagColor}
|
||||
setValidatedTagColor={setValidatedTagColor}
|
||||
tagNameError={tagNameError}
|
||||
setTagNameError={setTagNameError}
|
||||
tagColorError={tagColorError}
|
||||
setTagColorError={setTagColorError}
|
||||
/>
|
||||
</View>
|
||||
<View style={[styles.flex, styles.justifyEnd]}>
|
||||
<Button
|
||||
mode="contained"
|
||||
icon="floppy"
|
||||
onPress={handleSave}
|
||||
disabled={!!tagNameError || !!tagColorError}>
|
||||
Save
|
||||
</Button>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddTag;
|
@@ -1,8 +1,8 @@
|
||||
import React from 'react';
|
||||
import { Appbar, Text, useTheme } from 'react-native-paper';
|
||||
import { ScrollView } from 'react-native';
|
||||
import { Appbar, useTheme } from 'react-native-paper';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { useDimensions } from '../contexts';
|
||||
import { ScrollView } from 'react-native';
|
||||
import styles from '../styles';
|
||||
|
||||
const EditMeme = () => {
|
||||
@@ -14,20 +14,17 @@ const EditMeme = () => {
|
||||
<>
|
||||
<Appbar.Header>
|
||||
<Appbar.BackAction onPress={() => navigation.goBack()} />
|
||||
<Appbar.Content title="Add Meme" />
|
||||
<Appbar.Content title={'Edit Meme'} />
|
||||
</Appbar.Header>
|
||||
<ScrollView
|
||||
contentContainerStyle={[
|
||||
orientation == 'portrait' && styles.paddingVertical,
|
||||
orientation == 'landscape' && styles.smallPaddingVertical,
|
||||
styles.paddingHorizontal,
|
||||
[styles.centered, styles.flex],
|
||||
styles.fullSize,
|
||||
styles.flexGrow,
|
||||
styles.flexColumnSpaceBetween,
|
||||
{ backgroundColor: colors.background },
|
||||
]}
|
||||
nestedScrollEnabled>
|
||||
<Text>Add Meme</Text>
|
||||
</ScrollView>
|
||||
]}></ScrollView>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@@ -1,19 +1,12 @@
|
||||
import React, { useState } from 'react';
|
||||
import { ScrollView, View } from 'react-native';
|
||||
import {
|
||||
TextInput,
|
||||
Appbar,
|
||||
HelperText,
|
||||
Button,
|
||||
useTheme,
|
||||
} from 'react-native-paper';
|
||||
import { Appbar, Button, useTheme } from 'react-native-paper';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { NativeStackScreenProps } from '@react-navigation/native-stack';
|
||||
import { BSON, UpdateMode } from 'realm';
|
||||
import { BSON } from 'realm';
|
||||
import { useRealm } from '@realm/react';
|
||||
import { TagPreview } from '../components';
|
||||
import { TagEditor } from '../components';
|
||||
import styles from '../styles';
|
||||
import { generateRandomColor, isValidColor } from '../utilities';
|
||||
import { useDimensions } from '../contexts';
|
||||
import { ROUTE, RootStackParamList } from '../types';
|
||||
import { Tag } from '../database';
|
||||
@@ -26,62 +19,41 @@ const EditTag = ({
|
||||
const { orientation } = useDimensions();
|
||||
const realm = useRealm();
|
||||
|
||||
const tagId = route.params?.id;
|
||||
const tag = tagId
|
||||
? realm.objectForPrimaryKey(Tag, BSON.UUID.createFromHexString(tagId))
|
||||
: undefined;
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const tag = realm.objectForPrimaryKey(
|
||||
Tag,
|
||||
BSON.UUID.createFromHexString(route.params.id),
|
||||
)!;
|
||||
|
||||
const [tagName, setTagName] = useState(tag?.name ?? 'newTag');
|
||||
const [tagColor, setTagColor] = useState(tag?.color ?? generateRandomColor());
|
||||
const [tagName, setTagName] = useState(tag.name);
|
||||
const [tagColor, setTagColor] = useState(tag.color);
|
||||
const [validatedTagColor, setValidatedTagColor] = useState(tagColor);
|
||||
|
||||
const [tagNameError, setTagNameError] = useState<string | undefined>();
|
||||
const [tagColorError, setTagColorError] = useState<string | undefined>();
|
||||
|
||||
const handleTagNameChange = (name: string) => {
|
||||
setTagName(name);
|
||||
|
||||
if (name.length === 0) {
|
||||
setTagNameError('Tag name cannot be empty');
|
||||
} else if (name.includes(' ')) {
|
||||
setTagNameError('Tag name cannot contain spaces');
|
||||
} else {
|
||||
// eslint-disable-next-line unicorn/no-useless-undefined
|
||||
setTagNameError(undefined);
|
||||
}
|
||||
};
|
||||
|
||||
const handleTagColorChange = (color: string) => {
|
||||
setTagColor(color);
|
||||
|
||||
if (isValidColor(color)) {
|
||||
setValidatedTagColor(color);
|
||||
// eslint-disable-next-line unicorn/no-useless-undefined
|
||||
setTagColorError(undefined);
|
||||
} else {
|
||||
setTagColorError('Color must be a valid hex or rgb value');
|
||||
}
|
||||
};
|
||||
|
||||
const handleSave = () => {
|
||||
realm.write(() => {
|
||||
realm.create(
|
||||
Tag,
|
||||
{
|
||||
id: tag?.id,
|
||||
name: tagName,
|
||||
color: tagColor,
|
||||
},
|
||||
UpdateMode.Modified,
|
||||
);
|
||||
tag.name = tagName;
|
||||
tag.color = tagColor;
|
||||
tag.dateModified = new Date();
|
||||
});
|
||||
|
||||
navigation.goBack();
|
||||
};
|
||||
|
||||
const handleDelete = () => {
|
||||
realm.write(() => {
|
||||
for (const meme of tag.memes) {
|
||||
meme.dateModified = new Date();
|
||||
const tags = meme.tags as Set<Tag>;
|
||||
tags.delete(tag);
|
||||
meme.tagsLength = tags.size;
|
||||
}
|
||||
|
||||
realm.delete(tag);
|
||||
});
|
||||
|
||||
navigation.goBack();
|
||||
};
|
||||
|
||||
@@ -89,50 +61,32 @@ const EditTag = ({
|
||||
<>
|
||||
<Appbar.Header>
|
||||
<Appbar.BackAction onPress={() => navigation.goBack()} />
|
||||
<Appbar.Content title={tag ? 'Edit Tag' : 'Add Tag'} />
|
||||
{tag && <Appbar.Action icon="delete" onPress={handleDelete} />}
|
||||
<Appbar.Content title={'Edit Tag'} />
|
||||
<Appbar.Action icon="delete" onPress={handleDelete} />
|
||||
</Appbar.Header>
|
||||
<ScrollView
|
||||
contentContainerStyle={[
|
||||
orientation == 'portrait' && styles.paddingVertical,
|
||||
orientation == 'landscape' && styles.smallPaddingVertical,
|
||||
styles.paddingHorizontal,
|
||||
styles.fullSize,
|
||||
styles.flexGrow,
|
||||
styles.flexColumnSpaceBetween,
|
||||
{ backgroundColor: colors.background },
|
||||
]}>
|
||||
]}
|
||||
nestedScrollEnabled>
|
||||
<View style={[styles.flex, styles.justifyStart]}>
|
||||
<TagPreview name={tagName} color={validatedTagColor} />
|
||||
<TextInput
|
||||
mode="outlined"
|
||||
label="Tag Name"
|
||||
value={tagName}
|
||||
onChangeText={handleTagNameChange}
|
||||
error={!!tagNameError}
|
||||
autoCapitalize="none"
|
||||
selectTextOnFocus
|
||||
<TagEditor
|
||||
tagName={tagName}
|
||||
setTagName={setTagName}
|
||||
tagColor={tagColor}
|
||||
setTagColor={setTagColor}
|
||||
validatedTagColor={validatedTagColor}
|
||||
setValidatedTagColor={setValidatedTagColor}
|
||||
tagNameError={tagNameError}
|
||||
setTagNameError={setTagNameError}
|
||||
tagColorError={tagColorError}
|
||||
setTagColorError={setTagColorError}
|
||||
/>
|
||||
<HelperText type="error" visible={!!tagNameError}>
|
||||
{tagNameError}
|
||||
</HelperText>
|
||||
<TextInput
|
||||
mode="outlined"
|
||||
label="Tag Color"
|
||||
value={tagColor}
|
||||
onChangeText={handleTagColorChange}
|
||||
error={!!tagColorError}
|
||||
autoCorrect={false}
|
||||
right={
|
||||
<TextInput.Icon
|
||||
icon="palette"
|
||||
onPress={() => handleTagColorChange(generateRandomColor())}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<HelperText type="error" visible={!!tagColorError}>
|
||||
{tagColorError}
|
||||
</HelperText>
|
||||
</View>
|
||||
<View style={[styles.flex, styles.justifyEnd]}>
|
||||
<Button
|
||||
|
@@ -1,6 +1,8 @@
|
||||
export { default as AddMeme } from './addMeme';
|
||||
export { default as AddTag } from './addTag';
|
||||
export { default as EditMeme } from './editMeme';
|
||||
export { default as EditTag } from './editTag';
|
||||
export { default as Home } from './home';
|
||||
export { default as Memes } from './memes';
|
||||
export { default as Settings } from './settings';
|
||||
export { default as Tags } from './tags';
|
||||
export { default as Welcome } from './welcome';
|
||||
|
@@ -16,17 +16,17 @@ import { MEME_SORT, SORT_DIRECTION } from '../types';
|
||||
import { getSortIcon, getViewIcon } from '../utilities';
|
||||
import {
|
||||
RootState,
|
||||
cycleHomeView,
|
||||
toggleHomeSortDirection,
|
||||
setHomeSortDirection,
|
||||
toggleHomeFavoritesOnly,
|
||||
setHomeSort,
|
||||
setHomeFilter,
|
||||
cycleMemesView,
|
||||
toggleMemesSortDirection,
|
||||
setMemesSortDirection,
|
||||
toggleMemesFavoritesOnly,
|
||||
setMemesSort,
|
||||
setMemesFilter,
|
||||
} from '../state';
|
||||
import { MEME_TYPE, Meme, memeTypePlural } from '../database';
|
||||
import { useDimensions } from '../contexts';
|
||||
|
||||
const homeStyles = StyleSheet.create({
|
||||
const memesStyles = StyleSheet.create({
|
||||
headerButtonView: {
|
||||
height: 50,
|
||||
},
|
||||
@@ -35,18 +35,18 @@ const homeStyles = StyleSheet.create({
|
||||
},
|
||||
});
|
||||
|
||||
const Home = () => {
|
||||
const Memes = () => {
|
||||
const { colors } = useTheme();
|
||||
const { orientation } = useDimensions();
|
||||
const sort = useSelector((state: RootState) => state.home.sort);
|
||||
const sort = useSelector((state: RootState) => state.memes.sort);
|
||||
const sortDirection = useSelector(
|
||||
(state: RootState) => state.home.sortDirection,
|
||||
(state: RootState) => state.memes.sortDirection,
|
||||
);
|
||||
const view = useSelector((state: RootState) => state.home.view);
|
||||
const view = useSelector((state: RootState) => state.memes.view);
|
||||
const favoritesOnly = useSelector(
|
||||
(state: RootState) => state.home.favoritesOnly,
|
||||
(state: RootState) => state.memes.favoritesOnly,
|
||||
);
|
||||
const filter = useSelector((state: RootState) => state.home.filter);
|
||||
const filter = useSelector((state: RootState) => state.memes.filter);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const [sortMenuVisible, setSortMenuVisible] = useState(false);
|
||||
@@ -54,20 +54,20 @@ const Home = () => {
|
||||
|
||||
const handleSortModeChange = (newSort: MEME_SORT) => {
|
||||
if (newSort === sort) {
|
||||
dispatch(toggleHomeSortDirection());
|
||||
dispatch(toggleMemesSortDirection());
|
||||
} else {
|
||||
dispatch(setHomeSort(newSort));
|
||||
dispatch(setMemesSort(newSort));
|
||||
if (newSort === MEME_SORT.TITLE) {
|
||||
dispatch(setHomeSortDirection(SORT_DIRECTION.ASCENDING));
|
||||
dispatch(setMemesSortDirection(SORT_DIRECTION.ASCENDING));
|
||||
} else {
|
||||
dispatch(setHomeSortDirection(SORT_DIRECTION.DESCENDING));
|
||||
dispatch(setMemesSortDirection(SORT_DIRECTION.DESCENDING));
|
||||
}
|
||||
}
|
||||
setSortMenuVisible(false);
|
||||
};
|
||||
|
||||
const handleFilterChange = (newFilter: MEME_TYPE | undefined) => {
|
||||
dispatch(setHomeFilter(newFilter));
|
||||
dispatch(setMemesFilter(newFilter));
|
||||
setFilterMenuVisible(false);
|
||||
};
|
||||
|
||||
@@ -92,7 +92,7 @@ const Home = () => {
|
||||
style={[
|
||||
styles.flexRowSpaceBetween,
|
||||
styles.alignCenter,
|
||||
homeStyles.headerButtonView,
|
||||
memesStyles.headerButtonView,
|
||||
]}>
|
||||
<View style={[styles.flexRow, styles.alignCenter]}>
|
||||
<Menu
|
||||
@@ -127,13 +127,15 @@ const Home = () => {
|
||||
icon={getViewIcon(view)}
|
||||
iconColor={colors.primary}
|
||||
size={16}
|
||||
onPress={() => dispatch(cycleHomeView())}
|
||||
animated
|
||||
onPress={() => dispatch(cycleMemesView())}
|
||||
/>
|
||||
<IconButton
|
||||
icon={favoritesOnly ? 'heart' : 'heart-outline'}
|
||||
iconColor={colors.primary}
|
||||
size={16}
|
||||
onPress={() => dispatch(toggleHomeFavoritesOnly())}
|
||||
animated
|
||||
onPress={() => dispatch(toggleMemesFavoritesOnly())}
|
||||
/>
|
||||
<Menu
|
||||
visible={filterMenuVisible}
|
||||
@@ -172,7 +174,7 @@ const Home = () => {
|
||||
{memes.length === 0 && (
|
||||
<HelperText
|
||||
type={'info'}
|
||||
style={[homeStyles.helperText, styles.centerText]}>
|
||||
style={[memesStyles.helperText, styles.centerText]}>
|
||||
No memes found
|
||||
</HelperText>
|
||||
)}
|
||||
@@ -180,4 +182,4 @@ const Home = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default Home;
|
||||
export default Memes;
|
@@ -28,16 +28,16 @@ const SettingsScreen = () => {
|
||||
const noMedia = useSelector((state: RootState) => state.settings.noMedia);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const [optimizingDatabase, setOptimizingDatabase] = useState(false);
|
||||
const [isOptimizingDatabase, setIsOptimizingDatabase] = useState(false);
|
||||
const [snackbarVisible, setSnackbarVisible] = useState(false);
|
||||
const [snackbarMessage, setSnackbarMessage] = useState('');
|
||||
|
||||
const optimizeDatabase = () => {
|
||||
setOptimizingDatabase(true);
|
||||
setIsOptimizingDatabase(true);
|
||||
// TODO: clean up missing / extra files
|
||||
setSnackbarMessage('Database optimized!');
|
||||
setSnackbarVisible(true);
|
||||
setOptimizingDatabase(false);
|
||||
setIsOptimizingDatabase(false);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -47,7 +47,6 @@ const SettingsScreen = () => {
|
||||
orientation == 'portrait' && styles.paddingTop,
|
||||
orientation == 'landscape' && styles.smallPaddingTop,
|
||||
styles.paddingHorizontal,
|
||||
styles.fullSize,
|
||||
{ backgroundColor: colors.background },
|
||||
]}>
|
||||
<View>
|
||||
@@ -55,10 +54,7 @@ const SettingsScreen = () => {
|
||||
<List.Subheader>Database</List.Subheader>
|
||||
<Button
|
||||
mode="elevated"
|
||||
style={{
|
||||
marginBottom: responsive.verticalScale(15),
|
||||
}}
|
||||
loading={optimizingDatabase}
|
||||
loading={isOptimizingDatabase}
|
||||
onPress={optimizeDatabase}>
|
||||
Optimize Database Now
|
||||
</Button>
|
||||
|
@@ -2,7 +2,6 @@ import React, { useCallback, useRef, useState } from 'react';
|
||||
import {
|
||||
StyleSheet,
|
||||
View,
|
||||
Text,
|
||||
NativeSyntheticEvent,
|
||||
NativeScrollEvent,
|
||||
BackHandler,
|
||||
@@ -13,6 +12,7 @@ import {
|
||||
HelperText,
|
||||
Menu,
|
||||
Searchbar,
|
||||
Text,
|
||||
TouchableRipple,
|
||||
useTheme,
|
||||
} from 'react-native-paper';
|
||||
@@ -48,14 +48,13 @@ const tagsStyles = StyleSheet.create({
|
||||
height: 50,
|
||||
},
|
||||
tagRow: {
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'space-between',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingVertical: 10,
|
||||
paddingHorizontal: 15,
|
||||
},
|
||||
tagView: {
|
||||
tagChip: {
|
||||
flexShrink: 1,
|
||||
maxWidth: '80%',
|
||||
},
|
||||
@@ -195,6 +194,7 @@ const Tags = () => {
|
||||
<FlashList
|
||||
ref={flashListRef}
|
||||
data={tags}
|
||||
keyExtractor={tag => tag.id.toHexString()}
|
||||
estimatedItemSize={52}
|
||||
showsVerticalScrollIndicator={false}
|
||||
renderItem={({ item: tag }) => (
|
||||
@@ -203,9 +203,7 @@ const Tags = () => {
|
||||
navigate(ROUTE.EDIT_TAG, { id: tag.id.toHexString() })
|
||||
}>
|
||||
<View style={tagsStyles.tagRow}>
|
||||
<View style={tagsStyles.tagView}>
|
||||
<TagChip tag={tag} />
|
||||
</View>
|
||||
<TagChip tag={tag} style={tagsStyles.tagChip} />
|
||||
<Text>{tag.memesLength}</Text>
|
||||
</View>
|
||||
</TouchableRipple>
|
||||
|
Reference in New Issue
Block a user