diff --git a/src/assets/translations/en.ts b/src/assets/translations/en.ts index ae00dc0c..a7c9260f 100644 --- a/src/assets/translations/en.ts +++ b/src/assets/translations/en.ts @@ -23,6 +23,7 @@ export default { cancel: 'Cancel', ok: 'Ok', checkUpdate: 'Check for Update', + checkingUpdate: 'Checking for update...', foundNewVersion: 'New version found', pleaseUpdate: 'New version found. Please go to Settings to download the update.', diff --git a/src/assets/translations/zh.ts b/src/assets/translations/zh.ts index 32a3b7ef..6d03097b 100644 --- a/src/assets/translations/zh.ts +++ b/src/assets/translations/zh.ts @@ -22,6 +22,7 @@ export default { logoutSuccess: '注销成功', cancel: '取消', ok: '确定', + checkingUpdate: '检查更新中……', checkUpdate: '检查更新', foundNewVersion: '发现新版本', pleaseUpdate: '发现新版本,请前往设置下载更新', diff --git a/src/helpers/update.ts b/src/helpers/update.ts index 8ed4a126..e2c6fffa 100644 --- a/src/helpers/update.ts +++ b/src/helpers/update.ts @@ -25,3 +25,12 @@ export const getLatestRelease = async () => { }; } }; + +export const getReleaseNote = async (version: string) => { + const response = await fetch( + `https://api.github.com/repos/robertying/learnX/releases/tags/v${version}`, + ); + const json = await response.json(); + const body = json.body as string; + return body; +}; diff --git a/src/screens/SettingScreen.tsx b/src/screens/SettingScreen.tsx index 41c8627d..9a37afee 100644 --- a/src/screens/SettingScreen.tsx +++ b/src/screens/SettingScreen.tsx @@ -1,4 +1,4 @@ -import React, {useEffect} from 'react'; +import React, {useEffect, useRef, useState} from 'react'; import { Alert, Linking, @@ -6,13 +6,16 @@ import { SafeAreaView, View, ScrollView, + useWindowDimensions, + Text, } from 'react-native'; import { Navigation, OptionsModalPresentationStyle, } from 'react-native-navigation'; import fs from 'react-native-fs'; -import {iOSColors} from 'react-native-typography'; +import Modal from 'react-native-modal'; +import {iOSColors, iOSUIKit} from 'react-native-typography'; import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'; import MaterialIcons from 'react-native-vector-icons/MaterialIcons'; import {useDispatch} from 'react-redux'; @@ -21,7 +24,7 @@ import SettingListItem from '../components/SettingListItem'; import Colors from '../constants/Colors'; import {getTranslation} from '../helpers/i18n'; import Snackbar from 'react-native-snackbar'; -import {getLatestRelease} from '../helpers/update'; +import {getLatestRelease, getReleaseNote} from '../helpers/update'; import {clearStore} from '../redux/actions/root'; import {setSetting} from '../redux/actions/settings'; import {INavigationScreen} from '../types'; @@ -33,6 +36,9 @@ import {useColorScheme} from 'react-native-appearance'; import {useTypedSelector} from '../redux/store'; import {fileDir} from '../helpers/fs'; import {ISettingsState} from '../redux/types/state'; +import Button from '../components/Button'; +import MarkdownWebView from 'react-native-github-markdown'; +import WebView, {WebViewProps} from 'react-native-webview'; const SettingScreen: INavigationScreen = (props) => { const colorScheme = useColorScheme(); @@ -93,37 +99,6 @@ const SettingScreen: INavigationScreen = (props) => { ); }; - const onCheckUpdatePress = async () => { - const {version, url} = await getLatestRelease(); - - if (semverGt(version, packageConfig.version)) { - Alert.alert( - getTranslation('checkUpdate'), - `${getTranslation('foundNewVersion')} v${version}`, - [ - { - text: getTranslation('cancel'), - style: 'cancel', - }, - { - text: getTranslation('update'), - onPress: () => { - Linking.openURL(url); - }, - }, - ], - {cancelable: true}, - ); - dispatch(setSetting('hasUpdate', true)); - } else { - Snackbar.show({ - text: getTranslation('noUpdate'), - duration: Snackbar.LENGTH_LONG, - }); - dispatch(setSetting('hasUpdate', false)); - } - }; - const onClearFileCachePress = () => { Alert.alert( getTranslation('clearFileCache'), @@ -165,6 +140,52 @@ const SettingScreen: INavigationScreen = (props) => { adaptToSystemTheme(props.componentId, colorScheme, true); }, [colorScheme, props.componentId]); + const window = useWindowDimensions(); + + const webViewRef = useRef(null); + + const onNavigationStateChange: WebViewProps['onNavigationStateChange'] = ( + e, + ) => { + if (e.navigationType === 'click') { + if (webViewRef.current) { + webViewRef.current.stopLoading(); + } + Linking.openURL(e.url); + } + }; + + const [release, setRelease] = useState<{version: string; url: string}>(); + + const [releaseNote, setReleaseNote] = useState(''); + + const onCheckUpdatePress = async () => { + setReleaseNote(''); + + Snackbar.show({ + text: getTranslation('checkingUpdate'), + duration: Snackbar.LENGTH_LONG, + }); + + const {version, url} = await getLatestRelease(); + + try { + const releaseNote = await getReleaseNote(version); + setReleaseNote(releaseNote); + } catch {} + + if (semverGt(version, packageConfig.version)) { + setRelease({version, url}); + dispatch(setSetting('hasUpdate', true)); + } else { + Snackbar.show({ + text: getTranslation('noUpdate'), + duration: Snackbar.LENGTH_LONG, + }); + dispatch(setSetting('hasUpdate', false)); + } + }; + return ( { onPress={() => navigate('settings.about')} /> + setRelease(undefined)} + backdropColor={ + colorScheme === 'dark' ? 'rgba(255,255,255,0.25)' : undefined + } + animationIn="bounceIn" + animationOut="zoomOut" + deviceHeight={window.height} + deviceWidth={window.width} + useNativeDriver={true} + hideModalContentWhileAnimating={true}> + + + {release?.version ? `v${release?.version}` : ''} + + + + + + + + ); };