Various fixes (#56)

* Add missing translation for progress synced toast

* Graceful shutdown after all books closed, closes #50

* Throttle app update check to once every day

* Avoid infinite loop to redirect to the login page, closes #54
This commit is contained in:
Huang Xin
2024-12-27 16:59:06 +01:00
committed by GitHub
parent cb2c7b5c89
commit 3dcab5a1ee
23 changed files with 73 additions and 17 deletions
+15 -3
View File
@@ -9,15 +9,17 @@ import { FcGoogle } from 'react-icons/fc';
import { FaApple } from 'react-icons/fa';
import { VscAzure } from 'react-icons/vsc';
import { FaGithub } from 'react-icons/fa';
import { IoArrowBack } from 'react-icons/io5';
import { useAuth } from '@/context/AuthContext';
import { supabase } from '@/utils/supabase';
import { useTheme } from '@/hooks/useTheme';
import { useEnv } from '@/context/EnvContext';
import { useSettingsStore } from '@/store/settingsStore';
import { isTauriAppPlatform } from '@/services/environment';
import { start, cancel, onUrl, onInvalidUrl } from '@fabianlars/tauri-plugin-oauth';
import { openUrl } from '@tauri-apps/plugin-opener';
import { handleAuthCallback } from '@/helpers/auth';
import { IoArrowBack } from 'react-icons/io5';
type OAuthProvider = 'google' | 'apple' | 'azure' | 'github';
@@ -46,7 +48,9 @@ const ProviderLogin: React.FC<ProviderLoginProp> = ({ provider, handleSignIn, Ic
export default function AuthPage() {
const router = useRouter();
const { login } = useAuth();
const { envConfig } = useEnv();
const { isDarkMode } = useTheme();
const { settings, setSettings, saveSettings } = useSettingsStore();
const [port, setPort] = useState<number | null>(null);
const isOAuthServerRunning = useRef(false);
const [isMounted, setIsMounted] = useState(false);
@@ -109,6 +113,14 @@ export default function AuthPage() {
}
};
const handleGoBack = () => {
// Keep login false to avoid infinite loop to redirect to the login page
settings.keepLogin = false;
setSettings(settings);
saveSettings(envConfig, settings);
router.back();
};
useEffect(() => {
if (!isTauriAppPlatform()) return;
if (isOAuthServerRunning.current) return;
@@ -147,7 +159,7 @@ export default function AuthPage() {
return isTauriAppPlatform() ? (
<div className='flex pt-11'>
<button
onClick={() => router.back()}
onClick={handleGoBack}
className='btn btn-ghost fixed left-3 top-11 h-8 min-h-8 w-8 p-0'
>
<IoArrowBack size={20} />
@@ -191,7 +203,7 @@ export default function AuthPage() {
) : (
<div style={{ maxWidth: '420px', margin: 'auto', padding: '2rem', paddingTop: '4rem' }}>
<button
onClick={() => router.back()}
onClick={handleGoBack}
className='btn btn-ghost fixed left-10 top-6 h-8 min-h-8 w-8 p-0'
>
<IoArrowBack size={20} />
@@ -11,7 +11,8 @@ import { useReaderStore } from '@/store/readerStore';
import { useSidebarStore } from '@/store/sidebarStore';
import { SystemSettings } from '@/types/settings';
import { parseOpenWithFiles } from '@/helpers/cli';
import { tauriHandleClose } from '@/utils/window';
import { tauriHandleClose, tauriHandleOnCloseWindow } from '@/utils/window';
import { isTauriAppPlatform } from '@/services/environment';
import { uniqueId } from '@/utils/misc';
import { navigateToLibrary } from '@/utils/nav';
import { BOOK_IDS_SEPARATOR } from '@/services/constants';
@@ -61,6 +62,7 @@ const ReaderContent: React.FC<{ ids?: string; settings: SystemSettings }> = ({ i
}, []);
useEffect(() => {
if (isTauriAppPlatform()) tauriHandleOnCloseWindow(handleCloseBooks);
window.addEventListener('beforeunload', handleCloseBooks);
return () => {
window.removeEventListener('beforeunload', handleCloseBooks);
@@ -68,12 +70,12 @@ const ReaderContent: React.FC<{ ids?: string; settings: SystemSettings }> = ({ i
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [bookKeys]);
const saveBookConfig = (bookKey: string) => {
const saveBookConfig = async (bookKey: string) => {
const config = getConfig(bookKey);
const { book } = getBookData(bookKey) || {};
const { isPrimary } = getViewState(bookKey) || {};
if (isPrimary && book && config) {
saveConfig(envConfig, bookKey, config, settings);
await saveConfig(envConfig, bookKey, config, settings);
}
};
@@ -81,7 +83,7 @@ const ReaderContent: React.FC<{ ids?: string; settings: SystemSettings }> = ({ i
console.log('Closing book', bookKey);
getView(bookKey)?.close();
getView(bookKey)?.remove();
saveBookConfig(bookKey);
await saveBookConfig(bookKey);
clearViewState(bookKey);
};
@@ -90,11 +92,9 @@ const ReaderContent: React.FC<{ ids?: string; settings: SystemSettings }> = ({ i
navigateToLibrary(router);
};
const handleCloseBooks = () => {
bookKeys.forEach((key) => {
saveConfigAndCloseBook(key);
});
saveSettings(envConfig, settings);
const handleCloseBooks = async () => {
await Promise.all(bookKeys.map((key) => saveConfigAndCloseBook(key)));
await saveSettings(envConfig, settings);
};
const handleCloseBooksToLibrary = () => {
@@ -5,6 +5,7 @@ import { BookConfig } from '@/types/book';
import { useBookDataStore } from '@/store/bookDataStore';
import { useReaderStore } from '@/store/readerStore';
import { useSettingsStore } from '@/store/settingsStore';
import { useTranslation } from '@/hooks/useTranslation';
import { deserializeConfig, serializeConfig } from '@/utils/serializer';
import { DEFAULT_BOOK_SEARCH_CONFIG, SYNC_PROGRESS_INTERVAL_SEC } from '@/services/constants';
@@ -12,6 +13,7 @@ export const useProgressSync = (
bookKey: string,
setToastMessage?: React.Dispatch<React.SetStateAction<string>>,
) => {
const _ = useTranslation();
const { getConfig, setConfig } = useBookDataStore();
const { getView } = useReaderStore();
const { settings } = useSettingsStore();
@@ -81,7 +83,7 @@ export const useProgressSync = (
const configFraction = config!.progress![0] / config!.progress![1];
if (syncedFraction > configFraction) {
view?.goToFraction(syncedFraction);
setToastMessage?.('Progress synced');
setToastMessage?.(_('Reading progress synced'));
}
}
}
+9
View File
@@ -1,9 +1,18 @@
import { check } from '@tauri-apps/plugin-updater';
import { ask } from '@tauri-apps/plugin-dialog';
import { relaunch } from '@tauri-apps/plugin-process';
import { CHECK_UPDATE_INTERVAL_SEC } from '@/services/constants';
const LAST_CHECK_KEY = 'lastAppUpdateCheck';
export const checkForAppUpdates = async () => {
const lastCheck = localStorage.getItem(LAST_CHECK_KEY);
const now = Date.now();
if (lastCheck && now - parseInt(lastCheck, 10) < CHECK_UPDATE_INTERVAL_SEC * 1000) return;
localStorage.setItem(LAST_CHECK_KEY, now.toString());
const update = await check();
console.log('update found', update);
if (update) {
const yes = await ask(
`
@@ -89,3 +89,4 @@ export const READEST_WEB_BASE_URL = 'https://web.readest.com';
export const SYNC_PROGRESS_INTERVAL_SEC = 60;
export const SYNC_NOTES_INTERVAL_SEC = 60;
export const CHECK_UPDATE_INTERVAL_SEC = 24 * 60 * 60;
+2 -2
View File
@@ -68,8 +68,8 @@ export const useBookDataStore = create<BookDataState>((set, get) => ({
library.unshift(book);
setLibrary(library);
config.updatedAt = Date.now();
appService.saveBookConfig(book, config, settings);
appService.saveLibraryBooks(library);
await appService.saveBookConfig(book, config, settings);
await appService.saveLibraryBooks(library);
},
updateBooknotes: (key: string, booknotes: BookNote[]) => {
let updatedConfig: BookConfig | undefined;
+12
View File
@@ -12,3 +12,15 @@ export const tauriHandleClose = async () => {
const { getCurrentWindow } = await import('@tauri-apps/api/window');
getCurrentWindow().close();
};
export const tauriHandleOnCloseWindow = async (callback: () => void) => {
const { TauriEvent } = await import('@tauri-apps/api/event');
const { getCurrentWindow } = await import('@tauri-apps/api/window');
const { exit } = await import('@tauri-apps/plugin-process');
const currentWindow = getCurrentWindow();
return currentWindow.listen(TauriEvent.WINDOW_CLOSE_REQUESTED, async () => {
await callback();
console.log('exit app');
await exit(0);
});
};