From 0582091908906adeac79cbadc215f7323aefd2e2 Mon Sep 17 00:00:00 2001 From: Sakamoto Shiina <68018796+ShiinaSakamoto@users.noreply.github.com> Date: Sun, 13 Oct 2024 03:57:23 +0900 Subject: [PATCH] [Update] Add feature Restore Main Window Geometry. Note: the toggle-able setting, to restore or don't, has removed for now. --- src-python/config.py | 10 +- src-tauri/Cargo.toml | 2 +- src-tauri/tauri.conf.json | 2 + src-ui/app/App.jsx | 15 ++- .../setting_box/appearance/Appearance.jsx | 22 ++++- .../setting_box/components/useSettingBox.jsx | 19 ++-- src-ui/logics/common/index.js | 1 + src-ui/logics/common/useWindow.js | 92 +++++++++++++++++++ .../appearance/useRestoreWindowGeometry.js | 28 ++++++ src-ui/logics/configs/index.js | 1 + src-ui/logics/useReceiveRoutes.js | 12 +++ src-ui/store.js | 1 + 12 files changed, 183 insertions(+), 22 deletions(-) create mode 100644 src-ui/logics/common/useWindow.js create mode 100644 src-ui/logics/configs/appearance/useRestoreWindowGeometry.js diff --git a/src-python/config.py b/src-python/config.py index 3537c2f5..0e806e84 100644 --- a/src-python/config.py +++ b/src-python/config.py @@ -445,7 +445,7 @@ class Config: def MAIN_WINDOW_GEOMETRY(self, value): if isinstance(value, dict) and set(value.keys()) == set(self.MAIN_WINDOW_GEOMETRY.keys()): for key, value in value.items(): - if isinstance(value, str): + if isinstance(value, int): self._MAIN_WINDOW_GEOMETRY[key] = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, self.MAIN_WINDOW_GEOMETRY) @@ -1106,10 +1106,10 @@ class Config: self._UI_LANGUAGE = "en" self._RESTORE_MAIN_WINDOW_GEOMETRY = True self._MAIN_WINDOW_GEOMETRY = { - "x_pos": "0", - "y_pos": "0", - "width": "870", - "height": "654", + "x_pos": 0, + "y_pos": 0, + "width": 870, + "height": 654, } self._AUTO_MIC_SELECT = True self._SELECTED_MIC_HOST = device_manager.getDefaultMicDevice()["host"]["name"] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index b4240cf3..46da9fa7 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -11,7 +11,7 @@ edition = "2021" tauri-build = { version = "1", features = [] } [dependencies] -tauri = { version = "1", features = [ "window-unmaximize", "window-close", "window-maximize", "window-minimize", "window-unminimize", "window-start-dragging", "window-set-decorations", "window-set-always-on-top", "shell-sidecar", "shell-open", "devtools"] } +tauri = { version = "1", features = [ "window-set-size", "window-set-position", "window-unmaximize", "window-close", "window-maximize", "window-minimize", "window-unminimize", "window-start-dragging", "window-set-decorations", "window-set-always-on-top", "shell-sidecar", "shell-open", "devtools"] } serde = { version = "1", features = ["derive"] } serde_json = "1" font-kit = "0.14.2" diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 6dd58586..4d4d58ea 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -17,6 +17,8 @@ "setAlwaysOnTop": true, "setDecorations": true, "close": true, + "setPosition": true, + "setSize": true, "maximize": true, "minimize": true, "unmaximize": true, diff --git a/src-ui/app/App.jsx b/src-ui/app/App.jsx index 38bb14b2..461e152d 100644 --- a/src-ui/app/App.jsx +++ b/src-ui/app/App.jsx @@ -6,6 +6,7 @@ import { ConfigPage } from "./config_page/ConfigPage"; import styles from "./App.module.scss"; export const App = () => { + const { WindowGeometryController } = useWindow(); return (
@@ -14,6 +15,7 @@ export const App = () => { +
@@ -24,6 +26,11 @@ export const App = () => { ); }; +import { + useWindow, + useVolume, + useIsOpenedConfigPage, +} from "@logics_common"; import { useSoftwareVersion, @@ -59,6 +66,8 @@ const StartPythonFacadeComponent = () => { const hasRunRef = useRef(false); const { asyncFetchFonts } = useAsyncFetchFonts(); + const { fetchAndUpdateWindowGeometry } = useWindow(); + const { getMicHostList } = useMicHostList(); const { getMicDeviceList } = useMicDeviceList(); const { getSpeakerDeviceList } = useSpeakerDeviceList(); @@ -97,6 +106,8 @@ const StartPythonFacadeComponent = () => { asyncStartPython().then(() => { startFeedingToWatchDog(); + fetchAndUpdateWindowGeometry(); + getUiLanguage(); getUiScaling(); getMessageLogUiScaling(); @@ -156,10 +167,6 @@ const UiLanguageController = () => { }; import { useStore_MainFunctionsStateMemory } from "@store"; -import { - useVolume, - useIsOpenedConfigPage, -} from "@logics_common"; const ConfigPageCloseTrigger = () => { const { currentIsOpenedConfigPage } = useIsOpenedConfigPage(); diff --git a/src-ui/app/config_page/setting_section/setting_box/appearance/Appearance.jsx b/src-ui/app/config_page/setting_section/setting_box/appearance/Appearance.jsx index fb10feee..e5993713 100644 --- a/src-ui/app/config_page/setting_section/setting_box/appearance/Appearance.jsx +++ b/src-ui/app/config_page/setting_section/setting_box/appearance/Appearance.jsx @@ -9,12 +9,13 @@ import { useMessageLogUiScaling, useSelectedFontFamily, useTransparency, + // useRestoreWindowGeometry, } from "@logics_configs"; export const Appearance = () => { const { t } = useTranslation(); const { - DropdownMenuContainer, + // DropdownMenuContainer, // SliderContainer, // CheckboxContainer, // SwitchboxContainer, @@ -33,6 +34,7 @@ export const Appearance = () => { + {/* */} @@ -253,4 +255,20 @@ const TransparencyContainer = () => { track={false} /> ); -}; \ No newline at end of file +}; + +// import { CheckboxContainer } from "../components/useSettingBox"; + +// const RestoreWindowGeometryContainer = () => { +// const { t } = useTranslation(); +// const { currentRestoreWindowGeometry, toggleRestoreWindowGeometry } = useRestoreWindowGeometry(); + +// return ( +// +// ); +// }; \ No newline at end of file diff --git a/src-ui/app/config_page/setting_section/setting_box/components/useSettingBox.jsx b/src-ui/app/config_page/setting_section/setting_box/components/useSettingBox.jsx index d30197b2..58a874fe 100644 --- a/src-ui/app/config_page/setting_section/setting_box/components/useSettingBox.jsx +++ b/src-ui/app/config_page/setting_section/setting_box/components/useSettingBox.jsx @@ -45,17 +45,16 @@ export const SliderContainer = (props) => { ); }; +export const CheckboxContainer = (props) => { + return ( +
+ + +
+ ); +}; + export const useSettingBox = () => { - - const CheckboxContainer = (props) => { - return ( -
- - -
- ); - }; - const SwitchboxContainer = (props) => { return (
diff --git a/src-ui/logics/common/index.js b/src-ui/logics/common/index.js index e8f3b975..7ba865de 100644 --- a/src-ui/logics/common/index.js +++ b/src-ui/logics/common/index.js @@ -1,3 +1,4 @@ +export { useWindow } from "./useWindow"; export { useIsOpenedConfigPage } from "./useIsOpenedConfigPage"; export { useMessage } from "./useMessage"; export { useVolume } from "./useVolume"; \ No newline at end of file diff --git a/src-ui/logics/common/useWindow.js b/src-ui/logics/common/useWindow.js new file mode 100644 index 00000000..760e866b --- /dev/null +++ b/src-ui/logics/common/useWindow.js @@ -0,0 +1,92 @@ +import { useStdoutToPython } from "@logics/useStdoutToPython"; +import { useEffect } from "react"; +import { appWindow, currentMonitor, LogicalPosition, LogicalSize } from "@tauri-apps/api/window"; + +export const useWindow = () => { + const { asyncStdoutToPython } = useStdoutToPython(); + const asyncGetWindowGeometry = async () => { + try { + const position = await appWindow.outerPosition(); + const { x, y } = position; + + const size = await appWindow.outerSize(); + const { width, height } = size; + + return { + x_pos: x, + y_pos: y, + width: width, + height: height + }; + } catch (err) { + console.error("Error getting window position and size:", err); + } + }; + + const asyncSaveWindowGeometry = async () => { + const data = await asyncGetWindowGeometry(); + asyncStdoutToPython("/set/data/main_window_geometry", data); + }; + + const restoreWindowGeometry = async (data) => { + try { + const monitor = await currentMonitor(); + + if (monitor) { + const { width: monitorWidth, height: monitorHeight } = monitor.size; + + let width = Math.min(parseInt(data.width), monitorWidth); + let height = Math.min(parseInt(data.height), monitorHeight); + + const x = parseInt(data.x_pos); + const y = parseInt(data.y_pos); + + await appWindow.setPosition(new LogicalPosition(x, y)); + await appWindow.setSize(new LogicalSize(width, height)); + } else { + console.error("Monitor information could not be retrieved."); + } + } catch (err) { + console.error("Error setting window position and size:", err); + } + }; + + const fetchAndUpdateWindowGeometry = () => { + asyncStdoutToPython("/get/data/main_window_geometry"); + }; + + const WindowGeometryController = () => { + useEffect(() => { + let resizeTimeout; + const unlistenResize = appWindow.onResized(() => { + clearTimeout(resizeTimeout); + resizeTimeout = setTimeout(asyncSaveWindowGeometry, 200); + }); + + return () => { + unlistenResize.then((dispose) => dispose()); + }; + }, []); + + useEffect(() => { + let moveTimeout; + const unlistenMove = appWindow.onMoved(() => { + clearTimeout(moveTimeout); + moveTimeout = setTimeout(asyncSaveWindowGeometry, 200); + }); + + return () => { + unlistenMove.then((dispose) => dispose()); + }; + }, []); + + return null; + }; + + return { + WindowGeometryController, + asyncSaveWindowGeometry, + fetchAndUpdateWindowGeometry, + restoreWindowGeometry, + }; +}; diff --git a/src-ui/logics/configs/appearance/useRestoreWindowGeometry.js b/src-ui/logics/configs/appearance/useRestoreWindowGeometry.js new file mode 100644 index 00000000..2cc618be --- /dev/null +++ b/src-ui/logics/configs/appearance/useRestoreWindowGeometry.js @@ -0,0 +1,28 @@ +// import { useStore_RestoreWindowGeometry } from "@store"; +// import { useStdoutToPython } from "@logics/useStdoutToPython"; + +// export const useRestoreWindowGeometry = () => { +// const { asyncStdoutToPython } = useStdoutToPython(); +// const { currentRestoreWindowGeometry, updateRestoreWindowGeometry, pendingRestoreWindowGeometry } = useStore_RestoreWindowGeometry(); + +// const getRestoreWindowGeometry = () => { +// pendingRestoreWindowGeometry(); +// asyncStdoutToPython("/get/data/restore_main_window_geometry"); +// }; + +// const toggleRestoreWindowGeometry = () => { +// pendingRestoreWindowGeometry(); +// if (currentRestoreWindowGeometry.data) { +// asyncStdoutToPython("/set/disable/restore_main_window_geometry"); +// } else { +// asyncStdoutToPython("/set/enable/restore_main_window_geometry"); +// } +// }; + +// return { +// currentRestoreWindowGeometry, +// getRestoreWindowGeometry, +// toggleRestoreWindowGeometry, +// updateRestoreWindowGeometry, +// }; +// }; \ No newline at end of file diff --git a/src-ui/logics/configs/index.js b/src-ui/logics/configs/index.js index 53edfb1a..33c47d43 100644 --- a/src-ui/logics/configs/index.js +++ b/src-ui/logics/configs/index.js @@ -10,6 +10,7 @@ export { useSpeakerDeviceList } from "./device/useSpeakerDeviceList"; export { useSpeakerThreshold } from "./device/useSpeakerThreshold"; export { useMessageLogUiScaling } from "./appearance/useMessageLogUiScaling"; +// export { useRestoreWindowGeometry } from "./appearance/useRestoreWindowGeometry"; export { useSelectedFontFamily } from "./appearance/useSelectedFontFamily"; export { useSendMessageButtonType } from "./appearance/useSendMessageButtonType"; export { useTransparency } from "./appearance/useTransparency"; diff --git a/src-ui/logics/useReceiveRoutes.js b/src-ui/logics/useReceiveRoutes.js index da3ae189..a76e1447 100644 --- a/src-ui/logics/useReceiveRoutes.js +++ b/src-ui/logics/useReceiveRoutes.js @@ -2,6 +2,7 @@ import { translator_status } from "@data"; import { arrayToObject } from "@utils/arrayToObject"; import { + useWindow, useMessage, useVolume, } from "@logics_common"; @@ -33,9 +34,11 @@ import { useUiScaling, useMessageLogUiScaling, useTransparency, + // useRestoreWindowGeometry, } from "@logics_configs"; export const useReceiveRoutes = () => { + const { restoreWindowGeometry } = useWindow(); const { updateIsMainPageCompactMode } = useIsMainPageCompactMode(); const { updateTranslationStatus, @@ -82,10 +85,15 @@ export const useReceiveRoutes = () => { const { updateMessageInputBoxRatio } = useMessageInputBoxRatio(); const { updateSelectedFontFamily } = useSelectedFontFamily(); const { updateTransparency } = useTransparency(); + // const { updateRestoreWindowGeometry } = useRestoreWindowGeometry(); const routes = { + // Common "/run/feed_watchdog": () => {}, + "/get/data/main_window_geometry": restoreWindowGeometry, + "/set/data/main_window_geometry": () => {}, + // Main Page // Page Controls "/get/data/main_window_sidebar_compact_mode": updateIsMainPageCompactMode, @@ -222,6 +230,10 @@ export const useReceiveRoutes = () => { "/get/data/transparency": updateTransparency, "/set/data/transparency": updateTransparency, + // "/get/data/restore_main_window_geometry": updateRestoreWindowGeometry, + // "/set/enable/restore_main_window_geometry": updateRestoreWindowGeometry, + // "/set/disable/restore_main_window_geometry": updateRestoreWindowGeometry, + // Others Tab "/get/data/auto_clear_message_box": updateEnableAutoClearMessageBox, "/set/enable/auto_clear_message_box": updateEnableAutoClearMessageBox, diff --git a/src-ui/store.js b/src-ui/store.js index e104d8af..870cb963 100644 --- a/src-ui/store.js +++ b/src-ui/store.js @@ -99,6 +99,7 @@ const createAtomWithHook = (initialValue, base_name, options) => { // Common +// export const { atomInstance: Atom_RestoreWindowGeometry, useHook: useStore_RestoreWindowGeometry } = createAtomWithHook(true, "RestoreWindowGeometry"); export const { atomInstance: Atom_IsOpenedConfigPage, useHook: useStore_IsOpenedConfigPage } = createAtomWithHook(false, "IsOpenedConfigPage"); export const { atomInstance: Atom_MainFunctionsStateMemory, useHook: useStore_MainFunctionsStateMemory } = createAtomWithHook({ transcription_send: false,