Refactor App Update Checker
This commit is contained in:
@@ -12,13 +12,14 @@ import { Provider as PaperProvider } from 'react-native-paper';
|
||||
import { Provider } from 'react-redux';
|
||||
import { PersistGate } from 'redux-persist/lib/integration/react';
|
||||
import * as Notifications from 'expo-notifications';
|
||||
import { BottomSheetModalProvider } from '@gorhom/bottom-sheet';
|
||||
|
||||
import { createDatabase } from '@database/db';
|
||||
import { persistor, store } from '@redux/store';
|
||||
import AppErrorBoundary from '@components/AppErrorBoundary/AppErrorBoundary';
|
||||
import NewUpdateDialog from '@components/NewUpdateDialog';
|
||||
|
||||
import Main from './src/navigators/Main';
|
||||
import { BottomSheetModalProvider } from '@gorhom/bottom-sheet';
|
||||
|
||||
// Initialize trackers
|
||||
import './src/services/Trackers/index';
|
||||
@@ -49,6 +50,7 @@ const App = () => {
|
||||
<SafeAreaProvider>
|
||||
<PaperProvider>
|
||||
<BottomSheetModalProvider>
|
||||
<NewUpdateDialog />
|
||||
<StatusBar translucent={true} backgroundColor="transparent" />
|
||||
<Main />
|
||||
</BottomSheetModalProvider>
|
||||
|
||||
@@ -1,52 +1,57 @@
|
||||
import React, { useState } from 'react';
|
||||
import { StyleSheet, View, Text, Dimensions } from 'react-native';
|
||||
import React, { useEffect } from 'react';
|
||||
import { ScrollView, StyleSheet, View, Text, Dimensions } from 'react-native';
|
||||
import { Portal, Modal } from 'react-native-paper';
|
||||
import * as Linking from 'expo-linking';
|
||||
import { ScrollView } from 'react-native-gesture-handler';
|
||||
import Button from './Button/Button';
|
||||
|
||||
import { Button } from '@components';
|
||||
|
||||
import { useBoolean, useReleaseChecker, useTheme } from '@hooks';
|
||||
import { getString } from '@strings/translations';
|
||||
|
||||
import { useTheme } from '@hooks/useTheme';
|
||||
|
||||
interface NewUpdateDialogProps {
|
||||
newVersion: {
|
||||
tag_name: string;
|
||||
body: string;
|
||||
downloadUrl: string;
|
||||
};
|
||||
}
|
||||
|
||||
const NewUpdateDialog: React.FC<NewUpdateDialogProps> = ({ newVersion }) => {
|
||||
const [newUpdateDialog, showNewUpdateDialog] = useState(true);
|
||||
|
||||
const NewUpdateDialog: React.FC = () => {
|
||||
const theme = useTheme();
|
||||
|
||||
const newRelease = useReleaseChecker();
|
||||
|
||||
const {
|
||||
value: isVisible,
|
||||
setFalse: hideModal,
|
||||
setValue: setModalVisible,
|
||||
} = useBoolean();
|
||||
|
||||
useEffect(() => {
|
||||
setModalVisible(Boolean(newRelease));
|
||||
}, [newRelease]);
|
||||
|
||||
const modalHeight = Dimensions.get('window').height / 2;
|
||||
|
||||
if (!newRelease) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
<Modal
|
||||
visible={newUpdateDialog}
|
||||
onDismiss={() => showNewUpdateDialog(false)}
|
||||
visible={isVisible}
|
||||
onDismiss={hideModal}
|
||||
contentContainerStyle={[
|
||||
styles.containerStyle,
|
||||
{ backgroundColor: theme.overlay3 },
|
||||
]}
|
||||
>
|
||||
<Text style={[styles.modalHeader, { color: theme.onSurface }]}>
|
||||
{`${getString('common.newUpdateAvailable')} ${newVersion.tag_name}`}
|
||||
{`${getString('common.newUpdateAvailable')} ${newRelease?.tagName}`}
|
||||
</Text>
|
||||
<ScrollView style={{ height: modalHeight }}>
|
||||
{newVersion.body}
|
||||
<Text style={{ color: theme.onSurface }}>
|
||||
{newRelease?.changelog}
|
||||
</Text>
|
||||
</ScrollView>
|
||||
<View style={styles.buttonCtn}>
|
||||
<Button
|
||||
title={getString('common.cancel')}
|
||||
onPress={() => showNewUpdateDialog(false)}
|
||||
/>
|
||||
<Button title={getString('common.cancel')} onPress={hideModal} />
|
||||
<Button
|
||||
title={getString('common.install')}
|
||||
onPress={() => Linking.openURL(newVersion.downloadUrl)}
|
||||
onPress={() => Linking.openURL(newRelease?.downloadUrl)}
|
||||
/>
|
||||
</View>
|
||||
</Modal>
|
||||
@@ -67,7 +72,6 @@ const styles = StyleSheet.create({
|
||||
fontSize: 20,
|
||||
marginBottom: 16,
|
||||
},
|
||||
body: {},
|
||||
buttonCtn: {
|
||||
flexDirection: 'row',
|
||||
marginTop: 16,
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { appVersion } from '../utils/versionUtils';
|
||||
|
||||
export const useGithubUpdateChecker = () => {
|
||||
const latestReleaseUrl =
|
||||
'https://api.github.com/repos/rajarsheechatterjee/lnreader/releases/latest';
|
||||
|
||||
const [checking, setChecking] = useState(true);
|
||||
const [latestRelease, setLatestRelease] = useState();
|
||||
|
||||
const checkForRelease = async () => {
|
||||
let res = await fetch(latestReleaseUrl);
|
||||
res = await res.json();
|
||||
|
||||
const release = {
|
||||
tag_name: res.tag_name,
|
||||
body: res.body,
|
||||
downloadUrl: res.assets[0].browser_download_url,
|
||||
};
|
||||
|
||||
setLatestRelease(release);
|
||||
setChecking(false);
|
||||
};
|
||||
|
||||
const isNewVersion = versionTag => {
|
||||
const regex = /[^\\d.]/;
|
||||
|
||||
const currentVersion = appVersion;
|
||||
const newVersion = versionTag.replace(regex, '');
|
||||
|
||||
const newSemVer = newVersion.split('.');
|
||||
const oldSemVer = currentVersion.split('.');
|
||||
|
||||
return oldSemVer?.some((version, index) => {
|
||||
if (newSemVer[index] > version) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
checkForRelease();
|
||||
// .catch(e => {
|
||||
// showToast(`Could not connect to github:\n${`${e}`.split(':')[1].trim()}`);
|
||||
// // console.error(e);
|
||||
// });
|
||||
}, []);
|
||||
|
||||
if (!checking) {
|
||||
const data = {
|
||||
latestRelease,
|
||||
isNewVersion: isNewVersion(latestRelease.tag_name),
|
||||
};
|
||||
|
||||
return data;
|
||||
}
|
||||
};
|
||||
@@ -10,3 +10,4 @@ export { useTheme } from './useTheme';
|
||||
export { default as useCategories } from './useCategories';
|
||||
export { useCategorySettings, useLibrarySettings } from './useSettings';
|
||||
export { usePreviousRouteName } from './usePreviousRouteName';
|
||||
export { useReleaseChecker } from './useReleaseChecker';
|
||||
|
||||
@@ -12,12 +12,6 @@ const useNovel = () => {
|
||||
return novel;
|
||||
};
|
||||
|
||||
const useChapter = () => {
|
||||
const chapter = useSelector(state => state.chapterReducer);
|
||||
|
||||
return chapter;
|
||||
};
|
||||
|
||||
const useFindNovel = novelId => {
|
||||
let novel = useSelector(state => state.preferenceReducer.novelSettings);
|
||||
novel = novel[novelId];
|
||||
@@ -90,7 +84,6 @@ export {
|
||||
usePreferences,
|
||||
useContinueReading,
|
||||
useNovel,
|
||||
useChapter,
|
||||
useSavedSettings,
|
||||
usePosition,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import dayjs from 'dayjs';
|
||||
import { useMMKVNumber } from 'react-native-mmkv';
|
||||
|
||||
import { appVersion } from '../utils/versionUtils';
|
||||
import { showToast } from './showToast';
|
||||
|
||||
const LATEST_RELEASE_URL =
|
||||
'https://api.github.com/repos/LNReader/lnreader/releases/latest';
|
||||
|
||||
export interface NewRelease {
|
||||
tagName: string;
|
||||
changelog: string;
|
||||
downloadUrl: string;
|
||||
}
|
||||
|
||||
const isNewVersion = (versionTag: string) => {
|
||||
const regex = /[^\\d.]/;
|
||||
|
||||
const currentVersion = appVersion;
|
||||
const newVersion = versionTag.replace(regex, '');
|
||||
|
||||
const newSemVer = newVersion.split('.');
|
||||
const oldSemVer = currentVersion.split('.');
|
||||
|
||||
return oldSemVer?.some((version, index) => {
|
||||
if (newSemVer[index] > version) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useReleaseChecker = () => {
|
||||
const [lastChecked, setLastChecked] = useMMKVNumber('last_app_update_check');
|
||||
const [newRelease, setNewRelease] = useState<NewRelease>();
|
||||
|
||||
const getNewRelease = async () => {
|
||||
try {
|
||||
if (lastChecked && dayjs(lastChecked).diff(undefined, 'hours') < 24) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newReleaseRes = await fetch(LATEST_RELEASE_URL);
|
||||
const newReleaseJSON = await newReleaseRes.json();
|
||||
|
||||
if (isNewVersion(newReleaseJSON.tag_name)) {
|
||||
setNewRelease({
|
||||
changelog: newReleaseJSON.body,
|
||||
downloadUrl: newReleaseJSON.assets[0].browser_download_url,
|
||||
tagName: newReleaseJSON.tag_name,
|
||||
});
|
||||
}
|
||||
|
||||
setLastChecked(+Date.now());
|
||||
} catch (error: any) {
|
||||
showToast(error.message);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getNewRelease();
|
||||
}, []);
|
||||
|
||||
return newRelease;
|
||||
};
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from 'react';
|
||||
import Color from 'color';
|
||||
import { createMaterialBottomTabNavigator } from '@react-navigation/material-bottom-tabs';
|
||||
|
||||
import Library from '../screens/library/LibraryScreen';
|
||||
@@ -5,7 +5,6 @@ import { createStackNavigator } from '@react-navigation/stack';
|
||||
|
||||
import { setBarColor } from '../theme/utils/setBarColor';
|
||||
import { useTheme } from '../hooks/useTheme';
|
||||
import { useGithubUpdateChecker } from '../hooks/githubUpdateChecker';
|
||||
|
||||
/**
|
||||
* Navigators
|
||||
@@ -26,7 +25,6 @@ import MigrateNovel from '../screens/browse/migration/MigrationNovels';
|
||||
|
||||
import MalTopNovels from '../screens/browse/discover/MalTopNovels';
|
||||
import AniListTopNovels from '../screens/browse/discover/AniListTopNovels';
|
||||
import NewUpdateDialog from '../components/NewUpdateDialog';
|
||||
import BrowseSettings from '../screens/browse/BrowseSettings';
|
||||
import { useAppDispatch } from '@redux/hooks';
|
||||
import { updateLibraryAction } from '@redux/updates/updates.actions';
|
||||
@@ -56,11 +54,8 @@ const MainNavigator = () => {
|
||||
}
|
||||
}, []);
|
||||
|
||||
const { isNewVersion, latestRelease } = useGithubUpdateChecker() || {};
|
||||
|
||||
return (
|
||||
<NavigationContainer theme={{ colors: theme }}>
|
||||
{isNewVersion && <NewUpdateDialog newVersion={latestRelease} />}
|
||||
<Stack.Navigator screenOptions={{ headerShown: false }}>
|
||||
<Stack.Screen name="BottomNavigator" component={BottomNavigator} />
|
||||
<Stack.Screen name="Novel" component={Novel} />
|
||||
|
||||
Reference in New Issue
Block a user