Add tag editing
Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
@@ -107,7 +107,8 @@
|
|||||||
"unicorn/expiring-todo-comments": "off",
|
"unicorn/expiring-todo-comments": "off",
|
||||||
"unicorn/no-array-for-each": "off",
|
"unicorn/no-array-for-each": "off",
|
||||||
"unicorn/filename-case": ["error", { "case": "camelCase" }],
|
"unicorn/filename-case": ["error", { "case": "camelCase" }],
|
||||||
"unicorn/numeric-separators-style": "off"
|
"unicorn/numeric-separators-style": "off",
|
||||||
|
"unicorn/prevent-abbreviations": "off"
|
||||||
},
|
},
|
||||||
"ignorePatterns": ["*.config.js"]
|
"ignorePatterns": ["*.config.js"]
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,7 @@ import { FAB } from 'react-native-paper';
|
|||||||
import { ParamListBase, useNavigation } from '@react-navigation/native';
|
import { ParamListBase, useNavigation } from '@react-navigation/native';
|
||||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||||
import { useDimensions } from '../contexts';
|
import { useDimensions } from '../contexts';
|
||||||
|
import { ROUTE } from '../types';
|
||||||
|
|
||||||
const FloatingActionButton = ({ visible = true }: { visible?: boolean }) => {
|
const FloatingActionButton = ({ visible = true }: { visible?: boolean }) => {
|
||||||
const { navigate } =
|
const { navigate } =
|
||||||
@@ -38,22 +39,22 @@ const FloatingActionButton = ({ visible = true }: { visible?: boolean }) => {
|
|||||||
{
|
{
|
||||||
icon: 'tag',
|
icon: 'tag',
|
||||||
label: 'Tag',
|
label: 'Tag',
|
||||||
onPress: () => navigate('Add Tag'),
|
onPress: () => navigate(ROUTE.EDIT_TAG),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'note-text',
|
icon: 'note-text',
|
||||||
label: 'Text',
|
label: 'Text',
|
||||||
onPress: () => navigate('Add Meme'),
|
onPress: () => navigate(ROUTE.EDIT_MEME),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'image-album',
|
icon: 'image-album',
|
||||||
label: 'Album',
|
label: 'Album',
|
||||||
onPress: () => navigate('Add Meme'),
|
onPress: () => navigate(ROUTE.EDIT_MEME),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
onStateChange={({ open }) => setState(open)}
|
onStateChange={({ open }) => setState(open)}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
if (state) navigate('Add Meme');
|
if (state) navigate(ROUTE.EDIT_MEME);
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
paddingBottom: responsive.verticalScale(75),
|
paddingBottom: responsive.verticalScale(75),
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
import { Realm } from '@realm/react';
|
import { Realm } from '@realm/react';
|
||||||
|
import { BSON } from 'realm';
|
||||||
import { Tag } from './tag';
|
import { Tag } from './tag';
|
||||||
|
|
||||||
enum MEME_TYPE {
|
enum MEME_TYPE {
|
||||||
@@ -20,7 +21,7 @@ const memeTypePlural = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class Meme extends Realm.Object<Meme> {
|
class Meme extends Realm.Object<Meme> {
|
||||||
id!: Realm.BSON.UUID;
|
id!: BSON.UUID;
|
||||||
type!: MEME_TYPE;
|
type!: MEME_TYPE;
|
||||||
uri!: Realm.List<string>;
|
uri!: Realm.List<string>;
|
||||||
size!: number;
|
size!: number;
|
||||||
@@ -38,7 +39,7 @@ class Meme extends Realm.Object<Meme> {
|
|||||||
name: 'Meme',
|
name: 'Meme',
|
||||||
primaryKey: 'id',
|
primaryKey: 'id',
|
||||||
properties: {
|
properties: {
|
||||||
id: 'uuid',
|
id: { type: 'uuid', default: () => new BSON.UUID() },
|
||||||
type: { type: 'string', indexed: true },
|
type: { type: 'string', indexed: true },
|
||||||
uri: 'string[]',
|
uri: 'string[]',
|
||||||
size: 'int',
|
size: 'int',
|
||||||
@@ -47,8 +48,8 @@ class Meme extends Realm.Object<Meme> {
|
|||||||
isFavorite: { type: 'bool', indexed: true, default: false },
|
isFavorite: { type: 'bool', indexed: true, default: false },
|
||||||
tags: { type: 'list', objectType: 'Tag', default: [] },
|
tags: { type: 'list', objectType: 'Tag', default: [] },
|
||||||
tagsLength: { type: 'int', default: 0 },
|
tagsLength: { type: 'int', default: 0 },
|
||||||
dateCreated: { type: 'date', default: new Date() },
|
dateCreated: { type: 'date', default: () => new Date() },
|
||||||
dateModified: { type: 'date', default: new Date() },
|
dateModified: { type: 'date', default: () => new Date() },
|
||||||
dateUsed: 'date?',
|
dateUsed: 'date?',
|
||||||
timesUsed: { type: 'int', default: 0 },
|
timesUsed: { type: 'int', default: 0 },
|
||||||
},
|
},
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
import { Realm } from '@realm/react';
|
import { Realm } from '@realm/react';
|
||||||
|
import { BSON } from 'realm';
|
||||||
import { Meme } from './meme';
|
import { Meme } from './meme';
|
||||||
|
|
||||||
class Tag extends Realm.Object<Tag> {
|
class Tag extends Realm.Object<Tag> {
|
||||||
id!: Realm.BSON.UUID;
|
id!: BSON.UUID;
|
||||||
name!: string;
|
name!: string;
|
||||||
color!: string;
|
color!: string;
|
||||||
memes!: Realm.List<Meme>;
|
memes!: Realm.List<Meme>;
|
||||||
@@ -15,13 +16,13 @@ class Tag extends Realm.Object<Tag> {
|
|||||||
name: 'Tag',
|
name: 'Tag',
|
||||||
primaryKey: 'id',
|
primaryKey: 'id',
|
||||||
properties: {
|
properties: {
|
||||||
id: 'uuid',
|
id: { type: 'uuid', default: () => new BSON.UUID() },
|
||||||
name: { type: 'string', indexed: true },
|
name: { type: 'string', indexed: true },
|
||||||
color: 'string',
|
color: 'string',
|
||||||
memes: { type: 'list', objectType: 'Meme', default: [] },
|
memes: { type: 'list', objectType: 'Meme', default: [] },
|
||||||
memesLength: { type: 'int', default: 0 },
|
memesLength: { type: 'int', default: 0 },
|
||||||
dateCreated: { type: 'date', default: new Date() },
|
dateCreated: { type: 'date', default: () => new Date() },
|
||||||
dateModified: { type: 'date', default: new Date() },
|
dateModified: { type: 'date', default: () => new Date() },
|
||||||
timesUsed: { type: 'int', default: 0 },
|
timesUsed: { type: 'int', default: 0 },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@@ -5,13 +5,13 @@ import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
|
|||||||
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
||||||
import { useTheme } from 'react-native-paper';
|
import { useTheme } from 'react-native-paper';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { Home, Tags, Settings, AddMeme, AddTag } from './screens';
|
import { Home, Tags, Settings, EditMeme, EditTag } from './screens';
|
||||||
import { darkNavigationTheme, lightNavigationTheme } from './theme';
|
import { darkNavigationTheme, lightNavigationTheme } from './theme';
|
||||||
import {
|
import {
|
||||||
FloatingActionButton,
|
FloatingActionButton,
|
||||||
HideableBottomNavigationBar,
|
HideableBottomNavigationBar,
|
||||||
} from './components';
|
} from './components';
|
||||||
import { ROUTE } from './types';
|
import { ROUTE, RootStackParamList } from './types';
|
||||||
import { RootState } from './state';
|
import { RootState } from './state';
|
||||||
|
|
||||||
const TabNavigator = () => {
|
const TabNavigator = () => {
|
||||||
@@ -73,7 +73,7 @@ const TabNavigator = () => {
|
|||||||
|
|
||||||
const NavigationContainer = () => {
|
const NavigationContainer = () => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const StackNavigatorBase = createNativeStackNavigator();
|
const StackNavigatorBase = createNativeStackNavigator<RootStackParamList>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavigationContainerBase
|
<NavigationContainerBase
|
||||||
@@ -85,8 +85,11 @@ const NavigationContainer = () => {
|
|||||||
animation: 'slide_from_bottom',
|
animation: 'slide_from_bottom',
|
||||||
}}>
|
}}>
|
||||||
<StackNavigatorBase.Screen name={ROUTE.MAIN} component={TabNavigator} />
|
<StackNavigatorBase.Screen name={ROUTE.MAIN} component={TabNavigator} />
|
||||||
<StackNavigatorBase.Screen name={ROUTE.ADD_MEME} component={AddMeme} />
|
<StackNavigatorBase.Screen
|
||||||
<StackNavigatorBase.Screen name={ROUTE.ADD_TAG} component={AddTag} />
|
name={ROUTE.EDIT_MEME}
|
||||||
|
component={EditMeme}
|
||||||
|
/>
|
||||||
|
<StackNavigatorBase.Screen name={ROUTE.EDIT_TAG} component={EditTag} />
|
||||||
</StackNavigatorBase.Navigator>
|
</StackNavigatorBase.Navigator>
|
||||||
</NavigationContainerBase>
|
</NavigationContainerBase>
|
||||||
);
|
);
|
||||||
|
@@ -5,7 +5,7 @@ import { useDimensions } from '../contexts';
|
|||||||
import { ScrollView } from 'react-native';
|
import { ScrollView } from 'react-native';
|
||||||
import styles from '../styles';
|
import styles from '../styles';
|
||||||
|
|
||||||
const AddMeme = () => {
|
const EditMeme = () => {
|
||||||
const navigation = useNavigation();
|
const navigation = useNavigation();
|
||||||
const { colors } = useTheme();
|
const { colors } = useTheme();
|
||||||
const { orientation } = useDimensions();
|
const { orientation } = useDimensions();
|
||||||
@@ -32,4 +32,4 @@ const AddMeme = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AddMeme;
|
export default EditMeme;
|
@@ -8,21 +8,31 @@ import {
|
|||||||
useTheme,
|
useTheme,
|
||||||
} from 'react-native-paper';
|
} from 'react-native-paper';
|
||||||
import { useNavigation } from '@react-navigation/native';
|
import { useNavigation } from '@react-navigation/native';
|
||||||
import { BSON } from 'realm';
|
import { NativeStackScreenProps } from '@react-navigation/native-stack';
|
||||||
|
import { BSON, UpdateMode } from 'realm';
|
||||||
import { useRealm } from '@realm/react';
|
import { useRealm } from '@realm/react';
|
||||||
import { TagPreview } from '../components';
|
import { TagPreview } from '../components';
|
||||||
import styles from '../styles';
|
import styles from '../styles';
|
||||||
import { generateRandomColor, isValidColor } from '../utilities';
|
import { generateRandomColor, isValidColor } from '../utilities';
|
||||||
import { useDimensions } from '../contexts';
|
import { useDimensions } from '../contexts';
|
||||||
|
import { ROUTE, RootStackParamList } from '../types';
|
||||||
|
import { Tag } from '../database';
|
||||||
|
|
||||||
const AddTag = () => {
|
const EditTag = ({
|
||||||
|
route,
|
||||||
|
}: NativeStackScreenProps<RootStackParamList, ROUTE.EDIT_TAG>) => {
|
||||||
const navigation = useNavigation();
|
const navigation = useNavigation();
|
||||||
const { colors } = useTheme();
|
const { colors } = useTheme();
|
||||||
const { orientation } = useDimensions();
|
const { orientation } = useDimensions();
|
||||||
const realm = useRealm();
|
const realm = useRealm();
|
||||||
|
|
||||||
const [tagName, setTagName] = useState('newTag');
|
const tagId = route.params?.id;
|
||||||
const [tagColor, setTagColor] = useState(generateRandomColor());
|
const tag = tagId
|
||||||
|
? realm.objectForPrimaryKey(Tag, BSON.UUID.createFromHexString(tagId))
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const [tagName, setTagName] = useState(tag?.name ?? 'newTag');
|
||||||
|
const [tagColor, setTagColor] = useState(tag?.color ?? generateRandomColor());
|
||||||
const [validatedTagColor, setValidatedTagColor] = useState(tagColor);
|
const [validatedTagColor, setValidatedTagColor] = useState(tagColor);
|
||||||
|
|
||||||
const [tagNameError, setTagNameError] = useState<string | undefined>();
|
const [tagNameError, setTagNameError] = useState<string | undefined>();
|
||||||
@@ -55,11 +65,22 @@ const AddTag = () => {
|
|||||||
|
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
realm.write(() => {
|
realm.write(() => {
|
||||||
realm.create('Tag', {
|
realm.create(
|
||||||
id: new BSON.UUID(),
|
Tag,
|
||||||
name: tagName,
|
{
|
||||||
color: tagColor,
|
id: tag?.id,
|
||||||
});
|
name: tagName,
|
||||||
|
color: tagColor,
|
||||||
|
},
|
||||||
|
UpdateMode.Modified,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
navigation.goBack();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelete = () => {
|
||||||
|
realm.write(() => {
|
||||||
|
realm.delete(tag);
|
||||||
});
|
});
|
||||||
navigation.goBack();
|
navigation.goBack();
|
||||||
};
|
};
|
||||||
@@ -68,7 +89,8 @@ const AddTag = () => {
|
|||||||
<>
|
<>
|
||||||
<Appbar.Header>
|
<Appbar.Header>
|
||||||
<Appbar.BackAction onPress={() => navigation.goBack()} />
|
<Appbar.BackAction onPress={() => navigation.goBack()} />
|
||||||
<Appbar.Content title="Add Tag" />
|
<Appbar.Content title={tag ? 'Edit Tag' : 'Add Tag'} />
|
||||||
|
{tag && <Appbar.Action icon="delete" onPress={handleDelete} />}
|
||||||
</Appbar.Header>
|
</Appbar.Header>
|
||||||
<ScrollView
|
<ScrollView
|
||||||
contentContainerStyle={[
|
contentContainerStyle={[
|
||||||
@@ -126,4 +148,4 @@ const AddTag = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AddTag;
|
export default EditTag;
|
@@ -1,5 +1,5 @@
|
|||||||
export { default as AddMeme } from './addMeme';
|
export { default as EditMeme } from './editMeme';
|
||||||
export { default as AddTag } from './addTag';
|
export { default as EditTag } from './editTag';
|
||||||
export { default as Home } from './home';
|
export { default as Home } from './home';
|
||||||
export { default as Settings } from './settings';
|
export { default as Settings } from './settings';
|
||||||
export { default as Tags } from './tags';
|
export { default as Tags } from './tags';
|
||||||
|
@@ -16,11 +16,11 @@ import {
|
|||||||
TouchableRipple,
|
TouchableRipple,
|
||||||
useTheme,
|
useTheme,
|
||||||
} from 'react-native-paper';
|
} from 'react-native-paper';
|
||||||
import { useQuery, useRealm } from '@realm/react';
|
import { useQuery } from '@realm/react';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { FlashList } from '@shopify/flash-list';
|
import { FlashList } from '@shopify/flash-list';
|
||||||
import { TagChip } from '../components';
|
import { TagChip } from '../components';
|
||||||
import { Tag, deleteTag } from '../database';
|
import { Tag } from '../database';
|
||||||
import styles from '../styles';
|
import styles from '../styles';
|
||||||
import {
|
import {
|
||||||
RootState,
|
RootState,
|
||||||
@@ -29,9 +29,16 @@ import {
|
|||||||
setTagsSortDirection,
|
setTagsSortDirection,
|
||||||
toggleTagsSortDirection,
|
toggleTagsSortDirection,
|
||||||
} from '../state';
|
} from '../state';
|
||||||
import { SORT_DIRECTION, TAG_SORT, tagSortQuery } from '../types';
|
import {
|
||||||
|
ROUTE,
|
||||||
|
RootStackParamList,
|
||||||
|
SORT_DIRECTION,
|
||||||
|
TAG_SORT,
|
||||||
|
tagSortQuery,
|
||||||
|
} from '../types';
|
||||||
import { getSortIcon } from '../utilities';
|
import { getSortIcon } from '../utilities';
|
||||||
import { useDimensions } from '../contexts';
|
import { useDimensions } from '../contexts';
|
||||||
|
import { NavigationProp, useNavigation } from '@react-navigation/native';
|
||||||
|
|
||||||
const tagsStyles = StyleSheet.create({
|
const tagsStyles = StyleSheet.create({
|
||||||
headerView: {
|
headerView: {
|
||||||
@@ -68,7 +75,7 @@ const tagsStyles = StyleSheet.create({
|
|||||||
const Tags = () => {
|
const Tags = () => {
|
||||||
const { colors } = useTheme();
|
const { colors } = useTheme();
|
||||||
const { orientation } = useDimensions();
|
const { orientation } = useDimensions();
|
||||||
const realm = useRealm();
|
const navigation = useNavigation<NavigationProp<RootStackParamList>>();
|
||||||
const sort = useSelector((state: RootState) => state.tags.sort);
|
const sort = useSelector((state: RootState) => state.tags.sort);
|
||||||
const sortDirection = useSelector(
|
const sortDirection = useSelector(
|
||||||
(state: RootState) => state.tags.sortDirection,
|
(state: RootState) => state.tags.sortDirection,
|
||||||
@@ -208,7 +215,10 @@ const Tags = () => {
|
|||||||
estimatedItemSize={52}
|
estimatedItemSize={52}
|
||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
renderItem={({ item: tag }) => (
|
renderItem={({ item: tag }) => (
|
||||||
<TouchableRipple onPress={() => deleteTag(realm, tag)}>
|
<TouchableRipple
|
||||||
|
onPress={() =>
|
||||||
|
navigation.navigate(ROUTE.EDIT_TAG, { id: tag.id.toHexString() })
|
||||||
|
}>
|
||||||
<View style={tagsStyles.tagRow}>
|
<View style={tagsStyles.tagRow}>
|
||||||
<View style={tagsStyles.tagView}>
|
<View style={tagsStyles.tagView}>
|
||||||
<TagChip tag={tag} />
|
<TagChip tag={tag} />
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
export { ROUTE } from './route';
|
export { ROUTE, type RootStackParamList } from './route';
|
||||||
export {
|
export {
|
||||||
MEME_SORT,
|
MEME_SORT,
|
||||||
homeSortQuery,
|
homeSortQuery,
|
||||||
|
@@ -3,7 +3,19 @@ enum ROUTE {
|
|||||||
HOME = 'Home',
|
HOME = 'Home',
|
||||||
TAGS = 'Tags',
|
TAGS = 'Tags',
|
||||||
SETTINGS = 'Settings',
|
SETTINGS = 'Settings',
|
||||||
ADD_MEME = 'Add Meme',
|
EDIT_MEME = 'Edit Meme',
|
||||||
ADD_TAG = 'Add Tag',
|
EDIT_TAG = 'Edit Tag',
|
||||||
}
|
}
|
||||||
export { ROUTE };
|
|
||||||
|
interface EditTagRouteParams {
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RootStackParamList {
|
||||||
|
[key: string]: undefined | EditTagRouteParams;
|
||||||
|
[ROUTE.MAIN]: undefined;
|
||||||
|
[ROUTE.EDIT_MEME]: undefined;
|
||||||
|
[ROUTE.EDIT_TAG]: EditTagRouteParams | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { ROUTE, type RootStackParamList };
|
||||||
|
Reference in New Issue
Block a user