Add tag sorting
Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
@@ -52,7 +52,7 @@
|
|||||||
"no-console": "warn",
|
"no-console": "warn",
|
||||||
"react/jsx-filename-extension": [
|
"react/jsx-filename-extension": [
|
||||||
"warn",
|
"warn",
|
||||||
{"extensions": [".js", ".jsx", ".ts", ".tsx"]}
|
{ "extensions": [".js", ".jsx", ".ts", ".tsx"] }
|
||||||
],
|
],
|
||||||
"react/jsx-props-no-spreading": "off",
|
"react/jsx-props-no-spreading": "off",
|
||||||
"react-native/no-unused-styles": "error",
|
"react-native/no-unused-styles": "error",
|
||||||
@@ -106,7 +106,7 @@
|
|||||||
"unicorn/empty-brace-spaces": "off",
|
"unicorn/empty-brace-spaces": "off",
|
||||||
"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"
|
||||||
},
|
},
|
||||||
"ignorePatterns": ["*.config.js"]
|
"ignorePatterns": ["*.config.js"]
|
||||||
|
14
package-lock.json
generated
14
package-lock.json
generated
@@ -29,7 +29,7 @@
|
|||||||
"react-native-safe-area-context": "^4.6.4",
|
"react-native-safe-area-context": "^4.6.4",
|
||||||
"react-native-scoped-storage": "^1.9.3",
|
"react-native-scoped-storage": "^1.9.3",
|
||||||
"react-native-screens": "^3.22.1",
|
"react-native-screens": "^3.22.1",
|
||||||
"react-native-share": "^9.2.2",
|
"react-native-share": "^9.2.3",
|
||||||
"react-native-vector-icons": "^9.2.0",
|
"react-native-vector-icons": "^9.2.0",
|
||||||
"react-native-video": "^5.2.1",
|
"react-native-video": "^5.2.1",
|
||||||
"react-redux": "^8.1.1",
|
"react-redux": "^8.1.1",
|
||||||
@@ -13500,9 +13500,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-native-share": {
|
"node_modules/react-native-share": {
|
||||||
"version": "9.2.2",
|
"version": "9.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-native-share/-/react-native-share-9.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-share/-/react-native-share-9.2.3.tgz",
|
||||||
"integrity": "sha512-z99dvVuSvVfQ7VwrO+JWdfurAgDpkMvdZYmqIDG9HX8RHXIqU6oNVx2ePuNWXn4UgySyFjMUKjGv99njM0934Q=="
|
"integrity": "sha512-y6ju4HS6ydJoPVoacZ/Hp3i47AfI9W4e76Jv00r01dVbr6SCCcuqk37kIbn+kYivdTxOW77UGEbhtBHHtXnhzg=="
|
||||||
},
|
},
|
||||||
"node_modules/react-native-vector-icons": {
|
"node_modules/react-native-vector-icons": {
|
||||||
"version": "9.2.0",
|
"version": "9.2.0",
|
||||||
@@ -25846,9 +25846,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-native-share": {
|
"react-native-share": {
|
||||||
"version": "9.2.2",
|
"version": "9.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-native-share/-/react-native-share-9.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-share/-/react-native-share-9.2.3.tgz",
|
||||||
"integrity": "sha512-z99dvVuSvVfQ7VwrO+JWdfurAgDpkMvdZYmqIDG9HX8RHXIqU6oNVx2ePuNWXn4UgySyFjMUKjGv99njM0934Q=="
|
"integrity": "sha512-y6ju4HS6ydJoPVoacZ/Hp3i47AfI9W4e76Jv00r01dVbr6SCCcuqk37kIbn+kYivdTxOW77UGEbhtBHHtXnhzg=="
|
||||||
},
|
},
|
||||||
"react-native-vector-icons": {
|
"react-native-vector-icons": {
|
||||||
"version": "9.2.0",
|
"version": "9.2.0",
|
||||||
|
@@ -34,7 +34,7 @@
|
|||||||
"react-native-safe-area-context": "^4.6.4",
|
"react-native-safe-area-context": "^4.6.4",
|
||||||
"react-native-scoped-storage": "^1.9.3",
|
"react-native-scoped-storage": "^1.9.3",
|
||||||
"react-native-screens": "^3.22.1",
|
"react-native-screens": "^3.22.1",
|
||||||
"react-native-share": "^9.2.2",
|
"react-native-share": "^9.2.3",
|
||||||
"react-native-vector-icons": "^9.2.0",
|
"react-native-vector-icons": "^9.2.0",
|
||||||
"react-native-video": "^5.2.1",
|
"react-native-video": "^5.2.1",
|
||||||
"react-redux": "^8.1.1",
|
"react-redux": "^8.1.1",
|
||||||
|
@@ -28,6 +28,7 @@ class Meme extends Realm.Object<Meme> {
|
|||||||
description?: string;
|
description?: string;
|
||||||
isFavorite!: boolean;
|
isFavorite!: boolean;
|
||||||
tags!: Realm.List<Tag>;
|
tags!: Realm.List<Tag>;
|
||||||
|
tagsLength!: number;
|
||||||
dateCreated!: Date;
|
dateCreated!: Date;
|
||||||
dateModified!: Date;
|
dateModified!: Date;
|
||||||
dateUsed?: Date;
|
dateUsed?: Date;
|
||||||
@@ -45,6 +46,7 @@ class Meme extends Realm.Object<Meme> {
|
|||||||
description: 'string?',
|
description: 'string?',
|
||||||
isFavorite: { type: 'bool', indexed: true, default: false },
|
isFavorite: { type: 'bool', indexed: true, default: false },
|
||||||
tags: 'Tag[]',
|
tags: 'Tag[]',
|
||||||
|
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?',
|
||||||
|
@@ -6,9 +6,9 @@ class Tag extends Realm.Object<Tag> {
|
|||||||
name!: string;
|
name!: string;
|
||||||
color!: string;
|
color!: string;
|
||||||
memes!: Realm.List<Meme>;
|
memes!: Realm.List<Meme>;
|
||||||
|
memesLength!: number;
|
||||||
dateCreated!: Date;
|
dateCreated!: Date;
|
||||||
dateModified!: Date;
|
dateModified!: Date;
|
||||||
dateUsed?: Date;
|
|
||||||
timesUsed!: number;
|
timesUsed!: number;
|
||||||
|
|
||||||
static schema: Realm.ObjectSchema = {
|
static schema: Realm.ObjectSchema = {
|
||||||
@@ -19,9 +19,9 @@ class Tag extends Realm.Object<Tag> {
|
|||||||
name: 'string',
|
name: 'string',
|
||||||
color: 'string',
|
color: 'string',
|
||||||
memes: 'Meme[]',
|
memes: 'Meme[]',
|
||||||
|
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() },
|
||||||
dateUsed: 'date?',
|
|
||||||
timesUsed: { type: 'int', default: 0 },
|
timesUsed: { type: 'int', default: 0 },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { View } from 'react-native';
|
import { StyleSheet, View } from 'react-native';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Menu,
|
Menu,
|
||||||
@@ -7,22 +7,33 @@ import {
|
|||||||
Divider,
|
Divider,
|
||||||
useTheme,
|
useTheme,
|
||||||
Searchbar,
|
Searchbar,
|
||||||
|
HelperText,
|
||||||
} from 'react-native-paper';
|
} from 'react-native-paper';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { RootScrollView } from '../components';
|
import { RootScrollView } from '../components';
|
||||||
import styles from '../styles';
|
import styles from '../styles';
|
||||||
import { SORT, SORT_DIRECTION } from '../types';
|
import { HOME_SORT, SORT_DIRECTION } from '../types';
|
||||||
import { getSortIcon, getViewIcon } from '../utilities';
|
import { getSortIcon, getViewIcon } from '../utilities';
|
||||||
import {
|
import {
|
||||||
RootState,
|
RootState,
|
||||||
cycleView,
|
cycleHomeView,
|
||||||
toggleSortDirection,
|
toggleHomeSortDirection,
|
||||||
setSortDirection,
|
setHomeSortDirection,
|
||||||
toggleFavoritesOnly,
|
toggleHomeFavoritesOnly,
|
||||||
setSort,
|
setHomeSort,
|
||||||
setFilter,
|
setHomeFilter,
|
||||||
} from '../state';
|
} from '../state';
|
||||||
import { MEME_TYPE, memeTypePlural } from '../database';
|
import { MEME_TYPE, Meme, memeTypePlural } from '../database';
|
||||||
|
import { useQuery } from '@realm/react';
|
||||||
|
|
||||||
|
const homeStyles = StyleSheet.create({
|
||||||
|
headerButtonView: {
|
||||||
|
height: 50,
|
||||||
|
},
|
||||||
|
helperText: {
|
||||||
|
marginVertical: 10,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const Home = () => {
|
const Home = () => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
@@ -40,26 +51,27 @@ const Home = () => {
|
|||||||
const [sortMenuVisible, setSortMenuVisible] = useState(false);
|
const [sortMenuVisible, setSortMenuVisible] = useState(false);
|
||||||
const [filterMenuVisible, setFilterMenuVisible] = useState(false);
|
const [filterMenuVisible, setFilterMenuVisible] = useState(false);
|
||||||
|
|
||||||
const handleSortModeChange = (newSort: SORT) => {
|
const handleSortModeChange = (newSort: HOME_SORT) => {
|
||||||
if (newSort === sort) {
|
if (newSort === sort) {
|
||||||
dispatch(toggleSortDirection());
|
dispatch(toggleHomeSortDirection());
|
||||||
} else {
|
} else {
|
||||||
dispatch(setSort(newSort));
|
dispatch(setHomeSort(newSort));
|
||||||
if (newSort === SORT.TITLE) {
|
if (newSort === HOME_SORT.TITLE) {
|
||||||
dispatch(setSortDirection(SORT_DIRECTION.ASCENDING));
|
dispatch(setHomeSortDirection(SORT_DIRECTION.ASCENDING));
|
||||||
} else {
|
} else {
|
||||||
dispatch(setSortDirection(SORT_DIRECTION.DESCENDING));
|
dispatch(setHomeSortDirection(SORT_DIRECTION.DESCENDING));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setSortMenuVisible(false);
|
setSortMenuVisible(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFilterChange = (newFilter: MEME_TYPE | undefined) => {
|
const handleFilterChange = (newFilter: MEME_TYPE | undefined) => {
|
||||||
dispatch(setFilter(newFilter));
|
dispatch(setHomeFilter(newFilter));
|
||||||
setFilterMenuVisible(false);
|
setFilterMenuVisible(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
|
const memes = useQuery<Meme>('Meme');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RootScrollView padded>
|
<RootScrollView padded>
|
||||||
@@ -68,7 +80,12 @@ const Home = () => {
|
|||||||
value={search}
|
value={search}
|
||||||
onChangeText={setSearch}
|
onChangeText={setSearch}
|
||||||
/>
|
/>
|
||||||
<View style={[styles.flexRowSpaceBetween, styles.alignCenter]}>
|
<View
|
||||||
|
style={[
|
||||||
|
styles.flexRowSpaceBetween,
|
||||||
|
styles.alignCenter,
|
||||||
|
homeStyles.headerButtonView,
|
||||||
|
]}>
|
||||||
<View style={[styles.flexRow, styles.alignCenter]}>
|
<View style={[styles.flexRow, styles.alignCenter]}>
|
||||||
<Menu
|
<Menu
|
||||||
visible={sortMenuVisible}
|
visible={sortMenuVisible}
|
||||||
@@ -82,31 +99,33 @@ const Home = () => {
|
|||||||
Sort By: {sort}
|
Sort By: {sort}
|
||||||
</Button>
|
</Button>
|
||||||
}>
|
}>
|
||||||
{Object.keys(SORT).map(key => {
|
{Object.keys(HOME_SORT).map(key => {
|
||||||
return (
|
return (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
key={key}
|
key={key}
|
||||||
onPress={() =>
|
onPress={() =>
|
||||||
handleSortModeChange(SORT[key as keyof typeof SORT])
|
handleSortModeChange(
|
||||||
|
HOME_SORT[key as keyof typeof HOME_SORT],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
title={SORT[key as keyof typeof SORT]}
|
title={HOME_SORT[key as keyof typeof HOME_SORT]}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</Menu>
|
</Menu>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.flexRow}>
|
<View style={[styles.flexRow, styles.alignCenter]}>
|
||||||
<IconButton
|
<IconButton
|
||||||
icon={getViewIcon(view)}
|
icon={getViewIcon(view)}
|
||||||
iconColor={theme.colors.primary}
|
iconColor={theme.colors.primary}
|
||||||
size={18}
|
size={16}
|
||||||
onPress={() => dispatch(cycleView())}
|
onPress={() => dispatch(cycleHomeView())}
|
||||||
/>
|
/>
|
||||||
<IconButton
|
<IconButton
|
||||||
icon={favoritesOnly ? 'heart' : 'heart-outline'}
|
icon={favoritesOnly ? 'heart' : 'heart-outline'}
|
||||||
iconColor={theme.colors.primary}
|
iconColor={theme.colors.primary}
|
||||||
size={18}
|
size={16}
|
||||||
onPress={() => dispatch(toggleFavoritesOnly())}
|
onPress={() => dispatch(toggleHomeFavoritesOnly())}
|
||||||
/>
|
/>
|
||||||
<Menu
|
<Menu
|
||||||
visible={filterMenuVisible}
|
visible={filterMenuVisible}
|
||||||
@@ -116,7 +135,7 @@ const Home = () => {
|
|||||||
onPress={() => setFilterMenuVisible(true)}
|
onPress={() => setFilterMenuVisible(true)}
|
||||||
icon={filter ? 'filter' : 'filter-outline'}
|
icon={filter ? 'filter' : 'filter-outline'}
|
||||||
iconColor={theme.colors.primary}
|
iconColor={theme.colors.primary}
|
||||||
size={18}
|
size={16}
|
||||||
/>
|
/>
|
||||||
}>
|
}>
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
@@ -141,6 +160,14 @@ const Home = () => {
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<Divider />
|
<Divider />
|
||||||
|
{/* TODO: Meme Views */}
|
||||||
|
{memes.length === 0 && (
|
||||||
|
<View style={styles.alignCenter}>
|
||||||
|
<HelperText type={'info'} style={homeStyles.helperText}>
|
||||||
|
No memes found
|
||||||
|
</HelperText>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
</RootScrollView>
|
</RootScrollView>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -1,16 +1,35 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { DataTable, HelperText, Searchbar } from 'react-native-paper';
|
import { StyleSheet, View } from 'react-native';
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
DataTable,
|
||||||
|
Divider,
|
||||||
|
HelperText,
|
||||||
|
Menu,
|
||||||
|
Searchbar,
|
||||||
|
} from 'react-native-paper';
|
||||||
import { useQuery, useRealm } from '@realm/react';
|
import { useQuery, useRealm } from '@realm/react';
|
||||||
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { RootScrollView, TagChip } from '../components';
|
import { RootScrollView, TagChip } from '../components';
|
||||||
import { Tag, deleteTag } from '../database';
|
import { Tag, deleteTag } from '../database';
|
||||||
import { StyleSheet, View } from 'react-native';
|
|
||||||
import styles from '../styles';
|
import styles from '../styles';
|
||||||
|
import {
|
||||||
|
RootState,
|
||||||
|
setTagsSort,
|
||||||
|
setTagsSortDirection,
|
||||||
|
toggleTagsSortDirection,
|
||||||
|
} from '../state';
|
||||||
|
import { SORT_DIRECTION, TAG_SORT, tagSortQuery } from '../types';
|
||||||
|
import { getSortIcon } from '../utilities';
|
||||||
|
|
||||||
const tagStyles = StyleSheet.create({
|
const tagStyles = StyleSheet.create({
|
||||||
|
headerButtonView: {
|
||||||
|
height: 50,
|
||||||
|
},
|
||||||
helperText: {
|
helperText: {
|
||||||
marginVertical: 10,
|
marginVertical: 10,
|
||||||
},
|
},
|
||||||
view: {
|
tagView: {
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
maxWidth: '75%',
|
maxWidth: '75%',
|
||||||
},
|
},
|
||||||
@@ -18,37 +37,90 @@ const tagStyles = StyleSheet.create({
|
|||||||
|
|
||||||
const Tags = () => {
|
const Tags = () => {
|
||||||
const realm = useRealm();
|
const realm = useRealm();
|
||||||
|
const sort = useSelector((state: RootState) => state.tags.sort);
|
||||||
|
const sortDirection = useSelector(
|
||||||
|
(state: RootState) => state.tags.sortDirection,
|
||||||
|
);
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const [sortMenuVisible, setSortMenuVisible] = useState(false);
|
||||||
|
|
||||||
|
const handleSortModeChange = (newSort: TAG_SORT) => {
|
||||||
|
if (newSort === sort) {
|
||||||
|
dispatch(toggleTagsSortDirection());
|
||||||
|
} else {
|
||||||
|
dispatch(setTagsSort(newSort));
|
||||||
|
if (newSort === TAG_SORT.NAME) {
|
||||||
|
dispatch(setTagsSortDirection(SORT_DIRECTION.ASCENDING));
|
||||||
|
} else {
|
||||||
|
dispatch(setTagsSortDirection(SORT_DIRECTION.DESCENDING));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setSortMenuVisible(false);
|
||||||
|
};
|
||||||
|
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
const tags = useQuery<Tag>('Tag').filtered(`name CONTAINS[c] "${search}"`);
|
const tags = useQuery<Tag>('Tag')
|
||||||
|
.filtered(`name CONTAINS[c] "${search}"`)
|
||||||
|
.sorted(tagSortQuery(sort), sortDirection === SORT_DIRECTION.ASCENDING);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RootScrollView padded style={styles.alignCenter}>
|
<RootScrollView padded>
|
||||||
<Searchbar
|
<Searchbar
|
||||||
placeholder="Search Tags"
|
placeholder="Search Tags"
|
||||||
value={search}
|
value={search}
|
||||||
onChangeText={setSearch}
|
onChangeText={setSearch}
|
||||||
/>
|
/>
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
styles.flexRow,
|
||||||
|
styles.alignCenter,
|
||||||
|
tagStyles.headerButtonView,
|
||||||
|
]}>
|
||||||
|
<Menu
|
||||||
|
visible={sortMenuVisible}
|
||||||
|
onDismiss={() => setSortMenuVisible(false)}
|
||||||
|
anchor={
|
||||||
|
<Button
|
||||||
|
onPress={() => setSortMenuVisible(true)}
|
||||||
|
icon={getSortIcon(sort, sortDirection)}
|
||||||
|
contentStyle={styles.flexRowReverse}
|
||||||
|
compact>
|
||||||
|
Sort By: {sort}
|
||||||
|
</Button>
|
||||||
|
}>
|
||||||
|
{Object.keys(TAG_SORT).map(key => {
|
||||||
|
return (
|
||||||
|
<Menu.Item
|
||||||
|
key={key}
|
||||||
|
onPress={() =>
|
||||||
|
handleSortModeChange(TAG_SORT[key as keyof typeof TAG_SORT])
|
||||||
|
}
|
||||||
|
title={TAG_SORT[key as keyof typeof TAG_SORT]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Menu>
|
||||||
|
</View>
|
||||||
|
<Divider />
|
||||||
<DataTable>
|
<DataTable>
|
||||||
<DataTable.Header>
|
|
||||||
<DataTable.Title>Tag</DataTable.Title>
|
|
||||||
<DataTable.Title numeric>Items</DataTable.Title>
|
|
||||||
</DataTable.Header>
|
|
||||||
{tags.map(tag => (
|
{tags.map(tag => (
|
||||||
<DataTable.Row
|
<DataTable.Row
|
||||||
key={tag.id.toHexString()}
|
key={tag.id.toHexString()}
|
||||||
onPress={() => deleteTag(realm, tag)}>
|
onPress={() => deleteTag(realm, tag)}>
|
||||||
<View style={tagStyles.view}>
|
<View style={tagStyles.tagView}>
|
||||||
<TagChip tag={tag} />
|
<TagChip tag={tag} />
|
||||||
</View>
|
</View>
|
||||||
<DataTable.Cell numeric>{tag.memes.length}</DataTable.Cell>
|
<DataTable.Cell numeric>{tag.memesLength}</DataTable.Cell>
|
||||||
</DataTable.Row>
|
</DataTable.Row>
|
||||||
))}
|
))}
|
||||||
</DataTable>
|
</DataTable>
|
||||||
{tags.length === 0 && (
|
{tags.length === 0 && (
|
||||||
<HelperText type={'info'} style={tagStyles.helperText}>
|
<View style={styles.alignCenter}>
|
||||||
No tags found
|
<HelperText type={'info'} style={tagStyles.helperText}>
|
||||||
</HelperText>
|
No tags found
|
||||||
|
</HelperText>
|
||||||
|
</View>
|
||||||
)}
|
)}
|
||||||
</RootScrollView>
|
</RootScrollView>
|
||||||
);
|
);
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||||||
import { SORT, SORT_DIRECTION, VIEW } from '../types';
|
import { HOME_SORT, SORT_DIRECTION, VIEW } from '../types';
|
||||||
import { MEME_TYPE } from '../database';
|
import { MEME_TYPE } from '../database';
|
||||||
|
|
||||||
interface HomeState {
|
interface HomeState {
|
||||||
sort: SORT;
|
sort: HOME_SORT;
|
||||||
sortDirection: SORT_DIRECTION;
|
sortDirection: SORT_DIRECTION;
|
||||||
view: VIEW;
|
view: VIEW;
|
||||||
favoritesOnly: boolean;
|
favoritesOnly: boolean;
|
||||||
@@ -11,7 +11,7 @@ interface HomeState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const initialState: HomeState = {
|
const initialState: HomeState = {
|
||||||
sort: SORT.TITLE,
|
sort: HOME_SORT.TITLE,
|
||||||
sortDirection: SORT_DIRECTION.ASCENDING,
|
sortDirection: SORT_DIRECTION.ASCENDING,
|
||||||
view: VIEW.MASONRY,
|
view: VIEW.MASONRY,
|
||||||
favoritesOnly: false,
|
favoritesOnly: false,
|
||||||
@@ -22,19 +22,19 @@ const homeSlice = createSlice({
|
|||||||
name: 'home',
|
name: 'home',
|
||||||
initialState,
|
initialState,
|
||||||
reducers: {
|
reducers: {
|
||||||
setSort: (state, action: PayloadAction<SORT>) => {
|
setHomeSort: (state, action: PayloadAction<HOME_SORT>) => {
|
||||||
state.sort = action.payload;
|
state.sort = action.payload;
|
||||||
},
|
},
|
||||||
setSortDirection: (state, action: PayloadAction<SORT_DIRECTION>) => {
|
setHomeSortDirection: (state, action: PayloadAction<SORT_DIRECTION>) => {
|
||||||
state.sortDirection = action.payload;
|
state.sortDirection = action.payload;
|
||||||
},
|
},
|
||||||
toggleSortDirection: state => {
|
toggleHomeSortDirection: state => {
|
||||||
state.sortDirection ^= 1;
|
state.sortDirection ^= 1;
|
||||||
},
|
},
|
||||||
setView: (state, action: PayloadAction<VIEW>) => {
|
setHomeView: (state, action: PayloadAction<VIEW>) => {
|
||||||
state.view = action.payload;
|
state.view = action.payload;
|
||||||
},
|
},
|
||||||
cycleView: state => {
|
cycleHomeView: state => {
|
||||||
switch (state.view) {
|
switch (state.view) {
|
||||||
case VIEW.MASONRY: {
|
case VIEW.MASONRY: {
|
||||||
state.view = VIEW.GRID;
|
state.view = VIEW.GRID;
|
||||||
@@ -50,38 +50,38 @@ const homeSlice = createSlice({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setFavoritesOnly: (state, action: PayloadAction<boolean>) => {
|
setHomeFavoritesOnly: (state, action: PayloadAction<boolean>) => {
|
||||||
state.favoritesOnly = action.payload;
|
state.favoritesOnly = action.payload;
|
||||||
},
|
},
|
||||||
toggleFavoritesOnly: state => {
|
toggleHomeFavoritesOnly: state => {
|
||||||
state.favoritesOnly = !state.favoritesOnly;
|
state.favoritesOnly = !state.favoritesOnly;
|
||||||
},
|
},
|
||||||
setFilter: (state, action: PayloadAction<MEME_TYPE | undefined>) => {
|
setHomeFilter: (state, action: PayloadAction<MEME_TYPE | undefined>) => {
|
||||||
state.filter = action.payload;
|
state.filter = action.payload;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
setSort,
|
setHomeSort,
|
||||||
setSortDirection,
|
setHomeSortDirection,
|
||||||
toggleSortDirection,
|
toggleHomeSortDirection,
|
||||||
setView,
|
setHomeView,
|
||||||
cycleView,
|
cycleHomeView,
|
||||||
setFavoritesOnly,
|
setHomeFavoritesOnly,
|
||||||
toggleFavoritesOnly,
|
toggleHomeFavoritesOnly,
|
||||||
setFilter,
|
setHomeFilter,
|
||||||
} = homeSlice.actions;
|
} = homeSlice.actions;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
type HomeState,
|
type HomeState,
|
||||||
setSort,
|
setHomeSort,
|
||||||
setSortDirection,
|
setHomeSortDirection,
|
||||||
toggleSortDirection,
|
toggleHomeSortDirection,
|
||||||
setView,
|
setHomeView,
|
||||||
cycleView,
|
cycleHomeView,
|
||||||
setFavoritesOnly,
|
setHomeFavoritesOnly,
|
||||||
toggleFavoritesOnly,
|
toggleHomeFavoritesOnly,
|
||||||
setFilter,
|
setHomeFilter,
|
||||||
};
|
};
|
||||||
export default homeSlice.reducer;
|
export default homeSlice.reducer;
|
||||||
|
@@ -12,15 +12,18 @@ import {
|
|||||||
import { createRealmPersistStorage } from '@bankify/redux-persist-realm';
|
import { createRealmPersistStorage } from '@bankify/redux-persist-realm';
|
||||||
import settingsReducer from './settings';
|
import settingsReducer from './settings';
|
||||||
import homeReducer from './home';
|
import homeReducer from './home';
|
||||||
|
import tagsReducer from './tags';
|
||||||
|
|
||||||
const rootReducer = combineReducers({
|
const rootReducer = combineReducers({
|
||||||
settings: settingsReducer,
|
settings: settingsReducer,
|
||||||
home: homeReducer,
|
home: homeReducer,
|
||||||
|
tags: tagsReducer,
|
||||||
});
|
});
|
||||||
|
|
||||||
interface RootState {
|
interface RootState {
|
||||||
settings: ReturnType<typeof settingsReducer>;
|
settings: ReturnType<typeof settingsReducer>;
|
||||||
home: ReturnType<typeof homeReducer>;
|
home: ReturnType<typeof homeReducer>;
|
||||||
|
tags: ReturnType<typeof tagsReducer>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const persistConfig = {
|
const persistConfig = {
|
||||||
@@ -51,12 +54,18 @@ export {
|
|||||||
} from './settings';
|
} from './settings';
|
||||||
export {
|
export {
|
||||||
type HomeState,
|
type HomeState,
|
||||||
setSort,
|
setHomeSort,
|
||||||
setSortDirection,
|
setHomeSortDirection,
|
||||||
toggleSortDirection,
|
toggleHomeSortDirection,
|
||||||
setView,
|
setHomeView,
|
||||||
cycleView,
|
cycleHomeView,
|
||||||
setFavoritesOnly,
|
setHomeFavoritesOnly,
|
||||||
toggleFavoritesOnly,
|
toggleHomeFavoritesOnly,
|
||||||
setFilter,
|
setHomeFilter,
|
||||||
} from './home';
|
} from './home';
|
||||||
|
export {
|
||||||
|
type TagsState,
|
||||||
|
setTagsSort,
|
||||||
|
setTagsSortDirection,
|
||||||
|
toggleTagsSortDirection,
|
||||||
|
} from './tags';
|
||||||
|
39
src/state/tags.ts
Normal file
39
src/state/tags.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||||||
|
import { TAG_SORT, SORT_DIRECTION } from '../types';
|
||||||
|
|
||||||
|
interface TagsState {
|
||||||
|
sort: TAG_SORT;
|
||||||
|
sortDirection: SORT_DIRECTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: TagsState = {
|
||||||
|
sort: TAG_SORT.NAME,
|
||||||
|
sortDirection: SORT_DIRECTION.DESCENDING,
|
||||||
|
};
|
||||||
|
|
||||||
|
const tagsSlice = createSlice({
|
||||||
|
name: 'tags',
|
||||||
|
initialState,
|
||||||
|
reducers: {
|
||||||
|
setTagsSort: (state, action: PayloadAction<TAG_SORT>) => {
|
||||||
|
state.sort = action.payload;
|
||||||
|
},
|
||||||
|
setTagsSortDirection: (state, action: PayloadAction<SORT_DIRECTION>) => {
|
||||||
|
state.sortDirection = action.payload;
|
||||||
|
},
|
||||||
|
toggleTagsSortDirection: state => {
|
||||||
|
state.sortDirection ^= 1;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { setTagsSort, setTagsSortDirection, toggleTagsSortDirection } =
|
||||||
|
tagsSlice.actions;
|
||||||
|
|
||||||
|
export {
|
||||||
|
type TagsState,
|
||||||
|
setTagsSort,
|
||||||
|
setTagsSortDirection,
|
||||||
|
toggleTagsSortDirection,
|
||||||
|
};
|
||||||
|
export default tagsSlice.reducer;
|
@@ -1,2 +1,8 @@
|
|||||||
export { SORT, SORT_DIRECTION } from './sort';
|
export {
|
||||||
|
HOME_SORT,
|
||||||
|
homeSortQuery,
|
||||||
|
TAG_SORT,
|
||||||
|
tagSortQuery,
|
||||||
|
SORT_DIRECTION,
|
||||||
|
} from './sort';
|
||||||
export { VIEW } from './view';
|
export { VIEW } from './view';
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
enum SORT {
|
enum HOME_SORT {
|
||||||
TITLE = 'Title',
|
TITLE = 'Title',
|
||||||
DATE_CREATED = 'Date Created',
|
DATE_CREATED = 'Date Created',
|
||||||
DATE_MODIFIED = 'Date Modified',
|
DATE_MODIFIED = 'Date Modified',
|
||||||
@@ -7,9 +7,60 @@ enum SORT {
|
|||||||
SIZE = 'Size',
|
SIZE = 'Size',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const homeSortQuery = (sort: HOME_SORT) => {
|
||||||
|
switch (sort) {
|
||||||
|
case HOME_SORT.TITLE: {
|
||||||
|
return 'title';
|
||||||
|
}
|
||||||
|
case HOME_SORT.DATE_CREATED: {
|
||||||
|
return 'dateCreated';
|
||||||
|
}
|
||||||
|
case HOME_SORT.DATE_MODIFIED: {
|
||||||
|
return 'dateModified';
|
||||||
|
}
|
||||||
|
case HOME_SORT.DATE_USED: {
|
||||||
|
return 'dateUsed';
|
||||||
|
}
|
||||||
|
case HOME_SORT.TIMES_USED: {
|
||||||
|
return 'timesUsed';
|
||||||
|
}
|
||||||
|
case HOME_SORT.SIZE: {
|
||||||
|
return 'size';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
enum TAG_SORT {
|
||||||
|
NAME = 'Name',
|
||||||
|
MEMES_LENGTH = 'Items',
|
||||||
|
DATE_CREATED = 'Date Created',
|
||||||
|
DATE_MODIFIED = 'Date Modified',
|
||||||
|
TIMES_USED = 'Times Used',
|
||||||
|
}
|
||||||
|
|
||||||
|
const tagSortQuery = (sort: TAG_SORT) => {
|
||||||
|
switch (sort) {
|
||||||
|
case TAG_SORT.NAME: {
|
||||||
|
return 'name';
|
||||||
|
}
|
||||||
|
case TAG_SORT.MEMES_LENGTH: {
|
||||||
|
return 'memesLength';
|
||||||
|
}
|
||||||
|
case TAG_SORT.DATE_CREATED: {
|
||||||
|
return 'dateCreated';
|
||||||
|
}
|
||||||
|
case TAG_SORT.DATE_MODIFIED: {
|
||||||
|
return 'dateModified';
|
||||||
|
}
|
||||||
|
case TAG_SORT.TIMES_USED: {
|
||||||
|
return 'timesUsed';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
enum SORT_DIRECTION {
|
enum SORT_DIRECTION {
|
||||||
ASCENDING = 0,
|
ASCENDING = 0,
|
||||||
DESCENDING = 1,
|
DESCENDING = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
export { SORT, SORT_DIRECTION };
|
export { HOME_SORT, homeSortQuery, TAG_SORT, tagSortQuery, SORT_DIRECTION };
|
||||||
|
@@ -1,21 +1,29 @@
|
|||||||
import { SORT, SORT_DIRECTION, VIEW } from '../types';
|
import { HOME_SORT, SORT_DIRECTION, TAG_SORT, VIEW } from '../types';
|
||||||
|
|
||||||
const getSortIcon = (sort: SORT, sortDirection: SORT_DIRECTION) => {
|
const getSortIcon = (
|
||||||
|
sort: HOME_SORT | TAG_SORT,
|
||||||
|
sortDirection: SORT_DIRECTION,
|
||||||
|
) => {
|
||||||
let sortIcon = '';
|
let sortIcon = '';
|
||||||
|
|
||||||
switch (sort) {
|
switch (sort) {
|
||||||
case SORT.TITLE: {
|
case HOME_SORT.TITLE:
|
||||||
|
case TAG_SORT.NAME: {
|
||||||
sortIcon = 'sort-alphabetical';
|
sortIcon = 'sort-alphabetical';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SORT.DATE_CREATED:
|
case HOME_SORT.DATE_CREATED:
|
||||||
case SORT.DATE_MODIFIED:
|
case HOME_SORT.DATE_MODIFIED:
|
||||||
case SORT.DATE_USED: {
|
case HOME_SORT.DATE_USED:
|
||||||
|
case TAG_SORT.DATE_CREATED:
|
||||||
|
case TAG_SORT.DATE_MODIFIED: {
|
||||||
sortIcon = 'sort-calendar';
|
sortIcon = 'sort-calendar';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SORT.TIMES_USED:
|
case HOME_SORT.TIMES_USED:
|
||||||
case SORT.SIZE: {
|
case HOME_SORT.SIZE:
|
||||||
|
case TAG_SORT.MEMES_LENGTH:
|
||||||
|
case TAG_SORT.TIMES_USED: {
|
||||||
sortIcon = 'sort-numeric';
|
sortIcon = 'sort-numeric';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user