diff --git a/package-lock.json b/package-lock.json index fb8699e0eb..73dd92f404 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8428,6 +8428,15 @@ "integrity": "sha512-qKD5Pbq+QMk4nea4lMuncUMhpEiQwaJyCW7MrvissnRcBDENhVfDmAqQYRQ3X525oTzhar9Zh1cK0L2d1UKYcw==", "dev": true }, + "electron-window-state": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/electron-window-state/-/electron-window-state-5.0.3.tgz", + "integrity": "sha512-1mNTwCfkolXl3kMf50yW3vE2lZj0y92P/HYWFBrb+v2S/pCka5mdwN3cagKm458A7NjndSwijynXgcLWRodsVg==", + "requires": { + "jsonfile": "^4.0.0", + "mkdirp": "^0.5.1" + } + }, "elegant-spinner": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", @@ -10081,8 +10090,7 @@ "graceful-fs": { "version": "4.2.6", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" }, "graceful-readlink": { "version": "1.0.1", @@ -11740,7 +11748,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, "requires": { "graceful-fs": "^4.1.6" } @@ -12847,8 +12854,7 @@ "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, "minipass": { "version": "3.1.3", @@ -12955,7 +12961,6 @@ "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, "requires": { "minimist": "^1.2.5" } diff --git a/package.json b/package.json index d2188e82f6..cac1556160 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "dayjs": "1.10.7", "electron-log": "4.4.1", "electron-store": "8.0.0", + "electron-window-state": "5.0.3", "encoding-japanese": "1.0.30", "immer": "9.0.2", "lodash.debounce": "4.0.8", diff --git a/src/background.ts b/src/background.ts index 1a41da3b2d..583fbe0d17 100644 --- a/src/background.ts +++ b/src/background.ts @@ -35,10 +35,12 @@ import { ToolbarSetting, ActivePointScrollMode, EngineInfo, + SplitterPosition, } from "./type/preload"; import log from "electron-log"; import dayjs from "dayjs"; +import windowStateKeeper from "electron-window-state"; // silly以上のログをコンソールに出力 log.transports.console.format = "[{h}:{i}:{s}.{ms}] [{level}] {text}"; @@ -206,6 +208,7 @@ const store = new Store<{ experimentalSetting: ExperimentalSetting; acceptRetrieveTelemetry: AcceptRetrieveTelemetryStatus; acceptTerms: AcceptTermsStatus; + splitterPosition: SplitterPosition; }>({ schema: { useGpu: { @@ -357,6 +360,15 @@ const store = new Store<{ enum: ["Unconfirmed", "Accepted", "Rejected"], default: "Unconfirmed", }, + splitterPosition: { + type: "object", + properties: { + portraitPaneWidth: { type: "number" }, + audioInfoPaneWidth: { type: "number" }, + audioDetailPaneHeight: { type: "number" }, + }, + default: {}, + }, }, migrations: {}, }); @@ -737,9 +749,16 @@ let willQuit = false; let filePathOnMac: string | null = null; // create window async function createWindow() { + const mainWindowState = windowStateKeeper({ + defaultWidth: 800, + defaultHeight: 600, + }); + win = new BrowserWindow({ - width: 800, - height: 600, + x: mainWindowState.x, + y: mainWindowState.y, + width: mainWindowState.width, + height: mainWindowState.height, frame: false, titleBarStyle: "hidden", trafficLightPosition: { x: 6, y: 4 }, @@ -811,6 +830,8 @@ async function createWindow() { } } }); + + mainWindowState.manage(win); } const menuTemplateForMac: Electron.MenuItemConstructorOptions[] = [ @@ -1162,6 +1183,14 @@ ipcMainHandle("SET_EXPERIMENTAL_SETTING", (_, experimentalSetting) => { store.set("experimentalSetting", experimentalSetting); }); +ipcMainHandle("GET_SPLITTER_POSITION", () => { + return store.get("splitterPosition"); +}); + +ipcMainHandle("SET_SPLITTER_POSITION", (_, splitterPosition) => { + store.set("splitterPosition", splitterPosition); +}); + // app callback app.on("web-contents-created", (e, contents) => { // リンククリック時はブラウザを開く diff --git a/src/electron/preload.ts b/src/electron/preload.ts index f0c9afb6ab..20138beb7d 100644 --- a/src/electron/preload.ts +++ b/src/electron/preload.ts @@ -263,6 +263,14 @@ const api: Sandbox = { return await ipcRendererInvoke("SET_EXPERIMENTAL_SETTING", setting); }, + getSplitterPosition: async () => { + return await ipcRendererInvoke("GET_SPLITTER_POSITION"); + }, + + setSplitterPosition: async (splitterPosition) => { + return await ipcRendererInvoke("SET_SPLITTER_POSITION", splitterPosition); + }, + getDefaultHotkeySettings: async () => { return await ipcRendererInvoke("GET_DEFAULT_HOTKEY_SETTINGS"); }, diff --git a/src/store/index.ts b/src/store/index.ts index dd25070060..8cab554663 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -177,6 +177,7 @@ export const indexStore: VoiceVoxStoreOptions< promises.push(dispatch("GET_ACCEPT_RETRIEVE_TELEMETRY")); promises.push(dispatch("GET_ACCEPT_TERMS")); promises.push(dispatch("GET_EXPERIMENTAL_SETTING")); + promises.push(dispatch("GET_SPLITTER_POSITION")); await Promise.all(promises).then(() => { dispatch("ON_VUEX_READY"); diff --git a/src/store/setting.ts b/src/store/setting.ts index 3d2514f70c..94e9c7c2fe 100644 --- a/src/store/setting.ts +++ b/src/store/setting.ts @@ -46,6 +46,11 @@ export const settingStoreState: SettingStoreState = { enablePreset: false, enableInterrogativeUpspeak: false, }, + splitterPosition: { + audioDetailPaneHeight: undefined, + audioInfoPaneWidth: undefined, + portraitPaneWidth: undefined, + }, }; export const settingStore: VoiceVoxStoreOptions< @@ -102,6 +107,9 @@ export const settingStore: VoiceVoxStoreOptions< SET_ACCEPT_TERMS(state, { acceptTerms }) { state.acceptTerms = acceptTerms; }, + SET_SPLITTER_POSITION(state, { splitterPosition }) { + state.splitterPosition = splitterPosition; + }, }, actions: { GET_SAVING_SETTING({ commit }) { @@ -237,6 +245,15 @@ export const settingStore: VoiceVoxStoreOptions< window.electron.setExperimentalSetting(experimentalSetting); commit("SET_EXPERIMENTAL_SETTING", { experimentalSetting }); }, + GET_SPLITTER_POSITION({ dispatch }) { + window.electron.getSplitterPosition().then((splitterPosition) => { + dispatch("SET_SPLITTER_POSITION", { splitterPosition }); + }); + }, + SET_SPLITTER_POSITION({ commit }, { splitterPosition }) { + window.electron.setSplitterPosition(splitterPosition); + commit("SET_SPLITTER_POSITION", { splitterPosition }); + }, }, }; diff --git a/src/store/type.ts b/src/store/type.ts index 368162cfdb..432a67c8a8 100644 --- a/src/store/type.ts +++ b/src/store/type.ts @@ -25,6 +25,7 @@ import { Preset, ActivePointScrollMode, EngineInfo, + SplitterPosition, } from "@/type/preload"; import { IEngineConnectorFactory } from "@/infrastructures/EngineConnector"; import { QVueGlobals } from "quasar"; @@ -767,6 +768,7 @@ export type SettingStoreState = { themeSetting: ThemeSetting; acceptRetrieveTelemetry: AcceptRetrieveTelemetryStatus; experimentalSetting: ExperimentalSetting; + splitterPosition: SplitterPosition; }; type SettingStoreTypes = { @@ -835,6 +837,15 @@ type SettingStoreTypes = { mutation: { experimentalSetting: ExperimentalSetting }; action(payload: { experimentalSetting: ExperimentalSetting }): void; }; + + GET_SPLITTER_POSITION: { + action(): void; + }; + + SET_SPLITTER_POSITION: { + mutation: { splitterPosition: SplitterPosition }; + action(payload: { splitterPosition: SplitterPosition }): void; + }; }; export type SettingGetters = StoreType; diff --git a/src/type/ipc.d.ts b/src/type/ipc.d.ts index 67a2491737..7ea78f89f4 100644 --- a/src/type/ipc.d.ts +++ b/src/type/ipc.d.ts @@ -262,6 +262,16 @@ type IpcIHData = { return: void; }; + GET_SPLITTER_POSITION: { + args: []; + return: import("@/type/preload").SplitterPosition; + }; + + SET_SPLITTER_POSITION: { + args: [splitterPosition: import("@/type/preload").SplitterPosition]; + return: void; + }; + THEME: { args: [obj: { newData?: string }]; return: import("@/type/preload").ThemeSetting | void; diff --git a/src/type/preload.d.ts b/src/type/preload.d.ts index 32a85c93d9..b9c22ec77f 100644 --- a/src/type/preload.d.ts +++ b/src/type/preload.d.ts @@ -82,6 +82,8 @@ export interface Sandbox { setAcceptTerms(acceptTerms: AcceptTermsStatus): Promise; getExperimentalSetting(): Promise; setExperimentalSetting(setting: ExperimentalSetting): Promise; + getSplitterPosition(): Promise; + setSplitterPosition(splitterPosition: SplitterPosition): Promise; getDefaultHotkeySettings(): Promise; getDefaultToolbarSetting(): Promise; theme(newData?: string): Promise; @@ -265,3 +267,9 @@ export type ExperimentalSetting = { enablePreset: boolean; enableInterrogativeUpspeak: boolean; }; + +export type SplitterPosition = { + portraitPaneWidth: number | undefined; + audioInfoPaneWidth: number | undefined; + audioDetailPaneHeight: number | undefined; +}; diff --git a/src/views/Home.vue b/src/views/Home.vue index ae10f12190..c0f137c9a7 100644 --- a/src/views/Home.vue +++ b/src/views/Home.vue @@ -31,7 +31,8 @@ class="full-width" before-class="overflow-hidden" :disable="!shouldShowPanes" - v-model="audioDetailPaneHeight" + :model-value="audioDetailPaneHeight" + @update:model-value="updateAudioDetailPane" >