diff --git a/app.json b/app.json index 3f5c793f..43ed9f97 100644 --- a/app.json +++ b/app.json @@ -9,12 +9,16 @@ "splash": { "image": "./assets/splash.png", "resizeMode": "cover", - "backgroundColor": "#000000" + "backgroundColor": "#222831" }, "updates": { "fallbackToCacheTimeout": 0, "enabled": false }, + "notification": { + "icon": "./assets/notification.png", + "color": "#00adb5" + }, "assetBundlePatterns": ["**/*"], "ios": { "supportsTablet": true diff --git a/assets/notification.png b/assets/notification.png new file mode 100644 index 00000000..b9cbe0c5 Binary files /dev/null and b/assets/notification.png differ diff --git a/assets/splash.png b/assets/splash.png index 2e43828c..933cbe56 100644 Binary files a/assets/splash.png and b/assets/splash.png differ diff --git a/src/Components/List.js b/src/Components/List.js index 5bc5f00f..b57e7eee 100644 --- a/src/Components/List.js +++ b/src/Components/List.js @@ -14,10 +14,19 @@ const ListSubHeader = ({ children, theme }) => ( ); -const ListItem = ({ title, description, icon, onPress, theme, right }) => ( +const ListItem = ({ + title, + description, + icon, + onPress, + theme, + right, + titleStyle, +}) => ( ` SELECT novels.*, C.chaptersUnread, D.chaptersDownloaded FROM novels LEFT JOIN ( @@ -18,15 +18,15 @@ const getLibraryQuery = ` GROUP BY chapters.novelId ) AS D ON novels.novelId = D.novelId - WHERE novels.followed = 1 - GROUP BY novels.novelId + WHERE novels.followed = 1 ${filter ? "AND " + filter : ""} + ${sort ? "ORDER BY " + sort : ""} `; -export const getLibrary = () => { +export const getLibrary = (sort, filter) => { return new Promise((resolve, reject) => db.transaction((tx) => { tx.executeSql( - getLibraryQuery, + getLibraryQuery(sort, filter), null, (txObj, { rows: { _array } }) => { // console.log(_array); diff --git a/src/Hooks/reduxHooks.js b/src/Hooks/reduxHooks.js index 31b6ab32..25866dab 100644 --- a/src/Hooks/reduxHooks.js +++ b/src/Hooks/reduxHooks.js @@ -95,6 +95,12 @@ const useTrackingStatus = () => { return tracker; }; +const useLibraryFilters = () => { + const filters = useSelector((state) => state.libraryReducer.filters); + + return filters; +}; + export { useTheme, useReaderSettings, @@ -106,4 +112,5 @@ export { useNovel, useChapter, useSavedSettings, + useLibraryFilters, }; diff --git a/src/Screens/Library/Library.js b/src/Screens/Library/Library.js index dbe7a262..2bfbd03d 100644 --- a/src/Screens/Library/Library.js +++ b/src/Screens/Library/Library.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useCallback } from "react"; +import React, { useState, useCallback, useRef } from "react"; import { StyleSheet, Text, @@ -21,12 +21,22 @@ import { import { updateLibraryAction } from "../../redux/updates/updates.actions"; import { useTheme } from "../../Hooks/reduxHooks"; import { setNovel } from "../../redux/novel/novel.actions"; +import { Portal } from "react-native-paper"; +import LibraryFilterSheet from "./components/LibraryFilterSheet"; const LibraryScreen = ({ navigation }) => { const theme = useTheme(); const dispatch = useDispatch(); - const { loading, novels } = useSelector((state) => state.libraryReducer); + const libraryFilterSheetRef = useRef(null); + + const { + loading, + novels, + filters: { sort, filter }, + } = useSelector((state) => state.libraryReducer); + + console.log("1.", sort, filter); const [refreshing, setRefreshing] = useState(false); const [searchText, setSearchText] = useState(""); @@ -34,7 +44,7 @@ const LibraryScreen = ({ navigation }) => { useFocusEffect( useCallback(() => { setSearchText(""); - dispatch(getLibraryAction()); + dispatch(getLibraryAction(sort, filter)); }, [getLibraryAction]) ); @@ -45,13 +55,13 @@ const LibraryScreen = ({ navigation }) => { }; const clearSearchbar = () => { - dispatch(getLibraryAction()); + dispatch(getLibraryAction(sort, filter)); setSearchText(""); }; const onChangeText = (text) => { setSearchText(text); - dispatch(searchLibraryAction(text)); + dispatch(searchLibraryAction(text, sort, filter)); }; const renderItem = ({ item }) => ( @@ -73,6 +83,10 @@ const LibraryScreen = ({ navigation }) => { /> ); + // if (!loading) { + // console.log(novels); + // } + const listEmptyComponent = () => searchText !== "" ? ( @@ -99,17 +113,30 @@ const LibraryScreen = ({ navigation }) => { clearSearchbar={clearSearchbar} onChangeText={onChangeText} left="magnify" + right="dots-vertical" + onPressRight={() => libraryFilterSheetRef.current.show()} theme={theme} /> {loading ? ( ) : ( - + <> + + + + + )} diff --git a/src/Screens/Library/components/LibraryFilterSheet.js b/src/Screens/Library/components/LibraryFilterSheet.js index e69de29b..8691e33a 100644 --- a/src/Screens/Library/components/LibraryFilterSheet.js +++ b/src/Screens/Library/components/LibraryFilterSheet.js @@ -0,0 +1,254 @@ +import React, { useState } from "react"; +import { StyleSheet, View, Text, Animated } from "react-native"; + +import { List, RadioButton, Checkbox } from "react-native-paper"; + +import Bottomsheet from "rn-sliding-up-panel"; +import BottomSheetHandle from "../../../Components/BottomSheetHandle"; +import { ListItem } from "../../../Components/List"; +import { filterLibrary } from "../../../redux/library/library.actions"; + +const LibraryFilterSheet = ({ + bottomSheetRef, + dispatch, + sort, + filter, + theme, +}) => { + const [animatedValue] = useState(new Animated.Value(0)); + + return ( + + + + + + SORT + + + sort === "novels.novelId ASC" + ? dispatch( + filterLibrary( + "novels.novelId DESC", + filter + ) + ) + : dispatch( + filterLibrary( + "novels.novelId ASC", + filter + ) + ) + } + /> + + sort === "novels.novelName ASC" + ? dispatch( + filterLibrary( + "novels.novelName DESC", + filter + ) + ) + : dispatch( + filterLibrary( + "novels.novelName ASC", + filter + ) + ) + } + /> + + sort === "novels.unread ASC" + ? dispatch( + filterLibrary( + "novels.unread DESC", + filter + ) + ) + : dispatch( + filterLibrary("novels.unread ASC", filter) + ) + } + /> + + sort === "chaptersDownloaded ASC" + ? dispatch( + filterLibrary( + "chaptersDownloaded DESC", + filter + ) + ) + : dispatch( + filterLibrary( + "chaptersDownloaded ASC", + filter + ) + ) + } + /> + + sort === "chaptersUnread ASC" + ? dispatch( + filterLibrary( + "chaptersUnread DESC", + filter + ) + ) + : dispatch( + filterLibrary( + "chaptersUnread ASC", + filter + ) + ) + } + /> + + + + Filter + + 0" + ? "checked" + : "unchecked" + } + onPress={() => + filter === "chaptersDownloaded > 0" + ? dispatch(filterLibrary(sort, "")) + : dispatch( + filterLibrary( + sort, + "chaptersDownloaded > 0" + ) + ) + } + /> + + filter === "unread = 1" + ? dispatch(filterLibrary(sort, "")) + : dispatch(filterLibrary(sort, "unread = 1")) + } + /> + + filter === "chaptersUnread IS NULL" + ? dispatch(filterLibrary(sort, "")) + : dispatch( + filterLibrary( + sort, + "chaptersUnread IS NULL" + ) + ) + } + /> + + + + ); +}; + +export default LibraryFilterSheet; + +const styles = StyleSheet.create({ + contentContainer: { + flex: 1, + borderTopRightRadius: 8, + borderTopLeftRadius: 8, + }, +}); diff --git a/src/Screens/Novel/Novel.js b/src/Screens/Novel/Novel.js index 3e4dabc1..3353bd9c 100644 --- a/src/Screens/Novel/Novel.js +++ b/src/Screens/Novel/Novel.js @@ -56,7 +56,7 @@ const Novel = ({ route, navigation }) => { }, [getNovelAction]); const onRefresh = () => { - dispatch(updateNovelAction(sourceId, novelUrl, novelId)); + dispatch(updateNovelAction(sourceId, novelUrl, novelId, sort, filter)); showToast(`Updated ${novelName}`); }; diff --git a/src/redux/library/library.actions.js b/src/redux/library/library.actions.js index f5d25773..f96c24c2 100644 --- a/src/redux/library/library.actions.js +++ b/src/redux/library/library.actions.js @@ -2,6 +2,7 @@ import { GET_LIBRARY_NOVELS, GET_LIBRARY_SEARCH_RESULTS, SET_LIBRARY_LOADING, + SORT_FILTER_LIBRARY, } from "./library.types"; import { getLibrary, @@ -9,8 +10,9 @@ import { } from "../../Database/queries/LibraryQueries"; import { restoreBackup } from "../../Services/backup"; -export const getLibraryAction = () => async (dispatch) => { - const res = await getLibrary(); +export const getLibraryAction = (sort, filter) => async (dispatch) => { + // console.log(sort, filter); + const res = await getLibrary(sort, filter); dispatch({ type: GET_LIBRARY_NOVELS, @@ -18,11 +20,23 @@ export const getLibraryAction = () => async (dispatch) => { }); }; -export const searchLibraryAction = (searchText) => async (dispatch) => { - const res = await searchLibrary(searchText); +export const searchLibraryAction = + (searchText, sort, filter) => async (dispatch) => { + const res = await searchLibrary(searchText, sort, filter); + + dispatch({ + type: GET_LIBRARY_SEARCH_RESULTS, + payload: res, + }); + }; + +export const filterLibrary = (sort, filter) => async (dispatch) => { + dispatch({ type: SORT_FILTER_LIBRARY, payload: { sort, filter } }); + + const res = await getLibrary(sort, filter); dispatch({ - type: GET_LIBRARY_SEARCH_RESULTS, + type: GET_LIBRARY_NOVELS, payload: res, }); }; diff --git a/src/redux/library/library.reducer.js b/src/redux/library/library.reducer.js index 683612ed..411b9867 100644 --- a/src/redux/library/library.reducer.js +++ b/src/redux/library/library.reducer.js @@ -2,11 +2,13 @@ import { GET_LIBRARY_NOVELS, GET_LIBRARY_SEARCH_RESULTS, SET_LIBRARY_LOADING, + SORT_FILTER_LIBRARY, } from "./library.types"; const initialState = { novels: [], searchResults: [], + filters: { sort: "novels.novelId ASC", filter: "" }, loading: true, }; @@ -20,6 +22,12 @@ const libraryReducer = (state = initialState, action) => { return { ...state, novels: payload, loading: false }; case GET_LIBRARY_SEARCH_RESULTS: return { ...state, novels: payload, loading: false }; + case SORT_FILTER_LIBRARY: + console.log("2.", payload.sort, payload.filter); + return { + ...state, + filters: { sort: payload.sort, filter: payload.filter }, + }; default: return state; } diff --git a/src/redux/library/library.types.js b/src/redux/library/library.types.js index 78045c06..8819717f 100644 --- a/src/redux/library/library.types.js +++ b/src/redux/library/library.types.js @@ -1,3 +1,5 @@ export const GET_LIBRARY_NOVELS = "GET_LIBRARY_NOVELS"; export const GET_LIBRARY_SEARCH_RESULTS = "GET_LIBRARY_SEARCH_RESULTS"; export const SET_LIBRARY_LOADING = "SET_LIBRARY_LOADING"; + +export const SORT_FILTER_LIBRARY = "SORT_FILTER_LIBRARY"; diff --git a/src/redux/novel/novel.actions.js b/src/redux/novel/novel.actions.js index 0f528a31..011d5640 100644 --- a/src/redux/novel/novel.actions.js +++ b/src/redux/novel/novel.actions.js @@ -257,13 +257,13 @@ export const deleteAllChaptersAction = (chapters) => async (dispatch) => { }; export const updateNovelAction = - (sourceId, novelUrl, novelId) => async (dispatch) => { + (sourceId, novelUrl, novelId, sort, filter) => async (dispatch) => { dispatch({ type: FETCHING_NOVEL }); await updateNovel(sourceId, novelUrl, novelId); let novel = await getNovel(sourceId, novelUrl); - let chapters = await getChapters(novel.novelId); + let chapters = await getChapters(novel.novelId, sort, filter); dispatch({ type: UPDATE_NOVEL,