Refactor
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { NavigationContainer } from "@react-navigation/native";
|
||||
import { useFonts } from "expo-font";
|
||||
import { Provider as PaperProvider } from "react-native-paper";
|
||||
import Main from "./src/Navigators/Main";
|
||||
@@ -8,17 +7,10 @@ import { Provider } from "react-redux";
|
||||
import { persistor, store } from "./src/redux/store";
|
||||
import { PersistGate } from "redux-persist/lib/integration/react";
|
||||
import { createDB, deleteDb } from "./src/Database/DBHelper";
|
||||
import { fonts } from "./src/Theme/fonts";
|
||||
|
||||
const App = () => {
|
||||
const [loaded] = useFonts({
|
||||
"pt-sans-bold": require("./assets/fonts/PTSansNarrow-Bold.ttf"),
|
||||
"arbutus-slab": require("./assets/fonts/ArbutusSlab-Regular.ttf"),
|
||||
domine: require("./assets/fonts/Domine-VariableFont_wght.ttf"),
|
||||
lato: require("./assets/fonts/Lato-Regular.ttf"),
|
||||
"noto-sans": require("./assets/fonts/NotoSans-Regular.ttf"),
|
||||
"open-sans": require("./assets/fonts/OpenSans-Regular.ttf"),
|
||||
"pt-serif": require("./assets/fonts/PTSerif-Regular.ttf"),
|
||||
});
|
||||
const [loaded] = useFonts(fonts);
|
||||
|
||||
useEffect(() => createDB(), []);
|
||||
|
||||
@@ -30,9 +22,7 @@ const App = () => {
|
||||
<Provider store={store}>
|
||||
<PersistGate loading={null} persistor={persistor}>
|
||||
<PaperProvider>
|
||||
<NavigationContainer>
|
||||
<Main />
|
||||
</NavigationContainer>
|
||||
<Main />
|
||||
</PaperProvider>
|
||||
</PersistGate>
|
||||
</Provider>
|
||||
|
||||
@@ -45,15 +45,10 @@ const ListItem = ({ title, description, icon, onPress, theme, right }) => (
|
||||
);
|
||||
|
||||
const Divider = ({ theme }) => (
|
||||
<PaperDivider
|
||||
style={{
|
||||
backgroundColor: theme.dividerColor,
|
||||
height: 1,
|
||||
}}
|
||||
/>
|
||||
<PaperDivider style={{ backgroundColor: theme.dividerColor, height: 1 }} />
|
||||
);
|
||||
|
||||
const InfoItem = ({ title, description, icon, onPress, theme, right }) => (
|
||||
const InfoItem = ({ title, icon, theme }) => (
|
||||
<List.Item
|
||||
title={title}
|
||||
titleStyle={{ color: theme.textColorSecondary, fontSize: 14 }}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import React from "react";
|
||||
import { View, Text as RNText, Image, StyleSheet } from "react-native";
|
||||
|
||||
const Text = () => {};
|
||||
|
||||
export default UpdateCard;
|
||||
|
||||
const styles = StyleSheet.create({});
|
||||
@@ -22,7 +22,7 @@ export const githubUpdateChecker = () => {
|
||||
};
|
||||
|
||||
const isNewVersion = (versionTag) => {
|
||||
let currentVersion = "v1.0.16";
|
||||
let currentVersion = "v1.0.17";
|
||||
const regex = /[^\\d.]/;
|
||||
|
||||
let newVersion = versionTag.replace(regex, "");
|
||||
|
||||
@@ -27,6 +27,12 @@ const useLibrary = () => {
|
||||
return library;
|
||||
};
|
||||
|
||||
const useNovel = () => {
|
||||
const novel = useSelector((state) => state.novelReducer);
|
||||
|
||||
return novel;
|
||||
};
|
||||
|
||||
const findNovel = (novelId) => {
|
||||
let novel = useSelector((state) => state.preferenceReducer.novelSettings);
|
||||
novel = novel.find((novel) => novel.novelId === novelId);
|
||||
@@ -74,5 +80,5 @@ export {
|
||||
useSettings,
|
||||
usePreferences,
|
||||
useContinueReading,
|
||||
findNovel,
|
||||
useNovel,
|
||||
};
|
||||
|
||||
+34
-28
@@ -16,6 +16,7 @@ import { View } from "react-native";
|
||||
import { useTheme } from "../Hooks/reduxHooks";
|
||||
import { githubUpdateChecker } from "../Hooks/githubUpdateChecker";
|
||||
import NewUpdateDialog from "../Components/NewUpdateDialog";
|
||||
import { NavigationContainer } from "@react-navigation/native";
|
||||
|
||||
const Stack = createStackNavigator();
|
||||
|
||||
@@ -29,34 +30,39 @@ const MainNavigator = () => {
|
||||
const { isNewVersion, latestRelease } = githubUpdateChecker() || {};
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1, backgroundColor: theme.colorPrimary }}>
|
||||
{isNewVersion && <NewUpdateDialog newVersion={latestRelease} />}
|
||||
<Stack.Navigator screenOptions={stackNavigatorConfig}>
|
||||
<Stack.Screen
|
||||
name="BottomNavigator"
|
||||
component={BottomNavigator}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="Novel"
|
||||
component={Novel}
|
||||
options={{
|
||||
headerTitle: "",
|
||||
headerShown: true,
|
||||
headerTransparent: true,
|
||||
headerTintColor: "white",
|
||||
...TransitionPresets.RevealFromBottomAndroid,
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="Chapter"
|
||||
component={Chapter}
|
||||
options={{ ...TransitionPresets.SlideFromRightIOS }}
|
||||
/>
|
||||
<Stack.Screen name="MoreStack" component={MoreStack} />
|
||||
<Stack.Screen name="Extension" component={Extension} />
|
||||
<Stack.Screen name="GlobalSearch" component={GlobalSearch} />
|
||||
</Stack.Navigator>
|
||||
</View>
|
||||
<NavigationContainer>
|
||||
<View style={{ flex: 1, backgroundColor: theme.colorPrimary }}>
|
||||
{isNewVersion && <NewUpdateDialog newVersion={latestRelease} />}
|
||||
<Stack.Navigator screenOptions={stackNavigatorConfig}>
|
||||
<Stack.Screen
|
||||
name="BottomNavigator"
|
||||
component={BottomNavigator}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="Novel"
|
||||
component={Novel}
|
||||
options={{
|
||||
headerTitle: "",
|
||||
headerShown: true,
|
||||
headerTransparent: true,
|
||||
headerTintColor: "white",
|
||||
...TransitionPresets.RevealFromBottomAndroid,
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="Chapter"
|
||||
component={Chapter}
|
||||
options={{ ...TransitionPresets.SlideFromRightIOS }}
|
||||
/>
|
||||
<Stack.Screen name="MoreStack" component={MoreStack} />
|
||||
<Stack.Screen name="Extension" component={Extension} />
|
||||
<Stack.Screen
|
||||
name="GlobalSearch"
|
||||
component={GlobalSearch}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
</View>
|
||||
</NavigationContainer>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -114,12 +114,18 @@ const GlobalSearch = ({ navigation }) => {
|
||||
renderItem={renderItem}
|
||||
extraData={pinned}
|
||||
ListEmptyComponent={
|
||||
!loading && (
|
||||
<EmptyView
|
||||
icon="__φ(..)"
|
||||
description="Search a novel in your pinned sources"
|
||||
/>
|
||||
)
|
||||
<>
|
||||
{!loading && (
|
||||
<EmptyView
|
||||
icon="__φ(..)"
|
||||
description={`Search a novel in your pinned sources ${
|
||||
pinned.length === 0
|
||||
? "(No sources pinned)"
|
||||
: ""
|
||||
}`}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
ListFooterComponent={
|
||||
loading && (
|
||||
|
||||
@@ -27,6 +27,7 @@ const History = ({
|
||||
const renderHistoryCard = ({ item }) => (
|
||||
<HistoryCard
|
||||
item={item}
|
||||
theme={theme}
|
||||
deleteHistoryAction={deleteHistoryAction}
|
||||
navigation={navigation}
|
||||
/>
|
||||
|
||||
@@ -7,9 +7,7 @@ import moment from "moment";
|
||||
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
const HistoryCard = ({ item, deleteHistoryAction, navigation }) => {
|
||||
const theme = useSelector((state) => state.settingsReducer.theme);
|
||||
|
||||
const HistoryCard = ({ item, deleteHistoryAction, navigation, theme }) => {
|
||||
return (
|
||||
<TouchableRipple
|
||||
style={styles.historyCard}
|
||||
|
||||
@@ -104,7 +104,7 @@ const LibraryScreen = ({ navigation }) => {
|
||||
data={novels}
|
||||
renderItem={renderItem}
|
||||
refreshControl={refreshControl()}
|
||||
ListEmptyComponent={listEmptyComponent()}
|
||||
ListEmptyComponent={listEmptyComponent}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
|
||||
@@ -17,12 +17,12 @@ const AboutScreen = ({ navigation }) => {
|
||||
<ListSection>
|
||||
<ListItem
|
||||
title="Version"
|
||||
description="Stable 1.0.16"
|
||||
description="Stable 1.0.17"
|
||||
theme={theme}
|
||||
/>
|
||||
<ListItem
|
||||
title="Build Time"
|
||||
description="03-05-21 20:45 PM"
|
||||
description="05-05-21 21:00 PM"
|
||||
theme={theme}
|
||||
/>
|
||||
<ListItem
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import { connect } from "react-redux";
|
||||
import { connect, useDispatch } from "react-redux";
|
||||
|
||||
import { switchTheme } from "../../redux/settings/settings.actions";
|
||||
import {
|
||||
@@ -23,6 +23,7 @@ import GridSizeModal from "./components/GridSizeModal";
|
||||
import ThemeModal from "./components/ThemeModal";
|
||||
import { createBackup, restoreBackup } from "../../Services/backup";
|
||||
import { useTheme } from "../../Hooks/reduxHooks";
|
||||
import { restoreLibraryAction } from "../../redux/library/library.actions";
|
||||
|
||||
const SettingsScreen = ({
|
||||
navigation,
|
||||
@@ -44,6 +45,8 @@ const SettingsScreen = ({
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
// Display Mode Modal
|
||||
const [displayModalVisible, setDisplayModalVisible] = useState(false);
|
||||
const showDisplayModal = () => setDisplayModalVisible(true);
|
||||
@@ -116,14 +119,13 @@ const SettingsScreen = ({
|
||||
<ListItem
|
||||
title="Restore backup"
|
||||
description="Restore library from backup file"
|
||||
onPress={restoreBackup}
|
||||
onPress={() => dispatch(restoreLibraryAction())}
|
||||
theme={theme}
|
||||
/>
|
||||
<InfoItem
|
||||
title="Create backup may not work on devices with Android 9 or lower."
|
||||
icon="information-outline"
|
||||
description="Restore library from backup file"
|
||||
onPress={restoreBackup}
|
||||
theme={theme}
|
||||
/>
|
||||
</ListSection>
|
||||
|
||||
+51
-57
@@ -3,15 +3,16 @@ import { StyleSheet, View, FlatList, RefreshControl } from "react-native";
|
||||
import { Provider, Portal } from "react-native-paper";
|
||||
import {
|
||||
useContinueReading,
|
||||
useNovel,
|
||||
usePreferences,
|
||||
useTheme,
|
||||
} from "../../Hooks/reduxHooks";
|
||||
|
||||
import ChapterCard from "./components/ChapterCard";
|
||||
import ChapterItem from "./components/ChapterItem";
|
||||
import NovelInfoHeader from "./components/NovelHeader";
|
||||
import ChaptersSettingsSheet from "./components/ChaptersSettingsSheet";
|
||||
|
||||
import { connect } from "react-redux";
|
||||
import { useDispatch } from "react-redux";
|
||||
|
||||
import {
|
||||
getNovelAction,
|
||||
@@ -21,16 +22,7 @@ import {
|
||||
import TrackSheet from "./components/Tracker/TrackSheet";
|
||||
import { showToast } from "../../Hooks/showToast";
|
||||
|
||||
const Novel = ({
|
||||
route,
|
||||
novel,
|
||||
chapters,
|
||||
loading,
|
||||
getNovelAction,
|
||||
fetching,
|
||||
sortAndFilterChapters,
|
||||
updateNovelAction,
|
||||
}) => {
|
||||
const Novel = ({ route, navigation }) => {
|
||||
const item = route.params;
|
||||
const {
|
||||
sourceId,
|
||||
@@ -42,6 +34,8 @@ const Novel = ({
|
||||
} = item;
|
||||
|
||||
const theme = useTheme();
|
||||
const dispatch = useDispatch();
|
||||
const { novel, chapters, loading, fetching } = useNovel();
|
||||
|
||||
let chaptersSettingsSheetRef = useRef(null);
|
||||
let trackerSheetRef = useRef(null);
|
||||
@@ -56,19 +50,49 @@ const Novel = ({
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
getNovelAction(followed, sourceId, novelUrl, novelId, sort, filter);
|
||||
dispatch(
|
||||
getNovelAction(followed, sourceId, novelUrl, novelId, sort, filter)
|
||||
);
|
||||
}, [getNovelAction]);
|
||||
|
||||
const onRefresh = async () => {
|
||||
await updateNovelAction(sourceId, novelUrl, novelId);
|
||||
const onRefresh = () => {
|
||||
dispatch(updateNovelAction(sourceId, novelUrl, novelId));
|
||||
showToast(`Updated ${novelName}`);
|
||||
};
|
||||
|
||||
const renderChapterCard = ({ item }) => (
|
||||
<ChapterCard
|
||||
novelUrl={novelUrl}
|
||||
extensionId={sourceId}
|
||||
const refreshControl = () => (
|
||||
<RefreshControl
|
||||
onRefresh={onRefresh}
|
||||
refreshing={fetching}
|
||||
colors={[theme.textColorPrimary]}
|
||||
progressBackgroundColor={theme.colorPrimary}
|
||||
/>
|
||||
);
|
||||
|
||||
const ListHeaderComponent = () => (
|
||||
<NovelInfoHeader
|
||||
item={item}
|
||||
novel={novel}
|
||||
theme={theme}
|
||||
filter={filter}
|
||||
loading={loading}
|
||||
lastRead={lastRead}
|
||||
dispatch={dispatch}
|
||||
chapters={chapters}
|
||||
navigation={navigation}
|
||||
trackerSheetRef={trackerSheetRef}
|
||||
chaptersSettingsSheetRef={chaptersSettingsSheetRef}
|
||||
/>
|
||||
);
|
||||
|
||||
const renderItem = ({ item }) => (
|
||||
<ChapterItem
|
||||
theme={theme}
|
||||
chapter={item}
|
||||
novelUrl={novelUrl}
|
||||
dispatch={dispatch}
|
||||
sourceId={sourceId}
|
||||
navigation={navigation}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -87,45 +111,25 @@ const Novel = ({
|
||||
maxToRenderPerBatch={5}
|
||||
windowSize={15}
|
||||
initialNumToRender={7}
|
||||
renderItem={renderChapterCard}
|
||||
ListHeaderComponent={
|
||||
<NovelInfoHeader
|
||||
loading={loading}
|
||||
item={item}
|
||||
novel={novel}
|
||||
chapters={chapters}
|
||||
trackerSheetRef={trackerSheetRef}
|
||||
chaptersSettingsSheetRef={chaptersSettingsSheetRef}
|
||||
theme={theme}
|
||||
filter={filter}
|
||||
lastRead={lastRead}
|
||||
/>
|
||||
}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={fetching}
|
||||
onRefresh={onRefresh}
|
||||
colors={[theme.textColorPrimary]}
|
||||
progressBackgroundColor={theme.colorPrimary}
|
||||
/>
|
||||
}
|
||||
renderItem={renderItem}
|
||||
ListHeaderComponent={ListHeaderComponent}
|
||||
refreshControl={refreshControl()}
|
||||
/>
|
||||
{!loading && (
|
||||
<Portal>
|
||||
<ChaptersSettingsSheet
|
||||
novelUrl={novelUrl}
|
||||
bottomSheetRef={chaptersSettingsSheetRef}
|
||||
dispatch={dispatch}
|
||||
sortAndFilterChapters={sortAndFilterChapters}
|
||||
novelId={novelId || (!loading && novel.novelId)}
|
||||
novelId={novelId || novel.novelId}
|
||||
savedSort={sort}
|
||||
savedFilter={filter}
|
||||
/>
|
||||
<TrackSheet
|
||||
bottomSheetRef={trackerSheetRef}
|
||||
novelId={novelId || (!loading && novel.novelId)}
|
||||
novelName={
|
||||
novelName || (!loading && novel.novelName)
|
||||
}
|
||||
novelId={novelId || novel.novelId}
|
||||
novelName={novelName || novel.novelName}
|
||||
theme={theme}
|
||||
/>
|
||||
</Portal>
|
||||
@@ -134,18 +138,8 @@ const Novel = ({
|
||||
</Provider>
|
||||
);
|
||||
};
|
||||
const mapStateToProps = (state) => ({
|
||||
novel: state.novelReducer.novel,
|
||||
chapters: state.novelReducer.chapters,
|
||||
loading: state.novelReducer.loading,
|
||||
fetching: state.novelReducer.fetching,
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, {
|
||||
getNovelAction,
|
||||
sortAndFilterChapters,
|
||||
updateNovelAction,
|
||||
})(Novel);
|
||||
export default Novel;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: { flex: 1 },
|
||||
|
||||
+22
-31
@@ -7,19 +7,15 @@ import {
|
||||
deleteChapterAction,
|
||||
downloadChapterAction,
|
||||
} from "../../../redux/novel/novel.actions";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
const ChapterCard = ({
|
||||
const ChapterItem = ({
|
||||
novelUrl,
|
||||
chapter,
|
||||
extensionId,
|
||||
sourceId,
|
||||
dispatch,
|
||||
theme,
|
||||
// downloading,
|
||||
downloadChapterAction,
|
||||
deleteChapterAction,
|
||||
navigation,
|
||||
}) => {
|
||||
const navigation = useNavigation();
|
||||
|
||||
const [visible, setVisible] = useState(false);
|
||||
const openMenu = () => setVisible(true);
|
||||
const closeMenu = () => setVisible(false);
|
||||
@@ -52,9 +48,11 @@ const ChapterCard = ({
|
||||
>
|
||||
<Menu.Item
|
||||
onPress={() =>
|
||||
deleteChapterAction(
|
||||
chapter.chapterId,
|
||||
chapter.chapterName
|
||||
dispatch(
|
||||
deleteChapterAction(
|
||||
chapter.chapterId,
|
||||
chapter.chapterName
|
||||
)
|
||||
)
|
||||
}
|
||||
title="Delete"
|
||||
@@ -69,16 +67,17 @@ const ChapterCard = ({
|
||||
animated
|
||||
color={theme.textColorHint}
|
||||
size={25}
|
||||
onPress={() => {
|
||||
downloadChapterAction(
|
||||
extensionId,
|
||||
novelUrl,
|
||||
chapter.chapterUrl,
|
||||
chapter.chapterName,
|
||||
chapter.chapterId
|
||||
);
|
||||
// console.log(downloading);
|
||||
}}
|
||||
onPress={() =>
|
||||
dispatch(
|
||||
downloadChapterAction(
|
||||
sourceId,
|
||||
novelUrl,
|
||||
chapter.chapterUrl,
|
||||
chapter.chapterName,
|
||||
chapter.chapterId
|
||||
)
|
||||
)
|
||||
}
|
||||
style={{ margin: 2 }}
|
||||
/>
|
||||
);
|
||||
@@ -92,7 +91,7 @@ const ChapterCard = ({
|
||||
navigation.navigate("Chapter", {
|
||||
chapterId: chapter.chapterId,
|
||||
chapterUrl: chapter.chapterUrl,
|
||||
extensionId,
|
||||
extensionId: sourceId,
|
||||
novelUrl: novelUrl,
|
||||
chapterName: chapter.chapterName,
|
||||
novelId: chapter.novelId,
|
||||
@@ -139,15 +138,7 @@ const ChapterCard = ({
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
theme: state.settingsReducer.theme,
|
||||
// downloading: state.novelReducer.downloading,
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, {
|
||||
downloadChapterAction,
|
||||
deleteChapterAction,
|
||||
})(ChapterCard);
|
||||
export default ChapterItem;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
chapterCardContainer: {
|
||||
@@ -9,6 +9,7 @@ const ChaptersSettingsSheet = ({
|
||||
bottomSheetRef,
|
||||
novelId,
|
||||
sortAndFilterChapters,
|
||||
dispatch,
|
||||
savedSort,
|
||||
savedFilter,
|
||||
}) => {
|
||||
@@ -17,12 +18,12 @@ const ChaptersSettingsSheet = ({
|
||||
|
||||
const sortChapters = (val) => {
|
||||
setSort(val);
|
||||
sortAndFilterChapters(novelId, val, filter);
|
||||
dispatch(sortAndFilterChapters(novelId, val, filter));
|
||||
};
|
||||
|
||||
const filterChapters = (val) => {
|
||||
setFilter(val);
|
||||
sortAndFilterChapters(novelId, sort, val);
|
||||
dispatch(sortAndFilterChapters(novelId, sort, val));
|
||||
};
|
||||
|
||||
const checkBoxStyle = { flexDirection: "row", alignItems: "center" };
|
||||
|
||||
@@ -18,18 +18,17 @@ import ReadButton from "./Info/ReadButton";
|
||||
|
||||
const NovelInfoHeader = ({
|
||||
item,
|
||||
loading,
|
||||
novel,
|
||||
chapters,
|
||||
theme,
|
||||
chaptersSettingsSheetRef,
|
||||
trackerSheetRef,
|
||||
filter,
|
||||
loading,
|
||||
dispatch,
|
||||
chapters,
|
||||
lastRead,
|
||||
navigation,
|
||||
trackerSheetRef,
|
||||
chaptersSettingsSheetRef,
|
||||
}) => {
|
||||
const navigation = useNavigation();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const [downloadMenu, showDownloadMenu] = useState(false);
|
||||
|
||||
const tracker = useSelector((state) => state.trackerReducer.tracker);
|
||||
|
||||
@@ -6,25 +6,26 @@ import {
|
||||
ActivityIndicator,
|
||||
RefreshControl,
|
||||
} from "react-native";
|
||||
import { connect, useDispatch } from "react-redux";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import EmptyView from "../../Components/EmptyView";
|
||||
import {
|
||||
getUpdatesAction,
|
||||
updateLibraryAction,
|
||||
} from "../../redux/updates/updates.actions";
|
||||
import { Appbar } from "./components/Appbar";
|
||||
import UpdateCard from "./components/UpdateCard";
|
||||
import UpdatesItem from "./components/UpdatesItem";
|
||||
import { useTheme } from "../../Hooks/reduxHooks";
|
||||
|
||||
const Updates = ({ updates, loading, getUpdatesAction }) => {
|
||||
const Updates = ({ navigation }) => {
|
||||
const theme = useTheme();
|
||||
const dispatch = useDispatch();
|
||||
const { updates, loading } = useSelector((state) => state.updatesReducer);
|
||||
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
getUpdatesAction();
|
||||
}, [getUpdatesAction]);
|
||||
dispatch(getUpdatesAction());
|
||||
}, [getUpdatesAction, updates]);
|
||||
|
||||
const onRefresh = async () => {
|
||||
setRefreshing(true);
|
||||
@@ -32,11 +33,40 @@ const Updates = ({ updates, loading, getUpdatesAction }) => {
|
||||
setRefreshing(false);
|
||||
};
|
||||
|
||||
const renderUpdateCard = ({ item }) => <UpdateCard item={item} />;
|
||||
const onPress = (item) =>
|
||||
navigation.navigate("Chapter", {
|
||||
chapterId: item.chapterId,
|
||||
chapterUrl: item.chapterUrl,
|
||||
extensionId: item.sourceId,
|
||||
novelUrl: item.novelUrl,
|
||||
chapterName: item.chapterName,
|
||||
novelId: item.novelId,
|
||||
});
|
||||
|
||||
const renderItem = ({ item }) => (
|
||||
<UpdatesItem item={item} theme={theme} onPress={() => onPress(item)} />
|
||||
);
|
||||
|
||||
const ListFooterComponent = () =>
|
||||
loading && <ActivityIndicator size="small" color={theme.colorAccent} />;
|
||||
|
||||
const ListEmptyComponent = () =>
|
||||
!loading && (
|
||||
<EmptyView icon="(˘・_・˘)" description="No recent updates" />
|
||||
);
|
||||
|
||||
const refreshControl = () => (
|
||||
<RefreshControl
|
||||
refreshing={refreshing}
|
||||
onRefresh={onRefresh}
|
||||
colors={["white"]}
|
||||
progressBackgroundColor={theme.colorAccent}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Appbar theme={theme} />
|
||||
<Appbar theme={theme} dispatch={dispatch} />
|
||||
<View
|
||||
style={[
|
||||
styles.container,
|
||||
@@ -44,47 +74,22 @@ const Updates = ({ updates, loading, getUpdatesAction }) => {
|
||||
]}
|
||||
>
|
||||
<FlatList
|
||||
contentContainerStyle={{ flexGrow: 1, paddingVertical: 8 }}
|
||||
contentContainerStyle={styles.flatList}
|
||||
data={updates}
|
||||
keyExtractor={(item) => item.updateId.toString()}
|
||||
renderItem={renderUpdateCard}
|
||||
ListFooterComponent={
|
||||
loading && (
|
||||
<ActivityIndicator
|
||||
size="small"
|
||||
color={theme.colorAccent}
|
||||
/>
|
||||
)
|
||||
}
|
||||
ListEmptyComponent={
|
||||
!loading && (
|
||||
<EmptyView
|
||||
icon="(˘・_・˘)"
|
||||
description="No recent updates"
|
||||
/>
|
||||
)
|
||||
}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={refreshing}
|
||||
onRefresh={onRefresh}
|
||||
colors={["white"]}
|
||||
progressBackgroundColor={theme.colorAccent}
|
||||
/>
|
||||
}
|
||||
renderItem={renderItem}
|
||||
ListFooterComponent={ListFooterComponent()}
|
||||
ListEmptyComponent={ListEmptyComponent()}
|
||||
refreshControl={refreshControl()}
|
||||
/>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
updates: state.updatesReducer.updates,
|
||||
loading: state.updatesReducer.loading,
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, { getUpdatesAction })(Updates);
|
||||
export default Updates;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: { flex: 1 },
|
||||
flatList: { flexGrow: 1, paddingVertical: 8 },
|
||||
});
|
||||
|
||||
@@ -1,22 +1,17 @@
|
||||
import React from "react";
|
||||
import { Appbar as MaterialAppbar } from "react-native-paper";
|
||||
|
||||
import { useDispatch } from "react-redux";
|
||||
import { updateLibraryAction } from "../../../redux/updates/updates.actions";
|
||||
|
||||
export const Appbar = ({ theme }) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
return (
|
||||
<MaterialAppbar.Header style={{ backgroundColor: theme.colorPrimary }}>
|
||||
<MaterialAppbar.Content
|
||||
title="Updates"
|
||||
titleStyle={{ color: theme.textColorPrimary }}
|
||||
/>
|
||||
<MaterialAppbar.Action
|
||||
icon="reload"
|
||||
onPress={() => dispatch(updateLibraryAction())}
|
||||
/>
|
||||
</MaterialAppbar.Header>
|
||||
);
|
||||
};
|
||||
export const Appbar = ({ theme, dispatch }) => (
|
||||
<MaterialAppbar.Header style={{ backgroundColor: theme.colorPrimary }}>
|
||||
<MaterialAppbar.Content
|
||||
title="Updates"
|
||||
titleStyle={{ color: theme.textColorPrimary }}
|
||||
/>
|
||||
<MaterialAppbar.Action
|
||||
icon="reload"
|
||||
onPress={() => dispatch(updateLibraryAction())}
|
||||
/>
|
||||
</MaterialAppbar.Header>
|
||||
);
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
import React from "react";
|
||||
import { View, Text, Image, StyleSheet } from "react-native";
|
||||
import { TouchableRipple, Button } from "react-native-paper";
|
||||
import moment from "moment";
|
||||
|
||||
import { useNavigation } from "@react-navigation/native";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
const UpdateCard = ({ item }) => {
|
||||
const navigation = useNavigation();
|
||||
|
||||
const theme = useSelector((state) => state.settingsReducer.theme);
|
||||
|
||||
return (
|
||||
<TouchableRipple
|
||||
style={styles.updateCard}
|
||||
onPress={() =>
|
||||
// console.log(item);
|
||||
navigation.navigate("Chapter", {
|
||||
chapterId: item.chapterId,
|
||||
chapterUrl: item.chapterUrl,
|
||||
extensionId: item.sourceId,
|
||||
novelUrl: item.novelUrl,
|
||||
chapterName: item.chapterName,
|
||||
novelId: item.novelId,
|
||||
})
|
||||
}
|
||||
rippleColor={theme.rippleColor}
|
||||
borderless
|
||||
>
|
||||
<>
|
||||
<Image
|
||||
source={{ uri: item.novelCover }}
|
||||
style={styles.updateIcon}
|
||||
/>
|
||||
<View style={styles.extensionDetails}>
|
||||
<View>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorPrimary,
|
||||
fontSize: 14,
|
||||
}}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{item.novelName}
|
||||
</Text>
|
||||
<View style={{ flexDirection: "row" }}>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorPrimary,
|
||||
fontSize: 12,
|
||||
}}
|
||||
>
|
||||
{`${item.chapterName} · ${moment(
|
||||
item.updateTime
|
||||
).calendar()}`}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
</TouchableRipple>
|
||||
);
|
||||
};
|
||||
|
||||
export default UpdateCard;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
updateCard: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
paddingVertical: 8,
|
||||
paddingHorizontal: 12,
|
||||
// borderRadius: 4,
|
||||
},
|
||||
updateIcon: {
|
||||
width: 42,
|
||||
height: 42,
|
||||
borderRadius: 4,
|
||||
},
|
||||
extensionDetails: {
|
||||
flex: 1,
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginLeft: 16,
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,65 @@
|
||||
import React from "react";
|
||||
import { View, Text, Image, StyleSheet } from "react-native";
|
||||
import { TouchableRipple } from "react-native-paper";
|
||||
import moment from "moment";
|
||||
|
||||
const UpdateCard = ({ item, theme, onPress }) => {
|
||||
return (
|
||||
<TouchableRipple
|
||||
style={styles.updateCard}
|
||||
onPress={onPress}
|
||||
rippleColor={theme.rippleColor}
|
||||
borderless
|
||||
>
|
||||
<>
|
||||
<Image
|
||||
source={{ uri: item.novelCover }}
|
||||
style={styles.updateIcon}
|
||||
/>
|
||||
<View style={styles.chapterDetails}>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorPrimary,
|
||||
fontSize: 14,
|
||||
}}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{item.novelName}
|
||||
</Text>
|
||||
<View style={{ flexDirection: "row" }}>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorPrimary,
|
||||
fontSize: 12,
|
||||
}}
|
||||
>
|
||||
{`${item.chapterName} · ${moment(
|
||||
item.updateTime
|
||||
).calendar()}`}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
</TouchableRipple>
|
||||
);
|
||||
};
|
||||
|
||||
export default UpdateCard;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
updateCard: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
paddingVertical: 8,
|
||||
paddingHorizontal: 12,
|
||||
},
|
||||
updateIcon: {
|
||||
width: 42,
|
||||
height: 42,
|
||||
borderRadius: 4,
|
||||
},
|
||||
chapterDetails: {
|
||||
flex: 1,
|
||||
marginLeft: 16,
|
||||
},
|
||||
});
|
||||
@@ -3,13 +3,13 @@ export const fetchSources = async () => {
|
||||
|
||||
let res = await fetch(url);
|
||||
let sources = await res.json();
|
||||
// console.log(sources);
|
||||
|
||||
return sources;
|
||||
};
|
||||
|
||||
export const fetchNovel = async (sourceId, novelUrl) => {
|
||||
const url = `https://lnreader-extensions.vercel.app/api/${sourceId}/novel/${novelUrl}`;
|
||||
// console.log(url);
|
||||
|
||||
let data = await fetch(url);
|
||||
let res = await data.json();
|
||||
|
||||
@@ -35,8 +35,6 @@ export const fetchNovel = async (sourceId, novelUrl) => {
|
||||
export const fetchChapter = async (sourceId, novelUrl, chapterUrl) => {
|
||||
const url = `https://lnreader-extensions.vercel.app/api/${sourceId}/novel/${novelUrl}${chapterUrl}`;
|
||||
|
||||
// console.log(url);
|
||||
|
||||
let res = await fetch(url);
|
||||
let chapter = await res.json();
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import * as DocumentPicker from "expo-document-picker";
|
||||
import { Platform } from "react-native";
|
||||
import * as FileSystem from "expo-file-system";
|
||||
import { StorageAccessFramework } from "expo-file-system";
|
||||
|
||||
import { getLibrary } from "../Database/queries/LibraryQueries";
|
||||
|
||||
+2
-10
@@ -3,7 +3,6 @@ const db = SQLite.openDatabase("lnreader.db");
|
||||
|
||||
import { getLibrary } from "../Database/queries/LibraryQueries";
|
||||
import { fetchChapters, fetchNovel } from "../Services/Source/source";
|
||||
import { ToastAndroid } from "react-native";
|
||||
|
||||
const updateNovelDetails = async (novel, novelId) => {
|
||||
db.transaction((tx) => {
|
||||
@@ -27,7 +26,7 @@ const updateNovelDetails = async (novel, novelId) => {
|
||||
|
||||
export const updateNovel = async (extensionId, novelUrl, novelId) => {
|
||||
let novel = await fetchNovel(extensionId, novelUrl);
|
||||
// console.log(novel);
|
||||
|
||||
await updateNovelDetails(novel, novelId);
|
||||
|
||||
db.transaction((tx) => {
|
||||
@@ -89,14 +88,7 @@ export const updateNovelChapters = async (extensionId, novelUrl, novelId) => {
|
||||
tx.executeSql(
|
||||
"INSERT OR IGNORE INTO updates (chapterId, novelId, updateTime) values (?, ?, (datetime('now','localtime')))",
|
||||
[insertId, novelId],
|
||||
(txObj, res) => {
|
||||
// console.log(
|
||||
// "Inserted Chapter Id -> " +
|
||||
// insertId +
|
||||
// " Novel Id " +
|
||||
// novelId
|
||||
// );
|
||||
},
|
||||
(txObj, res) => {},
|
||||
(txObj, error) => console.log("Error ", error)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Reader fonts
|
||||
*/
|
||||
|
||||
export const fonts = {
|
||||
"pt-sans-bold": require("../../assets/fonts/PTSansNarrow-Bold.ttf"),
|
||||
"arbutus-slab": require("../../assets/fonts/ArbutusSlab-Regular.ttf"),
|
||||
domine: require("../../assets/fonts/Domine-VariableFont_wght.ttf"),
|
||||
lato: require("../../assets/fonts/Lato-Regular.ttf"),
|
||||
"noto-sans": require("../../assets/fonts/NotoSans-Regular.ttf"),
|
||||
"open-sans": require("../../assets/fonts/OpenSans-Regular.ttf"),
|
||||
"pt-serif": require("../../assets/fonts/PTSerif-Regular.ttf"),
|
||||
};
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
getLibrary,
|
||||
searchLibrary,
|
||||
} from "../../Database/queries/LibraryQueries";
|
||||
import { restoreBackup } from "../../Services/backup";
|
||||
|
||||
export const getLibraryAction = () => async (dispatch) => {
|
||||
const res = await getLibrary();
|
||||
@@ -24,3 +25,14 @@ export const searchLibraryAction = (searchText) => async (dispatch) => {
|
||||
payload: res,
|
||||
});
|
||||
};
|
||||
|
||||
export const restoreLibraryAction = () => async (dispatch) => {
|
||||
await restoreBackup();
|
||||
|
||||
const res = await getLibrary();
|
||||
|
||||
dispatch({
|
||||
type: GET_LIBRARY_NOVELS,
|
||||
payload: res,
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user