mirror of
https://github.com/infinilabs/coco-app.git
synced 2025-12-16 11:37:47 +01:00
fix: settings window rendering/loading issue (#889)
This commit fixes(I guess?) the issue that the Settings window may not be rendered or loaded, you will see that the whole window is gray in that case. Background, aka, why this issue exists ============================================================= In commit [1], we wrapped all the backend setup routines in a tauri command, so that frontend code can call it before invoking any other backend interfaces to guarantee that these interfaces won't be called until the data/state they rely on is ready. The implementation in [1] had an issue that it didn't work with window reloading. To fix this issue, we made another commit [2]. Commit [2] fixed the refresh issue, but it also caused the settings window issue that this commit tries to fix. The backend setup tauri command needs a state to track whether the setup has completed. In the previous implementation, this was done in the frontend. In this commit, it is moved to the backend. Why didn't you guys move that state to backend in previous commits, e.g., commit [2]? ============================================================= We tried, but failed. In the previous tries, the backend would send an event to the frontend, but the frontend couldn't receive it, for reasons we still don’t understand. And this weird issue still exists, we just happen to find a way to work around it. [1]:f93c527561[2]:993da9a8adCo-authored-by: ayang <473033518@qq.com>
This commit is contained in:
@@ -34,6 +34,7 @@ Information about release notes of Coco App is provided here.
|
||||
- fix: set up hotkey on main thread or Windows will complain #879
|
||||
- fix: resolve deeplink login issue #881
|
||||
- fix: use kill_on_drop() to avoid zombie proc in error case #887
|
||||
- fix: settings window rendering/loading issue 889
|
||||
|
||||
### ✈️ Improvements
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@ use crate::GLOBAL_TAURI_APP_HANDLE;
|
||||
use crate::autostart;
|
||||
use crate::common::register::SearchSourceRegistry;
|
||||
use crate::util::app_lang::update_app_lang;
|
||||
use std::sync::OnceLock;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::Ordering;
|
||||
use tauri::{AppHandle, Manager, WebviewWindow};
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
@@ -41,9 +42,11 @@ pub fn default(
|
||||
);
|
||||
}
|
||||
|
||||
/// Use this variable to track if tauri command `backend_setup()` gets called
|
||||
/// by the frontend.
|
||||
pub(super) static BACKEND_SETUP_FUNC_INVOKED: OnceLock<()> = OnceLock::new();
|
||||
/// Indicates if the setup job is completed.
|
||||
static BACKEND_SETUP_COMPLETED: AtomicBool = AtomicBool::new(false);
|
||||
/// The function `backup_setup()` may be called concurrently, use this lock to
|
||||
/// synchronize that only 1 async task can do the actual setup job.
|
||||
static MUTEX_LOCK: tokio::sync::Mutex<()> = tokio::sync::Mutex::const_new(());
|
||||
|
||||
/// This function includes the setup job that has to be coordinated with the
|
||||
/// frontend, or the App will panic due to races[1]. The way we coordinate is to
|
||||
@@ -60,9 +63,17 @@ pub(super) static BACKEND_SETUP_FUNC_INVOKED: OnceLock<()> = OnceLock::new();
|
||||
/// called. If the frontend code invokes `list_extensions()` before `init_extension()`
|
||||
/// gets executed, we get a panic.
|
||||
#[tauri::command]
|
||||
#[function_name::named]
|
||||
pub(crate) async fn backend_setup(tauri_app_handle: AppHandle, app_lang: String) {
|
||||
if BACKEND_SETUP_FUNC_INVOKED.get().is_some() {
|
||||
if BACKEND_SETUP_COMPLETED.load(Ordering::Relaxed) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Race to let one async task do the setup job
|
||||
let _guard = MUTEX_LOCK.lock().await;
|
||||
|
||||
// Re-check in case the current async task is not the first one that acquires
|
||||
// the lock
|
||||
if BACKEND_SETUP_COMPLETED.load(Ordering::Relaxed) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -102,7 +113,5 @@ pub(crate) async fn backend_setup(tauri_app_handle: AppHandle, app_lang: String)
|
||||
update_app_lang(app_lang).await;
|
||||
|
||||
// Invoked, now update the state
|
||||
BACKEND_SETUP_FUNC_INVOKED
|
||||
.set(())
|
||||
.unwrap_or_else(|_| panic!("tauri command {}() gets called twice!", function_name!()));
|
||||
BACKEND_SETUP_COMPLETED.store(true, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
@@ -1,46 +1,22 @@
|
||||
import { useMount, useSessionStorageState } from "ahooks";
|
||||
import { useEffect } from "react";
|
||||
import { useMount } from "ahooks";
|
||||
import { useState } from "react";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
|
||||
import LayoutOutlet from "./outlet";
|
||||
import { useAppStore } from "@/stores/appStore";
|
||||
import platformAdapter from "@/utils/platformAdapter";
|
||||
import { CHAT_WINDOW_LABEL, MAIN_WINDOW_LABEL } from "@/constants";
|
||||
|
||||
const Layout = () => {
|
||||
const { language } = useAppStore();
|
||||
const [ready, setReady] = useSessionStorageState("rust_ready", {
|
||||
defaultValue: false,
|
||||
});
|
||||
const [ready, setReady] = useState(false);
|
||||
|
||||
useMount(async () => {
|
||||
const label = await platformAdapter.getCurrentWindowLabel();
|
||||
|
||||
if (label === CHAT_WINDOW_LABEL) {
|
||||
setReady(true);
|
||||
}
|
||||
|
||||
if (ready || label !== MAIN_WINDOW_LABEL) return;
|
||||
|
||||
await invoke("backend_setup", {
|
||||
appLang: language,
|
||||
});
|
||||
|
||||
setReady(true);
|
||||
|
||||
platformAdapter.emitEvent("rust_ready");
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const unlisten = platformAdapter.listenEvent("rust_ready", () => {
|
||||
setReady(true);
|
||||
});
|
||||
|
||||
return () => {
|
||||
unlisten.then((fn) => fn());
|
||||
};
|
||||
}, []);
|
||||
|
||||
return ready && <LayoutOutlet />;
|
||||
};
|
||||
|
||||
|
||||
@@ -47,7 +47,6 @@ export interface EventPayloads {
|
||||
"check-update": any;
|
||||
oauth_success: any;
|
||||
extension_install_success: any;
|
||||
rust_ready: boolean;
|
||||
}
|
||||
|
||||
// Window operation interface
|
||||
|
||||
Reference in New Issue
Block a user