From 927a04778f3a69241530a7487722507f47f8f43a Mon Sep 17 00:00:00 2001 From: Xing Yi Date: Thu, 9 Nov 2023 09:29:27 +0800 Subject: [PATCH] feat: cache articles and positions in page --- android/app/build.gradle | 4 +- android/app/src/main/AndroidManifest.xml | 4 +- .../main/play/release-notes/en-US/default.txt | 4 +- package.json | 2 +- src/components/QueryScreen.js | 167 +----------- .../QueryScreen/ArticleBottomBar.js | 12 +- src/components/QueryScreen/ArticleView.js | 81 ++++-- .../QueryScreen/DictionarySelection.js | 20 +- src/components/QueryScreen/Input.js | 15 +- src/components/QueryScreen/QueryBar.js | 20 +- src/components/QueryScreen/QueryContent.js | 58 ++--- src/components/QueryScreen/QueryContext.js | 241 ++++++++++++++++++ src/config.js | 3 +- 13 files changed, 365 insertions(+), 266 deletions(-) create mode 100644 src/components/QueryScreen/QueryContext.js diff --git a/android/app/build.gradle b/android/app/build.gradle index f172814..eba30be 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -78,8 +78,8 @@ android { applicationId "com.gmail.blandilyte.silverdict" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 5 - versionName "1.0.7" + versionCode 6 + versionName "1.1.0" } signingConfigs { debug { diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 6a372ce..dc5a24a 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="6" + android:versionName="1.1.0"> diff --git a/android/app/src/main/play/release-notes/en-US/default.txt b/android/app/src/main/play/release-notes/en-US/default.txt index 7bd1cd9..011be38 100644 --- a/android/app/src/main/play/release-notes/en-US/default.txt +++ b/android/app/src/main/play/release-notes/en-US/default.txt @@ -1,2 +1,2 @@ -Fix: -Retain the old search term when a suggestion is selected. This is the behaviour of GoldenDict. \ No newline at end of file +New Feature: +Caching the search results in memory. \ No newline at end of file diff --git a/package.json b/package.json index 3b20f06..f822d7a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "SilverDict", - "version": "1.0.7", + "version": "1.1.0", "private": true, "scripts": { "android": "react-native run-android", diff --git a/src/components/QueryScreen.js b/src/components/QueryScreen.js index 17ef66b..68e40e9 100644 --- a/src/components/QueryScreen.js +++ b/src/components/QueryScreen.js @@ -1,164 +1,19 @@ -import React, { useState, useEffect, useRef } from 'react'; +import React from 'react'; import { View } from 'react-native'; -import { loadDataFromJsonResponse } from '../utils'; +import { QueryProvider } from './QueryScreen/QueryContext'; import QueryBar from './QueryScreen/QueryBar'; import QueryContent from './QueryScreen/QueryContent'; -import { useAppContext } from '../AppContext'; -import { localisedStrings } from '../translations/l10n'; export default function QueryScreen({ navigation }) { - const { serverAddress, dictionaries, groups, groupings, history, setHistory, sizeSuggestion } = useAppContext(); - const apiPrefix = `${serverAddress}/api`; - const [query, setQuery] = useState(''); - const textInputRef = useRef(null); - - const [localHistory, setLocalHistory] = useState([]); - const [locationInLocalHistory, setLocationInLocalHistory] = useState(0); - - const [latestSuggestionsTimestamp, setLatestSuggestionsTimestamp] = useState(0); - const [suggestions, setSuggestions] = useState([]); - - const [nameActiveGroup, setNameActiveGroup] = useState('Default Group'); - - const [article, setArticle] = useState(''); - const [namesActiveDictionaries, setNamesActiveDictionaries] = useState([]); - const [nameDictionaryToJumpTo, setNameDictionaryToJumpTo] = useState(''); - - useEffect(function() { - setNameActiveGroup('Default Group'); - }, [groups.length]); - - useEffect(function () { - if (query.length === 0) { - setLatestSuggestionsTimestamp(Date.now()); - setSuggestions(['']); - resetNamesActiveDictionaries(); - } else { - fetch(`${apiPrefix}/suggestions/${nameActiveGroup}/${encodeURIComponent(query)}?timestamp=${Date.now()}`) - .then(loadDataFromJsonResponse) - .then((data) => { - if (data['timestamp'] > latestSuggestionsTimestamp) { - setLatestSuggestionsTimestamp(data['timestamp']); - // Filter out empty suggestions - const newSuggestions = data['suggestions'].filter((suggestion) => suggestion.length > 0); - if (newSuggestions.length > 0) { - setSuggestions(newSuggestions); - } else { - setSuggestions(['']); - } - } - }) - .catch((error) => { - alert(localisedStrings['query-screen-failure-fetch-suggestions']); - }); - } - }, [dictionaries, groupings, nameActiveGroup, query, sizeSuggestion]); - - useEffect(function() { - search(query); - }, [nameActiveGroup]); - - function search(newQuery) { - if (newQuery.length === 0) { - return; - } - - try { - newQuery = decodeURIComponent(newQuery); - // setQuery(newQuery); - newQuery = encodeURIComponent(newQuery); - } - catch (error) { - // setQuery(newQuery); - newQuery = encodeURIComponent(newQuery); - } - - fetch(`${apiPrefix}/query/${nameActiveGroup}/${newQuery}?dicts=True`) - .then(loadDataFromJsonResponse) - .then((data) => { - setArticle(data['articles']); - setNamesActiveDictionaries(data['dictionaries']); - - fetch(`${apiPrefix}/management/history`) - .then(loadDataFromJsonResponse) - .then((data) => { - setHistory(data); - }); - }) - .catch((error) => { - resetNamesActiveDictionaries(); - alert(localisedStrings['query-screen-failure-fetch-articles']); - }); - } - - function setQueryAndFocusOnInput(newQuery) { - setQuery(newQuery); - textInputRef.current.focus(); - } - - function resetNamesActiveDictionaries() { - if (groupings[nameActiveGroup]) { - const dictionariesInGroup = []; - for (let dictionary of dictionaries) { - if (groupings[nameActiveGroup].includes(dictionary.name)) { - dictionariesInGroup.push(dictionary.name); - } - } - setNamesActiveDictionaries(dictionariesInGroup); - } - } - - function searchBranching(newQuery) { - search(newQuery); - // If the current location is not the end of the local history, pop to the current location - setLocationInLocalHistory(localHistory.length); - setLocalHistory([...localHistory.slice(0, locationInLocalHistory + 1), newQuery]); - } - - function searchInLocalHistory(direction) { - search(localHistory[locationInLocalHistory + direction]); - setLocationInLocalHistory(locationInLocalHistory + direction); - } - - function handleInputSubmit(e) { - const firstSuggetion = suggestions[0]; - if (firstSuggetion && firstSuggetion.length > 0) { - searchBranching(firstSuggetion); - } else { - searchBranching(query); - } - } return ( - - - 0} - ableToGoForward={locationInLocalHistory < localHistory.length - 1} - /> - + + + + + + ); -} \ No newline at end of file +} diff --git a/src/components/QueryScreen/ArticleBottomBar.js b/src/components/QueryScreen/ArticleBottomBar.js index 277b7e8..39897ec 100644 --- a/src/components/QueryScreen/ArticleBottomBar.js +++ b/src/components/QueryScreen/ArticleBottomBar.js @@ -2,13 +2,15 @@ import React, { useState } from 'react'; import { View } from 'react-native'; import { Appbar, TextInput, useTheme } from 'react-native-paper'; import { TEXT_ZOOM_MAX, TEXT_ZOOM_MIN } from '../../config'; +import { useQueryContext } from './QueryContext'; import { localisedStrings } from '../../translations/l10n'; const TEXT_ZOOM_STEP = 10; -export default function ArticleBottomBar(props) { +export default function ArticleBottomBar() { const onSurfaceColour = useTheme().colors.onSurface; - const { searchInLocalHistory, ableToGoBack, ableToGoForward, textZoom, setTextZoom, findInPageRef } = props; + const { ableToGoBackInHistory, ableToGoForwardInHistory, searchInLocalHistory, textZoom, setTextZoom, findInPageRef } = useQueryContext(); + const [findBarActive, setFindBarActive] = useState(false); const [wordToFind, setWordToFind] = useState(''); @@ -69,7 +71,7 @@ export default function ArticleBottomBar(props) { { - ableToGoBack ? + ableToGoBackInHistory ? } { - ableToGoForward ? + ableToGoForwardInHistory ? ); -} \ No newline at end of file +} diff --git a/src/components/QueryScreen/ArticleView.js b/src/components/QueryScreen/ArticleView.js index 0221239..6a585e7 100644 --- a/src/components/QueryScreen/ArticleView.js +++ b/src/components/QueryScreen/ArticleView.js @@ -1,13 +1,15 @@ -import React, { useRef, useEffect, useState } from 'react'; +import React, { useRef, useState } from 'react'; import { View } from 'react-native'; import AutoHeightWebView from 'react-native-autoheight-webview'; import { Button, Dialog, Portal, Text, useTheme } from 'react-native-paper'; +import { ADDITIONAL_GOOGLE_FONTS, SEPARATOR } from '../../config'; import { useAppContext } from '../../AppContext'; +import { useQueryContext } from './QueryContext'; import { localisedStrings } from '../../translations/l10n'; -import { ADDITIONAL_GOOGLE_FONTS } from '../../config'; function ConfirmSearchDialogue(props) { - const { visible, wordSelected, setWordSelected, setQuery, search } = props; + const { visible, wordSelected, setWordSelected } = props; + const { searchBranching, setQueryAndFocusOnInput } = useQueryContext(); return ( @@ -24,13 +26,13 @@ function ConfirmSearchDialogue(props) { {localisedStrings['generic-no']}