diff --git a/.vscode/launch.template.json b/.vscode/launch.template.json index 969c53d659..483689b55b 100644 --- a/.vscode/launch.template.json +++ b/.vscode/launch.template.json @@ -6,11 +6,14 @@ "configurations": [ { "name": "Attach to Renderer Process", - // NOTE: background.tsで指定しているremote-debugging-port - "port": 9222, + "port": 9222, // NOTE: background.tsで指定しているremote-debugging-port "request": "attach", "type": "chrome", - "webRoot": "${workspaceFolder}", + "webRoot": "${workspaceFolder}/src", + "resolveSourceMapLocations": [ + "${workspaceFolder}/**", + "!**/node_modules/**" + ], "timeout": 20000, // 20 * 1000 ms程度あればビルド時間は間に合うはず }, { @@ -26,6 +29,23 @@ ], "type": "node" }, + { + // 直接Electronのみを起動し、バックグラウンドで"electron:serve"を実行する + // NOTE: ホットリロードできない代わりに、デバッグ起動が軽い + "name": "Launch Electron Main Process without hot reload", + "request": "launch", + "type": "node", + "runtimeExecutable": "npx", + "args": [ + "electron", + ".", + "--no-sandbox" + ], + "preLaunchTask": "Electron Serve without Launch Electron", + "skipFiles": [ + "/**" + ] + }, { "name": "Attach by Process ID", // .bin viteを指定するとElectronのMain Processのデバッグが可能 @@ -35,13 +55,25 @@ "/**" ], "type": "node" - }, + } ], "compounds": [ { "name": "Launch Electron Main/Renderer", - "configurations": ["Attach to Renderer Process", "Launch Electron Main Process via NPM"], + "configurations": [ + "Attach to Renderer Process", + "Launch Electron Main Process via NPM" + ], + "stopAll": true + }, + { + // ホットリロードできない代わりにデバッグ起動が軽いモード + "name": "Launch Electron Main/Renderer without hot reload", + "configurations": [ + "Attach to Renderer Process", + "Launch Electron Main Process without hot reload" + ], "stopAll": true } ] -} \ No newline at end of file +} diff --git a/.vscode/tasks.template.json b/.vscode/tasks.template.json new file mode 100644 index 0000000000..f79d5158ce --- /dev/null +++ b/.vscode/tasks.template.json @@ -0,0 +1,28 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Electron Serve without Launch Electron", + // Electronを起動せずにバックグラウンドで"electron:serve"を実行する + // NOTE: デバッグ起動を軽くできる + "type": "npm", + "script": "electron:serve", + "options": { + "env": { + "SKIP_LAUNCH_ELECTRON": "1" + } + }, + "isBackground": true, + "problemMatcher": { + "pattern": { + "regexp": "" + }, + "background": { + "activeOnStart": true, + "beginsPattern": "building for development\\.\\.\\.", + "endsPattern": "main process build is complete\\." + } + } + } + ] +} diff --git a/README.md b/README.md index 732103b907..98173cbd3a 100644 --- a/README.md +++ b/README.md @@ -319,7 +319,9 @@ npx openapi-generator-cli version-manager list npm scripts の `serve` や `electron:serve` などの開発ビルド下では、ビルドに使用している vite で sourcemap を出力するため、ソースコードと出力されたコードの対応付けが行われます。 -`.vscode/launch.template.json` をコピーして `.vscode/launch.json` を作成することで、開発ビルドを VS Code から実行し、デバッグを可能にするタスクが有効になります。 +`.vscode/launch.template.json` をコピーして `.vscode/launch.json` を、 +`.vscode/tasks.template.json` をコピーして `.vscode/tasks.json` を作成することで、 +開発ビルドを VS Code から実行し、デバッグを可能にするタスクが有効になります。 ## ライセンス diff --git a/src/backend/electron/electronConfig.ts b/src/backend/electron/electronConfig.ts index 0fc90bf23b..59dbfba4a5 100644 --- a/src/backend/electron/electronConfig.ts +++ b/src/backend/electron/electronConfig.ts @@ -1,7 +1,7 @@ import { join } from "path"; import fs from "fs"; import { app } from "electron"; -import { moveFile } from "move-file"; +import { writeFileSafely } from "./fileHelper"; import { BaseConfigManager, Metadata } from "@/backend/common/ConfigManager"; import { ConfigType } from "@/type/preload"; @@ -23,16 +23,7 @@ export class ElectronConfigManager extends BaseConfigManager { } protected async save(config: ConfigType & Metadata) { - // ファイル書き込みに失敗したときに設定が消えないように、tempファイル書き込み後上書き移動する - const temp_path = `${this.configPath}.tmp`; - await fs.promises.writeFile( - temp_path, - JSON.stringify(config, undefined, 2), - ); - - await moveFile(temp_path, this.configPath, { - overwrite: true, - }); + writeFileSafely(this.configPath, JSON.stringify(config, undefined, 2)); } private get configPath(): string { diff --git a/src/backend/electron/fileHelper.ts b/src/backend/electron/fileHelper.ts new file mode 100644 index 0000000000..9d80ac0c44 --- /dev/null +++ b/src/backend/electron/fileHelper.ts @@ -0,0 +1,18 @@ +import fs from "fs"; +import { moveFileSync } from "move-file"; + +/** + * 書き込みに失敗したときにファイルが消えないように、 + * tmpファイル書き込み後、保存先ファイルに上書きする + */ +export function writeFileSafely( + path: string, + data: string | NodeJS.ArrayBufferView, +) { + const tmpPath = `${path}.tmp`; + fs.writeFileSync(tmpPath, data); + + moveFileSync(tmpPath, path, { + overwrite: true, + }); +} diff --git a/src/backend/electron/ipc.ts b/src/backend/electron/ipc.ts index 588af9de98..02df0c6032 100644 --- a/src/backend/electron/ipc.ts +++ b/src/backend/electron/ipc.ts @@ -68,8 +68,8 @@ export const ipcMainSendProxy = new Proxy( const validateIpcSender = (event: IpcMainInvokeEvent) => { let isValid: boolean; const senderUrl = new URL(event.senderFrame.url); - if (process.env.VITE_DEV_SERVER_URL != undefined) { - const devServerUrl = new URL(process.env.VITE_DEV_SERVER_URL); + if (import.meta.env.VITE_DEV_SERVER_URL != undefined) { + const devServerUrl = new URL(import.meta.env.VITE_DEV_SERVER_URL); isValid = senderUrl.origin === devServerUrl.origin; } else { isValid = senderUrl.protocol === "app:"; diff --git a/src/backend/electron/main.ts b/src/backend/electron/main.ts index 42a908ecca..6b636c0883 100644 --- a/src/backend/electron/main.ts +++ b/src/backend/electron/main.ts @@ -28,6 +28,7 @@ import { RuntimeInfoManager } from "./manager/RuntimeInfoManager"; import { registerIpcMainHandle, ipcMainSendProxy, IpcMainHandle } from "./ipc"; import { getConfigManager } from "./electronConfig"; import { EngineAndVvppController } from "./engineAndVvppController"; +import { writeFileSafely } from "./fileHelper"; import { failure, success } from "@/type/result"; import { AssetTextFileNames } from "@/type/staticResources"; import { @@ -145,7 +146,7 @@ protocol.registerSchemesAsPrivileged([ { scheme: "app", privileges: { secure: true, standard: true, stream: true } }, ]); -const firstUrl = process.env.VITE_DEV_SERVER_URL ?? "app://./index.html"; +const firstUrl = import.meta.env.VITE_DEV_SERVER_URL ?? "app://./index.html"; // engine const vvppEngineDir = path.join(app.getPath("userData"), "vvpp-engines"); @@ -280,7 +281,7 @@ async function createWindow() { } // ソフトウェア起動時はプロトコルを app にする - if (process.env.VITE_DEV_SERVER_URL == undefined) { + if (import.meta.env.VITE_DEV_SERVER_URL == undefined) { protocol.handle("app", (request) => { // 読み取り先のファイルがインストールディレクトリ内であることを確認する // ref: https://www.electronjs.org/ja/docs/latest/api/protocol#protocolhandlescheme-handler @@ -744,7 +745,7 @@ registerIpcMainHandle({ WRITE_FILE: (_, { filePath, buffer }) => { try { - fs.writeFileSync( + writeFileSafely( filePath, new DataView(buffer instanceof Uint8Array ? buffer.buffer : buffer), ); diff --git a/src/backend/electron/manager/RuntimeInfoManager.ts b/src/backend/electron/manager/RuntimeInfoManager.ts index e3ec4340ca..04683ea375 100644 --- a/src/backend/electron/manager/RuntimeInfoManager.ts +++ b/src/backend/electron/manager/RuntimeInfoManager.ts @@ -3,11 +3,11 @@ * ランタイム情報には起動しているエンジンのURLなどが含まれる。 */ -import fs from "fs"; import AsyncLock from "async-lock"; import log from "electron-log/main"; import type { AltPortInfos } from "@/store/type"; import { EngineId, EngineInfo } from "@/type/preload"; +import { writeFileSafely } from "@/backend/electron/fileHelper"; /** * ランタイム情報書き出しに必要なEngineInfo @@ -99,7 +99,7 @@ export class RuntimeInfoManager { // ファイル書き出し try { - await fs.promises.writeFile( + writeFileSafely( this.runtimeInfoPath, JSON.stringify(runtimeInfoFormatFor3rdParty), // FIXME: zod化する ); diff --git a/src/components/Dialog/AcceptDialog/AcceptRetrieveTelemetryDialog.vue b/src/components/Dialog/AcceptDialog/AcceptRetrieveTelemetryDialog.vue index 53d572be33..d681837fc1 100644 --- a/src/components/Dialog/AcceptDialog/AcceptRetrieveTelemetryDialog.vue +++ b/src/components/Dialog/AcceptDialog/AcceptRetrieveTelemetryDialog.vue @@ -39,7 +39,7 @@ const modelValueComputed = computed({ }); const handler = (acceptRetrieveTelemetry: boolean) => { - void store.dispatch("SET_ACCEPT_RETRIEVE_TELEMETRY", { + void store.actions.SET_ACCEPT_RETRIEVE_TELEMETRY({ acceptRetrieveTelemetry: acceptRetrieveTelemetry ? "Accepted" : "Refused", }); @@ -48,6 +48,6 @@ const handler = (acceptRetrieveTelemetry: boolean) => { const privacyPolicy = ref(""); onMounted(async () => { - privacyPolicy.value = await store.dispatch("GET_PRIVACY_POLICY_TEXT"); + privacyPolicy.value = await store.actions.GET_PRIVACY_POLICY_TEXT(); }); diff --git a/src/components/Dialog/AcceptDialog/AcceptTermsDialog.vue b/src/components/Dialog/AcceptDialog/AcceptTermsDialog.vue index 64945bdce1..f754830555 100644 --- a/src/components/Dialog/AcceptDialog/AcceptTermsDialog.vue +++ b/src/components/Dialog/AcceptDialog/AcceptTermsDialog.vue @@ -35,11 +35,11 @@ const modelValueComputed = computed({ }); const handler = (acceptTerms: boolean) => { - void store.dispatch("SET_ACCEPT_TERMS", { + void store.actions.SET_ACCEPT_TERMS({ acceptTerms: acceptTerms ? "Accepted" : "Rejected", }); if (acceptTerms) { - void store.dispatch("CHECK_EDITED_AND_NOT_SAVE", { + void store.actions.CHECK_EDITED_AND_NOT_SAVE({ closeOrReload: "close", }); } @@ -49,6 +49,6 @@ const handler = (acceptTerms: boolean) => { const terms = ref(""); onMounted(async () => { - terms.value = await store.dispatch("GET_POLICY_TEXT"); + terms.value = await store.actions.GET_POLICY_TEXT(); }); diff --git a/src/components/Dialog/AllDialog.vue b/src/components/Dialog/AllDialog.vue index 340bd467c0..468371c4a2 100644 --- a/src/components/Dialog/AllDialog.vue +++ b/src/components/Dialog/AllDialog.vue @@ -52,20 +52,20 @@ const store = useStore(); // ライセンス表示 const isHelpDialogOpenComputed = computed({ get: () => store.state.isHelpDialogOpen, - set: (val) => store.dispatch("SET_DIALOG_OPEN", { isHelpDialogOpen: val }), + set: (val) => store.actions.SET_DIALOG_OPEN({ isHelpDialogOpen: val }), }); // 設定 const isSettingDialogOpenComputed = computed({ get: () => store.state.isSettingDialogOpen, - set: (val) => store.dispatch("SET_DIALOG_OPEN", { isSettingDialogOpen: val }), + set: (val) => store.actions.SET_DIALOG_OPEN({ isSettingDialogOpen: val }), }); // ショートカットキー設定 const isHotkeySettingDialogOpenComputed = computed({ get: () => store.state.isHotkeySettingDialogOpen, set: (val) => - store.dispatch("SET_DIALOG_OPEN", { + store.actions.SET_DIALOG_OPEN({ isHotkeySettingDialogOpen: val, }), }); @@ -74,7 +74,7 @@ const isHotkeySettingDialogOpenComputed = computed({ const isToolbarSettingDialogOpenComputed = computed({ get: () => store.state.isToolbarSettingDialogOpen, set: (val) => - store.dispatch("SET_DIALOG_OPEN", { + store.actions.SET_DIALOG_OPEN({ isToolbarSettingDialogOpen: val, }), }); @@ -83,7 +83,7 @@ const isToolbarSettingDialogOpenComputed = computed({ const isAcceptTermsDialogOpenComputed = computed({ get: () => store.state.isAcceptTermsDialogOpen, set: (val) => - store.dispatch("SET_DIALOG_OPEN", { + store.actions.SET_DIALOG_OPEN({ isAcceptTermsDialogOpen: val, }), }); @@ -97,7 +97,7 @@ const isCharacterOrderDialogOpenComputed = computed({ !store.state.isAcceptTermsDialogOpen && store.state.isCharacterOrderDialogOpen, set: (val) => - store.dispatch("SET_DIALOG_OPEN", { + store.actions.SET_DIALOG_OPEN({ isCharacterOrderDialogOpen: val, }), }); @@ -115,7 +115,7 @@ const isDefaultStyleSelectDialogOpenComputed = computed({ !store.state.isCharacterOrderDialogOpen && store.state.isDefaultStyleSelectDialogOpen, set: (val) => - store.dispatch("SET_DIALOG_OPEN", { + store.actions.SET_DIALOG_OPEN({ isDefaultStyleSelectDialogOpen: val, }), }); @@ -124,7 +124,7 @@ const isDefaultStyleSelectDialogOpenComputed = computed({ const isEngineManageDialogOpenComputed = computed({ get: () => store.state.isEngineManageDialogOpen, set: (val) => - store.dispatch("SET_DIALOG_OPEN", { + store.actions.SET_DIALOG_OPEN({ isEngineManageDialogOpen: val, }), }); @@ -133,7 +133,7 @@ const isEngineManageDialogOpenComputed = computed({ const isDictionaryManageDialogOpenComputed = computed({ get: () => store.state.isDictionaryManageDialogOpen, set: (val) => - store.dispatch("SET_DIALOG_OPEN", { + store.actions.SET_DIALOG_OPEN({ isDictionaryManageDialogOpen: val, }), }); @@ -145,7 +145,7 @@ const isAcceptRetrieveTelemetryDialogOpenComputed = computed({ !store.state.isDefaultStyleSelectDialogOpen && store.state.isAcceptRetrieveTelemetryDialogOpen, set: (val) => - store.dispatch("SET_DIALOG_OPEN", { + store.actions.SET_DIALOG_OPEN({ isAcceptRetrieveTelemetryDialogOpen: val, }), }); @@ -165,7 +165,7 @@ const canOpenNotificationDialog = computed(() => { const isExportSongAudioDialogOpen = computed({ get: () => store.state.isExportSongAudioDialogOpen, set: (val) => - store.dispatch("SET_DIALOG_OPEN", { + store.actions.SET_DIALOG_OPEN({ isExportSongAudioDialogOpen: val, }), }); @@ -174,7 +174,7 @@ const isExportSongAudioDialogOpen = computed({ const isImportSongProjectDialogOpenComputed = computed({ get: () => store.state.isImportSongProjectDialogOpen, set: (val) => - store.dispatch("SET_DIALOG_OPEN", { + store.actions.SET_DIALOG_OPEN({ isImportSongProjectDialogOpen: val, }), }); diff --git a/src/components/Dialog/CharacterOrderDialog.vue b/src/components/Dialog/CharacterOrderDialog.vue index 55cd374f6e..325f54207a 100644 --- a/src/components/Dialog/CharacterOrderDialog.vue +++ b/src/components/Dialog/CharacterOrderDialog.vue @@ -164,7 +164,7 @@ watch( async (newValue, oldValue) => { if (!oldValue && newValue) { // 新しいキャラクター - newCharacters.value = await store.dispatch("GET_NEW_CHARACTERS"); + newCharacters.value = await store.actions.GET_NEW_CHARACTERS(); // サンプルの順番、新しいキャラクターは上に sampleCharacterOrder.value = [ @@ -256,8 +256,7 @@ const togglePlayOrStop = ( const characterOrderDragging = ref(false); const closeDialog = () => { - void store.dispatch( - "SET_USER_CHARACTER_ORDER", + void store.actions.SET_USER_CHARACTER_ORDER( characterOrder.value.map((info) => info.metas.speakerUuid), ); stop(); diff --git a/src/components/Dialog/DefaultStyleListDialog.vue b/src/components/Dialog/DefaultStyleListDialog.vue index 685bc5b653..1d9c796625 100644 --- a/src/components/Dialog/DefaultStyleListDialog.vue +++ b/src/components/Dialog/DefaultStyleListDialog.vue @@ -191,8 +191,7 @@ watch([() => props.modelValue], async ([newValue]) => { const isHoverableItem = ref(true); const closeDialog = () => { - void store.dispatch( - "SET_DEFAULT_STYLE_IDS", + void store.actions.SET_DEFAULT_STYLE_IDS( Object.entries(selectedStyleIndexes.value).map( ([speakerUuidStr, styleIndex]) => { const speakerUuid = SpeakerId(speakerUuidStr); diff --git a/src/components/Dialog/DefaultStyleSelectDialog.vue b/src/components/Dialog/DefaultStyleSelectDialog.vue index 68a4bbb497..77df86b2de 100644 --- a/src/components/Dialog/DefaultStyleSelectDialog.vue +++ b/src/components/Dialog/DefaultStyleSelectDialog.vue @@ -215,7 +215,7 @@ const closeDialog = () => { const defaultStyleIds = JSON.parse( JSON.stringify(store.state.defaultStyleIds), ) as DefaultStyleId[]; - void store.dispatch("SET_DEFAULT_STYLE_IDS", [ + void store.actions.SET_DEFAULT_STYLE_IDS([ ...defaultStyleIds.filter( (defaultStyleId) => defaultStyleId.speakerUuid !== props.characterInfo.metas.speakerUuid, diff --git a/src/components/Dialog/Dialog.ts b/src/components/Dialog/Dialog.ts index bb6963680b..10278dfa40 100644 --- a/src/components/Dialog/Dialog.ts +++ b/src/components/Dialog/Dialog.ts @@ -11,7 +11,7 @@ import { ErrorTypeForSaveAllResultDialog, } from "@/store/type"; import { DotNotationDispatch } from "@/store/vuex"; -import { withProgressDotNotation as withProgress } from "@/store/ui"; +import { withProgress } from "@/store/ui"; type MediaType = "audio" | "text"; diff --git a/src/components/Dialog/DictionaryManageDialog.vue b/src/components/Dialog/DictionaryManageDialog.vue index 2d4c1dcfb0..5567117996 100644 --- a/src/components/Dialog/DictionaryManageDialog.vue +++ b/src/components/Dialog/DictionaryManageDialog.vue @@ -339,10 +339,10 @@ const loadingDictProcess = async () => { loadingDictState.value = "loading"; try { userDict.value = await createUILockAction( - store.dispatch("LOAD_ALL_USER_DICT"), + store.actions.LOAD_ALL_USER_DICT(), ); } catch { - const result = await store.dispatch("SHOW_ALERT_DIALOG", { + const result = await store.actions.SHOW_ALERT_DIALOG({ title: "辞書の取得に失敗しました", message: "エンジンの再起動をお試しください。", }); @@ -352,9 +352,9 @@ const loadingDictProcess = async () => { } loadingDictState.value = "synchronizing"; try { - await createUILockAction(store.dispatch("SYNC_ALL_USER_DICT")); + await createUILockAction(store.actions.SYNC_ALL_USER_DICT()); } catch { - await store.dispatch("SHOW_ALERT_DIALOG", { + await store.actions.SHOW_ALERT_DIALOG({ title: "辞書の同期に失敗しました", message: "エンジンの再起動をお試しください。", }); @@ -441,7 +441,7 @@ const setYomi = async (text: string, changeWord?: boolean) => { text = convertLongVowel(text); accentPhrase.value = ( await createUILockAction( - store.dispatch("FETCH_ACCENT_PHRASES", { + store.actions.FETCH_ACCENT_PHRASES({ text: text + "ガ'", engineId, styleId, @@ -465,7 +465,7 @@ const changeAccent = async (_: number, accent: number) => { accentPhrase.value.accent = accent; accentPhrase.value = ( await createUILockAction( - store.dispatch("FETCH_MORA_DATA", { + store.actions.FETCH_MORA_DATA({ accentPhrases: [accentPhrase.value], engineId, styleId, @@ -479,7 +479,7 @@ const play = async () => { if (!accentPhrase.value) return; nowGenerating.value = true; - const audioItem = await store.dispatch("GENERATE_AUDIO_ITEM", { + const audioItem = await store.actions.GENERATE_AUDIO_ITEM({ text: yomi.value, voice: voiceComputed.value, }); @@ -491,13 +491,13 @@ const play = async () => { let fetchAudioResult: FetchAudioResult; try { - fetchAudioResult = await store.dispatch("FETCH_AUDIO_FROM_AUDIO_ITEM", { + fetchAudioResult = await store.actions.FETCH_AUDIO_FROM_AUDIO_ITEM({ audioItem, }); } catch (e) { window.backend.logError(e); nowGenerating.value = false; - void store.dispatch("SHOW_ALERT_DIALOG", { + void store.actions.SHOW_ALERT_DIALOG({ title: "生成に失敗しました", message: "エンジンの再起動をお試しください。", }); @@ -507,11 +507,11 @@ const play = async () => { const { blob } = fetchAudioResult; nowGenerating.value = false; nowPlaying.value = true; - await store.dispatch("PLAY_AUDIO_BLOB", { audioBlob: blob }); + await store.actions.PLAY_AUDIO_BLOB({ audioBlob: blob }); nowPlaying.value = false; }; const stop = () => { - void store.dispatch("STOP_AUDIO"); + void store.actions.STOP_AUDIO(); }; // accent phraseにあるaccentと実際に登録するアクセントには差が生まれる @@ -562,7 +562,7 @@ const saveWord = async () => { const accent = computeRegisteredAccent(); if (selectedId.value) { try { - await store.dispatch("REWRITE_WORD", { + await store.actions.REWRITE_WORD({ wordUuid: selectedId.value, surface: surface.value, pronunciation: yomi.value, @@ -570,7 +570,7 @@ const saveWord = async () => { priority: wordPriority.value, }); } catch { - void store.dispatch("SHOW_ALERT_DIALOG", { + void store.actions.SHOW_ALERT_DIALOG({ title: "単語の更新に失敗しました", message: "エンジンの再起動をお試しください。", }); @@ -579,7 +579,7 @@ const saveWord = async () => { } else { try { await createUILockAction( - store.dispatch("ADD_WORD", { + store.actions.ADD_WORD({ surface: surface.value, pronunciation: yomi.value, accentType: accent, @@ -587,7 +587,7 @@ const saveWord = async () => { }), ); } catch { - void store.dispatch("SHOW_ALERT_DIALOG", { + void store.actions.SHOW_ALERT_DIALOG({ title: "単語の登録に失敗しました", message: "エンジンの再起動をお試しください。", }); @@ -598,7 +598,7 @@ const saveWord = async () => { toInitialState(); }; const deleteWord = async () => { - const result = await store.dispatch("SHOW_WARNING_DIALOG", { + const result = await store.actions.SHOW_WARNING_DIALOG({ title: "登録された単語を削除しますか?", message: "削除された単語は元に戻せません。", actionName: "削除", @@ -606,12 +606,12 @@ const deleteWord = async () => { if (result === "OK") { try { await createUILockAction( - store.dispatch("DELETE_WORD", { + store.actions.DELETE_WORD({ wordUuid: selectedId.value, }), ); } catch { - void store.dispatch("SHOW_ALERT_DIALOG", { + void store.actions.SHOW_ALERT_DIALOG({ title: "単語の削除に失敗しました", message: "エンジンの再起動をお試しください。", }); @@ -622,7 +622,7 @@ const deleteWord = async () => { } }; const resetWord = async (id: string) => { - const result = await store.dispatch("SHOW_WARNING_DIALOG", { + const result = await store.actions.SHOW_WARNING_DIALOG({ title: "単語の変更をリセットしますか?", message: "単語の変更は破棄されてリセットされます。", actionName: "リセット", @@ -637,7 +637,7 @@ const resetWord = async (id: string) => { }; const discardOrNotDialog = async (okCallback: () => void) => { if (isWordChanged.value) { - const result = await store.dispatch("SHOW_WARNING_DIALOG", { + const result = await store.actions.SHOW_WARNING_DIALOG({ title: "単語の追加・変更を破棄しますか?", message: "破棄すると、単語の追加・変更はリセットされます。", actionName: "破棄", diff --git a/src/components/Dialog/EngineManageDialog.vue b/src/components/Dialog/EngineManageDialog.vue index dc8932287f..4e7c19403a 100644 --- a/src/components/Dialog/EngineManageDialog.vue +++ b/src/components/Dialog/EngineManageDialog.vue @@ -338,8 +338,8 @@ watch( const id = EngineId(idStr); if (engineStates.value[id] !== "READY") continue; if (engineVersions.value[id]) continue; - const version = await store - .dispatch("INSTANTIATE_ENGINE_CONNECTOR", { engineId: id }) + const version = await store.actions + .INSTANTIATE_ENGINE_CONNECTOR({ engineId: id }) .then((instance) => instance.invoke("versionVersionGet")({})) .then((version) => { // OpenAPIのバグで"latest"のようにダブルクォーテーションで囲まれていることがあるので外す @@ -408,7 +408,7 @@ const getEngineDirValidationMessage = (result: EngineDirValidationResult) => { }; const addEngine = async () => { - const result = await store.dispatch("SHOW_WARNING_DIALOG", { + const result = await store.actions.SHOW_WARNING_DIALOG({ title: "エンジン追加の確認", message: "この操作はコンピュータに損害を与える可能性があります。エンジンの配布元が信頼できない場合は追加しないでください。", @@ -418,7 +418,7 @@ const addEngine = async () => { if (engineLoaderType.value === "dir") { await lockUi( "addingEngine", - store.dispatch("ADD_ENGINE_DIR", { + store.actions.ADD_ENGINE_DIR({ engineDir: newEngineDir.value, }), ); @@ -429,7 +429,7 @@ const addEngine = async () => { } else { const success = await lockUi( "addingEngine", - store.dispatch("INSTALL_VVPP_ENGINE", vvppFilePath.value), + store.actions.INSTALL_VVPP_ENGINE(vvppFilePath.value), ); if (success) { void requireReload( @@ -450,7 +450,7 @@ const deleteEngine = async () => { throw new Error("default engine cannot be deleted"); } - const result = await store.dispatch("SHOW_CONFIRM_DIALOG", { + const result = await store.actions.SHOW_CONFIRM_DIALOG({ title: "エンジン削除の確認", message: "選択中のエンジンを削除します。よろしいですか?", actionName: "削除", @@ -463,7 +463,7 @@ const deleteEngine = async () => { throw new Error("assert engineInfos[selectedId.value].path"); await lockUi( "deletingEngine", - store.dispatch("REMOVE_ENGINE_DIR", { + store.actions.REMOVE_ENGINE_DIR({ engineDir, }), ); @@ -475,7 +475,7 @@ const deleteEngine = async () => { case "vvpp": { const success = await lockUi( "deletingEngine", - store.dispatch("UNINSTALL_VVPP_ENGINE", engineId), + store.actions.UNINSTALL_VVPP_ENGINE(engineId), ); if (success) { void requireReload( @@ -497,19 +497,19 @@ const selectEngine = (id: EngineId) => { const openSelectedEngineDirectory = () => { if (selectedId.value == undefined) throw new Error("assert selectedId.value != undefined"); - void store.dispatch("OPEN_ENGINE_DIRECTORY", { engineId: selectedId.value }); + void store.actions.OPEN_ENGINE_DIRECTORY({ engineId: selectedId.value }); }; const restartSelectedEngine = () => { if (selectedId.value == undefined) throw new Error("assert selectedId.value != undefined"); - void store.dispatch("RESTART_ENGINES", { + void store.actions.RESTART_ENGINES({ engineIds: [selectedId.value], }); }; const requireReload = async (message: string) => { - const result = await store.dispatch("SHOW_WARNING_DIALOG", { + const result = await store.actions.SHOW_WARNING_DIALOG({ title: "再読み込みが必要です", message: message, actionName: "再読み込み", @@ -517,7 +517,7 @@ const requireReload = async (message: string) => { }); toInitialState(); if (result === "OK") { - void store.dispatch("CHECK_EDITED_AND_NOT_SAVE", { + void store.actions.CHECK_EDITED_AND_NOT_SAVE({ closeOrReload: "reload", }); } @@ -535,8 +535,7 @@ const selectEngineDir = async () => { newEngineDirValidationState.value = null; return; } - newEngineDirValidationState.value = await store.dispatch( - "VALIDATE_ENGINE_DIR", + newEngineDirValidationState.value = await store.actions.VALIDATE_ENGINE_DIR( { engineDir: path, }, diff --git a/src/components/Dialog/ExportSongAudioDialog/Container.vue b/src/components/Dialog/ExportSongAudioDialog/Container.vue index 7e92efccdf..d2b821867a 100644 --- a/src/components/Dialog/ExportSongAudioDialog/Container.vue +++ b/src/components/Dialog/ExportSongAudioDialog/Container.vue @@ -21,9 +21,9 @@ const handleExportAudio = async ( ) => { let result: SaveResultObject; if (target === "master") { - result = await store.dispatch("EXPORT_AUDIO_FILE", { setting }); + result = await store.actions.EXPORT_AUDIO_FILE({ setting }); } else { - result = await store.dispatch("EXPORT_STEM_AUDIO_FILE", { setting }); + result = await store.actions.EXPORT_STEM_AUDIO_FILE({ setting }); } notifyResult( diff --git a/src/components/Dialog/HelpDialog/HelpDialog.vue b/src/components/Dialog/HelpDialog/HelpDialog.vue index db7b0851b1..34bea3cfd5 100644 --- a/src/components/Dialog/HelpDialog/HelpDialog.vue +++ b/src/components/Dialog/HelpDialog/HelpDialog.vue @@ -116,9 +116,7 @@ const store = useStore(); const { warn } = createLogger("HelpDialog"); const updateInfos = ref(); -void store - .dispatch("GET_UPDATE_INFOS") - .then((obj) => (updateInfos.value = obj)); +void store.actions.GET_UPDATE_INFOS().then((obj) => (updateInfos.value = obj)); if (!import.meta.env.VITE_LATEST_UPDATE_INFOS_URL) { throw new Error( @@ -132,26 +130,24 @@ const newUpdateResult = useFetchNewUpdateInfos( // エディタのOSSライセンス取得 const licenses = ref[]>(); -void store.dispatch("GET_OSS_LICENSES").then((obj) => (licenses.value = obj)); +void store.actions.GET_OSS_LICENSES().then((obj) => (licenses.value = obj)); const policy = ref(); -void store.dispatch("GET_POLICY_TEXT").then((obj) => (policy.value = obj)); +void store.actions.GET_POLICY_TEXT().then((obj) => (policy.value = obj)); const howToUse = ref(); -void store - .dispatch("GET_HOW_TO_USE_TEXT") - .then((obj) => (howToUse.value = obj)); +void store.actions.GET_HOW_TO_USE_TEXT().then((obj) => (howToUse.value = obj)); const ossCommunityInfos = ref(); -void store - .dispatch("GET_OSS_COMMUNITY_INFOS") +void store.actions + .GET_OSS_COMMUNITY_INFOS() .then((obj) => (ossCommunityInfos.value = obj)); const qAndA = ref(); -void store.dispatch("GET_Q_AND_A_TEXT").then((obj) => (qAndA.value = obj)); +void store.actions.GET_Q_AND_A_TEXT().then((obj) => (qAndA.value = obj)); const contact = ref(); -void store.dispatch("GET_CONTACT_TEXT").then((obj) => (contact.value = obj)); +void store.actions.GET_CONTACT_TEXT().then((obj) => (contact.value = obj)); const pagedata = computed(() => { const data: PageData[] = [ diff --git a/src/components/Dialog/HotkeySettingDialog.vue b/src/components/Dialog/HotkeySettingDialog.vue index e3590d458f..8417edb6b9 100644 --- a/src/components/Dialog/HotkeySettingDialog.vue +++ b/src/components/Dialog/HotkeySettingDialog.vue @@ -208,7 +208,7 @@ const changeHotkeySettings = ( action: action as HotkeyActionNameType, combination, }); - return store.dispatch("SET_HOTKEY_SETTINGS", { + return store.actions.SET_HOTKEY_SETTINGS({ data: { action: action as HotkeyActionNameType, combination, @@ -263,7 +263,7 @@ const setHotkeyDialogOpened = () => { }; const resetHotkey = async (action: string) => { - const result = await store.dispatch("SHOW_CONFIRM_DIALOG", { + const result = await store.actions.SHOW_CONFIRM_DIALOG({ title: "ショートカットキーを初期値に戻します", message: `${action}のショートカットキーを初期値に戻します。\n本当に戻しますか?`, actionName: "初期値に戻す", diff --git a/src/components/Dialog/ImportSongProjectDialog.vue b/src/components/Dialog/ImportSongProjectDialog.vue index 223c2f33eb..94bbef4d93 100644 --- a/src/components/Dialog/ImportSongProjectDialog.vue +++ b/src/components/Dialog/ImportSongProjectDialog.vue @@ -263,7 +263,7 @@ const handleFileChange = async (event: Event) => { try { if (file.name.endsWith(".vvproj")) { const vvproj = await file.text(); - const parsedProject = await store.dispatch("PARSE_PROJECT_FILE", { + const parsedProject = await store.actions.PARSE_PROJECT_FILE({ projectJson: vvproj, }); project.value = { @@ -306,15 +306,16 @@ const handleImportTrack = () => { throw new Error("project or selected track is not set"); } // トラックをインポート + const trackIndexes = selectedTrackIndexes.value.toSorted(); if (project.value.type === "vvproj") { - void store.dispatch("COMMAND_IMPORT_VOICEVOX_PROJECT", { + void store.actions.COMMAND_IMPORT_VOICEVOX_PROJECT({ project: project.value.project, - trackIndexes: selectedTrackIndexes.value, + trackIndexes, }); } else { - void store.dispatch("COMMAND_IMPORT_UTAFORMATIX_PROJECT", { + void store.actions.COMMAND_IMPORT_UTAFORMATIX_PROJECT({ project: project.value.project, - trackIndexes: selectedTrackIndexes.value, + trackIndexes, }); } onDialogOK(); diff --git a/src/components/Dialog/PresetManageDialog.vue b/src/components/Dialog/PresetManageDialog.vue index f0f5286374..7b7f693b58 100644 --- a/src/components/Dialog/PresetManageDialog.vue +++ b/src/components/Dialog/PresetManageDialog.vue @@ -95,21 +95,21 @@ const reorderPreset = (featurePresetList: (Preset & { key: PresetKey })[]) => { // デフォルトプリセットは表示するlistから除外しているので、末尾に追加しておかないと失われる const defaultPresetKeys = presetKeys.value.filter(isDefaultPresetKey); - void store - .dispatch("SAVE_PRESET_ORDER", { + void store.actions + .SAVE_PRESET_ORDER({ presetKeys: [...newPresetKeys, ...defaultPresetKeys], }) .finally(() => (isPreview.value = false)); }; const deletePreset = async (key: PresetKey) => { - const result = await store.dispatch("SHOW_CONFIRM_DIALOG", { + const result = await store.actions.SHOW_CONFIRM_DIALOG({ title: "プリセット削除の確認", message: `プリセット "${presetItems.value[key].name}" を削除してもよろしいですか?`, actionName: "削除", }); if (result === "OK") { - await store.dispatch("DELETE_PRESET", { + await store.actions.DELETE_PRESET({ presetKey: key, }); } diff --git a/src/components/Dialog/SettingDialog/SettingDialog.vue b/src/components/Dialog/SettingDialog/SettingDialog.vue index 8150a68a8e..d8cc3f35c7 100644 --- a/src/components/Dialog/SettingDialog/SettingDialog.vue +++ b/src/components/Dialog/SettingDialog/SettingDialog.vue @@ -180,7 +180,7 @@ :disabled="isDefaultConfirmedTips" @click=" () => { - store.dispatch('RESET_CONFIRMED_TIPS'); + store.actions.RESET_CONFIRMED_TIPS(); hasResetConfirmedTips = true; } " @@ -527,7 +527,7 @@ const inheritAudioInfoMode = computed(() => store.state.inheritAudioInfo); const activePointScrollMode = computed({ get: () => store.state.activePointScrollMode, set: (activePointScrollMode: ActivePointScrollMode) => { - void store.dispatch("SET_ACTIVE_POINT_SCROLL_MODE", { + void store.actions.SET_ACTIVE_POINT_SCROLL_MODE({ activePointScrollMode, }); }, @@ -550,7 +550,7 @@ const undoableTrackOperationsLabels = { const undoableTrackOperations = computed({ get: () => store.state.undoableTrackOperations, set: (undoableTrackOperations) => { - void store.dispatch("SET_ROOT_MISC_SETTING", { + void store.actions.SET_ROOT_MISC_SETTING({ key: "undoableTrackOperations", value: undoableTrackOperations, }); @@ -561,7 +561,7 @@ const undoableTrackOperations = computed({ const currentThemeNameComputed = computed({ get: () => store.state.currentTheme, set: (currentTheme: string) => { - void store.dispatch("SET_CURRENT_THEME_SETTING", { currentTheme }); + void store.actions.SET_CURRENT_THEME_SETTING({ currentTheme }); }, }); @@ -654,7 +654,7 @@ if (navigator.mediaDevices) { const acceptRetrieveTelemetryComputed = computed({ get: () => store.state.acceptRetrieveTelemetry == "Accepted", set: (acceptRetrieveTelemetry: boolean) => { - void store.dispatch("SET_ACCEPT_RETRIEVE_TELEMETRY", { + void store.actions.SET_ACCEPT_RETRIEVE_TELEMETRY({ acceptRetrieveTelemetry: acceptRetrieveTelemetry ? "Accepted" : "Refused", }); @@ -662,7 +662,7 @@ const acceptRetrieveTelemetryComputed = computed({ return; } - void store.dispatch("SHOW_ALERT_DIALOG", { + void store.actions.SHOW_ALERT_DIALOG({ title: "ソフトウェア利用状況のデータ収集の無効化", message: "ソフトウェア利用状況のデータ収集を完全に無効にするには、VOICEVOXを再起動する必要があります", @@ -672,21 +672,21 @@ const acceptRetrieveTelemetryComputed = computed({ }); const changeUseGpu = async (useGpu: boolean) => { - void store.dispatch("SHOW_LOADING_SCREEN", { + void store.actions.SHOW_LOADING_SCREEN({ message: "起動モードを変更中です", }); - await store.dispatch("CHANGE_USE_GPU", { + await store.actions.CHANGE_USE_GPU({ useGpu, engineId: selectedEngineId.value, }); - void store.dispatch("HIDE_ALL_LOADING_SCREEN"); + void store.actions.HIDE_ALL_LOADING_SCREEN(); }; const changeinheritAudioInfo = async (inheritAudioInfo: boolean) => { if (store.state.inheritAudioInfo === inheritAudioInfo) return; - void store.dispatch("SET_INHERIT_AUDIOINFO", { inheritAudioInfo }); + void store.actions.SET_INHERIT_AUDIOINFO({ inheritAudioInfo }); }; const changeEnablePreset = (value: boolean) => { @@ -704,7 +704,7 @@ const changeExperimentalSetting = async ( key: keyof ExperimentalSettingType, data: boolean, ) => { - void store.dispatch("SET_EXPERIMENTAL_SETTING", { + void store.actions.SET_EXPERIMENTAL_SETTING({ experimentalSetting: { ...experimentalSetting.value, [key]: data }, }); }; @@ -754,7 +754,7 @@ const handleSavingSettingChange = ( key: keyof SavingSetting, data: string | boolean | number, ) => { - void store.dispatch("SET_SAVING_SETTING", { + void store.actions.SET_SAVING_SETTING({ data: { ...savingSetting.value, [key]: data }, }); }; @@ -766,7 +766,7 @@ const outputSamplingRate = computed({ }, set: async (outputSamplingRate: SamplingRateOption) => { if (outputSamplingRate !== "engineDefault") { - const result = await store.dispatch("SHOW_CONFIRM_DIALOG", { + const result = await store.actions.SHOW_CONFIRM_DIALOG({ title: "出力サンプリングレートを変更します", message: "出力サンプリングレートを変更しても、音質は変化しません。また、音声の生成処理に若干時間がかかる場合があります。\n変更しますか?", @@ -778,7 +778,7 @@ const outputSamplingRate = computed({ } } - void store.dispatch("SET_ENGINE_SETTING", { + void store.actions.SET_ENGINE_SETTING({ engineId: selectedEngineId.value, engineSetting: { ...store.state.engineSettings[selectedEngineId.value], diff --git a/src/components/Dialog/ToolBarCustomDialog.vue b/src/components/Dialog/ToolBarCustomDialog.vue index f0ff907b0f..f0bedec67e 100644 --- a/src/components/Dialog/ToolBarCustomDialog.vue +++ b/src/components/Dialog/ToolBarCustomDialog.vue @@ -208,7 +208,7 @@ watch( ); const applyDefaultSetting = async () => { - const result = await store.dispatch("SHOW_CONFIRM_DIALOG", { + const result = await store.actions.SHOW_CONFIRM_DIALOG({ title: "ツールバーをデフォルトに戻します", message: "ツールバーをデフォルトに戻します。\nよろしいですか?", actionName: "はい", @@ -220,14 +220,14 @@ const applyDefaultSetting = async () => { } }; const saveCustomToolbar = () => { - void store.dispatch("SET_TOOLBAR_SETTING", { + void store.actions.SET_TOOLBAR_SETTING({ data: [...toolbarButtons.value], }); }; const finishOrNotDialog = async () => { if (isChanged.value) { - const result = await store.dispatch("SHOW_WARNING_DIALOG", { + const result = await store.actions.SHOW_WARNING_DIALOG({ title: "カスタマイズを終了しますか?", message: "保存せずに終了すると、カスタマイズは破棄されてリセットされます。", diff --git a/src/components/Dialog/UpdateNotificationDialog/Container.vue b/src/components/Dialog/UpdateNotificationDialog/Container.vue index f29b515657..2c9c315334 100644 --- a/src/components/Dialog/UpdateNotificationDialog/Container.vue +++ b/src/components/Dialog/UpdateNotificationDialog/Container.vue @@ -30,7 +30,7 @@ const store = useStore(); const isDialogOpenComputed = computed({ get: () => store.state.isUpdateNotificationDialogOpen, set: (val) => - store.dispatch("SET_DIALOG_OPEN", { + store.actions.SET_DIALOG_OPEN({ isUpdateNotificationDialogOpen: val, }), }); @@ -48,7 +48,7 @@ const currentVersionGetter = async () => { .getAppInfos() .then((obj) => obj.version); - await store.dispatch("WAIT_VUEX_READY", { timeout: 15000 }); + await store.actions.WAIT_VUEX_READY({ timeout: 15000 }); const skipUpdateVersion = store.state.skipUpdateVersion ?? "0.0.0"; if (semver.valid(skipUpdateVersion) == undefined) { throw new Error(`skipUpdateVersionが不正です: ${skipUpdateVersion}`); @@ -67,7 +67,7 @@ const newUpdateResult = useFetchNewUpdateInfos( // 新しいバージョンのアップデートがスキップされたときの処理 const handleSkipThisVersionClick = (version: string) => { - void store.dispatch("SET_ROOT_MISC_SETTING", { + void store.actions.SET_ROOT_MISC_SETTING({ key: "skipUpdateVersion", value: version, }); diff --git a/src/components/Menu/MenuBar/MenuBar.vue b/src/components/Menu/MenuBar/MenuBar.vue index 9118bce887..759304ed92 100644 --- a/src/components/Menu/MenuBar/MenuBar.vue +++ b/src/components/Menu/MenuBar/MenuBar.vue @@ -110,62 +110,60 @@ watch(titleText, (newTitle) => { }); const closeAllDialog = () => { - void store.dispatch("SET_DIALOG_OPEN", { + void store.actions.SET_DIALOG_OPEN({ isSettingDialogOpen: false, }); - void store.dispatch("SET_DIALOG_OPEN", { + void store.actions.SET_DIALOG_OPEN({ isHelpDialogOpen: false, }); - void store.dispatch("SET_DIALOG_OPEN", { + void store.actions.SET_DIALOG_OPEN({ isHotkeySettingDialogOpen: false, }); - void store.dispatch("SET_DIALOG_OPEN", { + void store.actions.SET_DIALOG_OPEN({ isToolbarSettingDialogOpen: false, }); - void store.dispatch("SET_DIALOG_OPEN", { + void store.actions.SET_DIALOG_OPEN({ isCharacterOrderDialogOpen: false, }); - void store.dispatch("SET_DIALOG_OPEN", { + void store.actions.SET_DIALOG_OPEN({ isDefaultStyleSelectDialogOpen: false, }); }; const openHelpDialog = () => { - void store.dispatch("SET_DIALOG_OPEN", { + void store.actions.SET_DIALOG_OPEN({ isHelpDialogOpen: true, }); }; const createNewProject = async () => { if (!uiLocked.value) { - await store.dispatch("CREATE_NEW_PROJECT", {}); + await store.actions.CREATE_NEW_PROJECT({}); } }; const saveProject = async () => { if (!uiLocked.value) { - await store.dispatch("SAVE_PROJECT_FILE", { overwrite: true }); + await store.actions.SAVE_PROJECT_FILE({ overwrite: true }); } }; const saveProjectAs = async () => { if (!uiLocked.value) { - await store.dispatch("SAVE_PROJECT_FILE", {}); + await store.actions.SAVE_PROJECT_FILE({}); } }; const importProject = () => { if (!uiLocked.value) { - void store.dispatch("LOAD_PROJECT_FILE", {}); + void store.actions.LOAD_PROJECT_FILE({}); } }; // 「最近使ったプロジェクト」のメニュー const recentProjectsSubMenuData = ref([]); const updateRecentProjects = async () => { - const recentlyUsedProjects = await store.dispatch( - "GET_RECENTLY_USED_PROJECTS", - ); + const recentlyUsedProjects = await store.actions.GET_RECENTLY_USED_PROJECTS(); recentProjectsSubMenuData.value = recentlyUsedProjects.length === 0 ? [ @@ -183,7 +181,7 @@ const updateRecentProjects = async () => { type: "button", label: projectFilePath, onClick: () => { - void store.dispatch("LOAD_PROJECT_FILE", { + void store.actions.LOAD_PROJECT_FILE({ filePath: projectFilePath, }); }, @@ -206,7 +204,7 @@ const engineSubMenuData = computed(() => { type: "button", label: "再起動", onClick: () => { - void store.dispatch("RESTART_ENGINES", { + void store.actions.RESTART_ENGINES({ engineIds: [engineInfo.uuid], }); }, @@ -228,7 +226,7 @@ const engineSubMenuData = computed(() => { type: "button", label: "フォルダを開く", onClick: () => { - void store.dispatch("OPEN_ENGINE_DIRECTORY", { + void store.actions.OPEN_ENGINE_DIRECTORY({ engineId: engineInfo.uuid, }); }, @@ -238,7 +236,7 @@ const engineSubMenuData = computed(() => { type: "button", label: "再起動", onClick: () => { - void store.dispatch("RESTART_ENGINES", { + void store.actions.RESTART_ENGINES({ engineIds: [engineInfo.uuid], }); }, @@ -254,7 +252,7 @@ const engineSubMenuData = computed(() => { type: "button", label: "全てのエンジンを再起動", onClick: () => { - void store.dispatch("RESTART_ENGINES", { + void store.actions.RESTART_ENGINES({ engineIds: engineIds.value, }); }, @@ -267,7 +265,7 @@ const engineSubMenuData = computed(() => { type: "button", label: "エンジンの管理", onClick: () => { - void store.dispatch("SET_DIALOG_OPEN", { + void store.actions.SET_DIALOG_OPEN({ isEngineManageDialogOpen: true, }); }, @@ -280,7 +278,7 @@ const engineSubMenuData = computed(() => { type: "button", label: "マルチエンジンをオンにして再読み込み", onClick() { - void store.dispatch("RELOAD_APP", { + void store.actions.RELOAD_APP({ isMultiEngineOffMode: false, }); }, @@ -355,7 +353,7 @@ const menudata = computed(() => [ label: "元に戻す", onClick: async () => { if (!uiLocked.value) { - await store.dispatch("UNDO", { editor: props.editor }); + await store.actions.UNDO({ editor: props.editor }); } }, disabled: !canUndo.value, @@ -366,7 +364,7 @@ const menudata = computed(() => [ label: "やり直す", onClick: async () => { if (!uiLocked.value) { - await store.dispatch("REDO", { editor: props.editor }); + await store.actions.REDO({ editor: props.editor }); } }, disabled: !canRedo.value, @@ -379,7 +377,7 @@ const menudata = computed(() => [ label: "すべて選択", onClick: async () => { if (!uiLocked.value && isMultiSelectEnabled.value) { - await store.dispatch("SET_SELECTED_AUDIO_KEYS", { + await store.actions.SET_SELECTED_AUDIO_KEYS({ audioKeys: audioKeys.value, }); } @@ -421,7 +419,7 @@ const menudata = computed(() => [ type: "button", label: "キー割り当て", onClick() { - void store.dispatch("SET_DIALOG_OPEN", { + void store.actions.SET_DIALOG_OPEN({ isHotkeySettingDialogOpen: true, }); }, @@ -431,7 +429,7 @@ const menudata = computed(() => [ type: "button", label: "ツールバーのカスタマイズ", onClick() { - void store.dispatch("SET_DIALOG_OPEN", { + void store.actions.SET_DIALOG_OPEN({ isToolbarSettingDialogOpen: true, }); }, @@ -441,7 +439,7 @@ const menudata = computed(() => [ type: "button", label: "キャラクター並び替え・試聴", onClick() { - void store.dispatch("SET_DIALOG_OPEN", { + void store.actions.SET_DIALOG_OPEN({ isCharacterOrderDialogOpen: true, }); }, @@ -451,7 +449,7 @@ const menudata = computed(() => [ type: "button", label: "デフォルトスタイル", onClick() { - void store.dispatch("SET_DIALOG_OPEN", { + void store.actions.SET_DIALOG_OPEN({ isDefaultStyleSelectDialogOpen: true, }); }, @@ -461,7 +459,7 @@ const menudata = computed(() => [ type: "button", label: "読み方&アクセント辞書", onClick() { - void store.dispatch("SET_DIALOG_OPEN", { + void store.actions.SET_DIALOG_OPEN({ isDictionaryManageDialogOpen: true, }); }, @@ -472,7 +470,7 @@ const menudata = computed(() => [ type: "button", label: "オプション", onClick() { - void store.dispatch("SET_DIALOG_OPEN", { + void store.actions.SET_DIALOG_OPEN({ isSettingDialogOpen: true, }); }, diff --git a/src/components/Menu/MenuBar/MinMaxCloseButtons.vue b/src/components/Menu/MenuBar/MinMaxCloseButtons.vue index 745a108c4e..baeb5973bd 100644 --- a/src/components/Menu/MenuBar/MinMaxCloseButtons.vue +++ b/src/components/Menu/MenuBar/MinMaxCloseButtons.vue @@ -97,7 +97,7 @@ const $q = useQuasar(); const store = useStore(); const closeWindow = async () => { - void store.dispatch("CHECK_EDITED_AND_NOT_SAVE", { closeOrReload: "close" }); + void store.actions.CHECK_EDITED_AND_NOT_SAVE({ closeOrReload: "close" }); }; const minimizeWindow = () => window.backend.minimizeWindow(); const maximizeWindow = () => window.backend.maximizeWindow(); diff --git a/src/components/Menu/MenuBar/TitleBarEditorSwitcher.vue b/src/components/Menu/MenuBar/TitleBarEditorSwitcher.vue index 2f5f8c4c86..6410cdae55 100644 --- a/src/components/Menu/MenuBar/TitleBarEditorSwitcher.vue +++ b/src/components/Menu/MenuBar/TitleBarEditorSwitcher.vue @@ -30,7 +30,7 @@ const openedEditor = computed(() => store.state.openedEditor); const uiLocked = computed(() => store.getters.UI_LOCKED); const switchEditor = async (editor: EditorType) => { - await store.dispatch("SET_OPENED_EDITOR", { editor }); + await store.actions.SET_OPENED_EDITOR({ editor }); }; diff --git a/src/components/Sing/PlayheadPositionDisplay.vue b/src/components/Sing/PlayheadPositionDisplay.vue new file mode 100644 index 0000000000..42292df909 --- /dev/null +++ b/src/components/Sing/PlayheadPositionDisplay.vue @@ -0,0 +1,138 @@ + + + + + diff --git a/src/components/Sing/ScoreSequencer.vue b/src/components/Sing/ScoreSequencer.vue index 6005148ab2..f814b1549b 100644 --- a/src/components/Sing/ScoreSequencer.vue +++ b/src/components/Sing/ScoreSequencer.vue @@ -325,7 +325,7 @@ const scrollX = ref(0); const scrollY = ref(0); // 再生ヘッドの位置 -const playheadTicks = ref(0); +const playheadTicks = computed(() => store.getters.PLAYHEAD_POSITION); const playheadX = computed(() => { const baseX = tickToBaseX(playheadTicks.value, tpqn.value); return Math.floor(baseX * zoomX.value); @@ -377,7 +377,7 @@ const onLyricInput = (text: string, note: Note) => { const onLyricConfirmed = (nextNoteId: NoteId | undefined) => { commitPreviewLyrics(); - void store.dispatch("SET_EDITING_LYRIC_NOTE_ID", { noteId: nextNoteId }); + void store.actions.SET_EDITING_LYRIC_NOTE_ID({ noteId: nextNoteId }); }; // プレビュー @@ -763,9 +763,9 @@ const getYInBorderBox = (clientY: number, element: HTMLElement) => { }; const selectOnlyThis = (note: Note) => { - void store.dispatch("DESELECT_ALL_NOTES"); - void store.dispatch("SELECT_NOTES", { noteIds: [note.id] }); - void store.dispatch("PLAY_PREVIEW_SOUND", { + void store.actions.DESELECT_ALL_NOTES(); + void store.actions.SELECT_NOTES({ noteIds: [note.id] }); + void store.actions.PLAY_PREVIEW_SOUND({ noteNumber: note.noteNumber, duration: PREVIEW_SOUND_DURATION, }); @@ -811,7 +811,7 @@ const startPreview = (event: MouseEvent, mode: PreviewMode, note?: Note) => { noteNumber: cursorNoteNumber, lyric: getDoremiFromNoteNumber(cursorNoteNumber), }; - void store.dispatch("DESELECT_ALL_NOTES"); + void store.actions.DESELECT_ALL_NOTES(); copiedNotes.push(note); } else { if (!note) { @@ -834,9 +834,9 @@ const startPreview = (event: MouseEvent, mode: PreviewMode, note?: Note) => { noteIdsToSelect.push(noteId); } } - void store.dispatch("SELECT_NOTES", { noteIds: noteIdsToSelect }); + void store.actions.SELECT_NOTES({ noteIds: noteIdsToSelect }); } else if (isOnCommandOrCtrlKeyDown(event)) { - void store.dispatch("SELECT_NOTES", { noteIds: [note.id] }); + void store.actions.SELECT_NOTES({ noteIds: [note.id] }); } else if (!selectedNoteIds.value.has(note.id)) { void selectOnlyThis(note); } @@ -895,21 +895,21 @@ const endPreview = () => { // 編集ターゲットがノートのときにプレビューを開始した場合の処理 if (edited) { if (previewMode.value === "ADD_NOTE") { - void store.dispatch("COMMAND_ADD_NOTES", { + void store.actions.COMMAND_ADD_NOTES({ notes: previewNotes.value, trackId: selectedTrackId.value, }); - void store.dispatch("SELECT_NOTES", { + void store.actions.SELECT_NOTES({ noteIds: previewNotes.value.map((value) => value.id), }); } else { - void store.dispatch("COMMAND_UPDATE_NOTES", { + void store.actions.COMMAND_UPDATE_NOTES({ notes: previewNotes.value, trackId: selectedTrackId.value, }); } if (previewNotes.value.length === 1) { - void store.dispatch("PLAY_PREVIEW_SOUND", { + void store.actions.PLAY_PREVIEW_SOUND({ noteNumber: previewNotes.value[0].noteNumber, duration: PREVIEW_SOUND_DURATION, }); @@ -932,14 +932,14 @@ const endPreview = () => { applyGaussianFilter(data, 0.7); data = data.map((value) => Math.exp(value)); - void store.dispatch("COMMAND_SET_PITCH_EDIT_DATA", { + void store.actions.COMMAND_SET_PITCH_EDIT_DATA({ pitchArray: data, startFrame: previewPitchEdit.value.startFrame, trackId: selectedTrackId.value, }); } } else if (previewPitchEditType === "erase") { - void store.dispatch("COMMAND_ERASE_PITCH_EDIT_DATA", { + void store.actions.COMMAND_ERASE_PITCH_EDIT_DATA({ startFrame: previewPitchEdit.value.startFrame, frameLength: previewPitchEdit.value.frameLength, trackId: selectedTrackId.value, @@ -972,7 +972,7 @@ const onNoteBarDoubleClick = (event: MouseEvent, note: Note) => { } const mouseButton = getButton(event); if (mouseButton === "LEFT_BUTTON" && note.id !== state.editingLyricNoteId) { - void store.dispatch("SET_EDITING_LYRIC_NOTE_ID", { noteId: note.id }); + void store.actions.SET_EDITING_LYRIC_NOTE_ID({ noteId: note.id }); } }; @@ -1017,7 +1017,7 @@ const onMouseDown = (event: MouseEvent) => { startPreview(event, "ADD_NOTE"); } } else { - void store.dispatch("DESELECT_ALL_NOTES"); + void store.actions.DESELECT_ALL_NOTES(); } } else if (editTarget.value === "PITCH") { if (mouseButton === "LEFT_BUTTON") { @@ -1105,9 +1105,9 @@ const rectSelect = (additive: boolean) => { } } if (!additive) { - void store.dispatch("DESELECT_ALL_NOTES"); + void store.actions.DESELECT_ALL_NOTES(); } - void store.dispatch("SELECT_NOTES", { noteIds: noteIdsToSelect }); + void store.actions.SELECT_NOTES({ noteIds: noteIdsToSelect }); }; const onMouseEnter = () => { @@ -1128,13 +1128,13 @@ const handleNotesArrowUp = () => { if (editedNotes.some((note) => note.noteNumber > 127)) { return; } - void store.dispatch("COMMAND_UPDATE_NOTES", { + void store.actions.COMMAND_UPDATE_NOTES({ notes: editedNotes, trackId: selectedTrackId.value, }); if (editedNotes.length === 1) { - void store.dispatch("PLAY_PREVIEW_SOUND", { + void store.actions.PLAY_PREVIEW_SOUND({ noteNumber: editedNotes[0].noteNumber, duration: PREVIEW_SOUND_DURATION, }); @@ -1150,13 +1150,13 @@ const handleNotesArrowDown = () => { if (editedNotes.some((note) => note.noteNumber < 0)) { return; } - void store.dispatch("COMMAND_UPDATE_NOTES", { + void store.actions.COMMAND_UPDATE_NOTES({ notes: editedNotes, trackId: selectedTrackId.value, }); if (editedNotes.length === 1) { - void store.dispatch("PLAY_PREVIEW_SOUND", { + void store.actions.PLAY_PREVIEW_SOUND({ noteNumber: editedNotes[0].noteNumber, duration: PREVIEW_SOUND_DURATION, }); @@ -1173,7 +1173,7 @@ const handleNotesArrowRight = () => { // TODO: 例外処理は`UPDATE_NOTES`内に移す? return; } - void store.dispatch("COMMAND_UPDATE_NOTES", { + void store.actions.COMMAND_UPDATE_NOTES({ notes: editedNotes, trackId: selectedTrackId.value, }); @@ -1191,7 +1191,7 @@ const handleNotesArrowLeft = () => { ) { return; } - void store.dispatch("COMMAND_UPDATE_NOTES", { + void store.actions.COMMAND_UPDATE_NOTES({ notes: editedNotes, trackId: selectedTrackId.value, }); @@ -1202,7 +1202,7 @@ const handleNotesBackspaceOrDelete = () => { // TODO: 例外処理は`COMMAND_REMOVE_SELECTED_NOTES`内に移す? return; } - void store.dispatch("COMMAND_REMOVE_SELECTED_NOTES"); + void store.actions.COMMAND_REMOVE_SELECTED_NOTES(); }; const handleKeydown = (event: KeyboardEvent) => { @@ -1230,7 +1230,7 @@ const handleKeydown = (event: KeyboardEvent) => { handleNotesBackspaceOrDelete(); break; case "Escape": - void store.dispatch("DESELECT_ALL_NOTES"); + void store.actions.DESELECT_ALL_NOTES(); break; } }; @@ -1251,7 +1251,7 @@ const setZoomX = (value: number | null) => { const scrollTop = sequencerBodyElement.scrollTop; const clientWidth = sequencerBodyElement.clientWidth; - void store.dispatch("SET_ZOOM_X", { zoomX: newZoomX }).then(() => { + void store.actions.SET_ZOOM_X({ zoomX: newZoomX }).then(() => { const centerBaseX = (scrollLeft + clientWidth / 2) / oldZoomX; const newScrollLeft = centerBaseX * newZoomX - clientWidth / 2; sequencerBodyElement.scrollTo(newScrollLeft, scrollTop); @@ -1274,7 +1274,7 @@ const setZoomY = (value: number | null) => { const scrollTop = sequencerBodyElement.scrollTop; const clientHeight = sequencerBodyElement.clientHeight; - void store.dispatch("SET_ZOOM_Y", { zoomY: newZoomY }).then(() => { + void store.actions.SET_ZOOM_Y({ zoomY: newZoomY }).then(() => { const centerBaseY = (scrollTop + clientHeight / 2) / oldZoomY; const newScrollTop = centerBaseY * newZoomY - clientHeight / 2; sequencerBodyElement.scrollTo(scrollLeft, newScrollTop); @@ -1301,7 +1301,7 @@ const onWheel = (event: WheelEvent) => { const scrollTop = sequencerBodyElement.scrollTop; guideLineX.value = 0; // 補助線がはみ出さないように位置を一旦0にする - void store.dispatch("SET_ZOOM_X", { zoomX: newZoomX }).then(() => { + void store.actions.SET_ZOOM_X({ zoomX: newZoomX }).then(() => { const cursorBaseX = (scrollLeft + cursorX.value) / oldZoomX; const newScrollLeft = cursorBaseX * newZoomX - cursorX.value; sequencerBodyElement.scrollTo(newScrollLeft, scrollTop); @@ -1316,10 +1316,8 @@ const onScroll = (event: Event) => { } }; -const playheadPositionChangeListener = (position: number) => { - playheadTicks.value = position; - - // オートスクロール +// オートスクロール +watch(playheadTicks, (newPlayheadPosition) => { const sequencerBodyElement = sequencerBody.value; if (!sequencerBodyElement) { if (import.meta.env.DEV) { @@ -1335,7 +1333,7 @@ const playheadPositionChangeListener = (position: number) => { const scrollTop = sequencerBodyElement.scrollTop; const scrollWidth = sequencerBodyElement.scrollWidth; const clientWidth = sequencerBodyElement.clientWidth; - const playheadX = tickToBaseX(position, tpqn.value) * zoomX.value; + const playheadX = tickToBaseX(newPlayheadPosition, tpqn.value) * zoomX.value; const tolerance = 3; if (playheadX < scrollLeft) { sequencerBodyElement.scrollTo(playheadX, scrollTop); @@ -1345,7 +1343,7 @@ const playheadPositionChangeListener = (position: number) => { ) { sequencerBodyElement.scrollTo(playheadX, scrollTop); } -}; +}); // スクロールバーの幅を取得する onMounted(() => { @@ -1392,10 +1390,6 @@ onActivated(() => { // リスナー登録 onActivated(() => { - void store.dispatch("ADD_PLAYHEAD_POSITION_CHANGE_LISTENER", { - listener: playheadPositionChangeListener, - }); - document.addEventListener("keydown", handleKeydown); window.addEventListener("mousemove", onMouseMove); window.addEventListener("mouseup", onMouseUp); @@ -1403,10 +1397,6 @@ onActivated(() => { // リスナー解除 onDeactivated(() => { - void store.dispatch("REMOVE_PLAYHEAD_POSITION_CHANGE_LISTENER", { - listener: playheadPositionChangeListener, - }); - document.removeEventListener("keydown", handleKeydown); window.removeEventListener("mousemove", onMouseMove); window.removeEventListener("mouseup", onMouseUp); @@ -1426,7 +1416,7 @@ registerHotkeyWithCleanup({ if (selectedNoteIds.value.size === 0) { return; } - void store.dispatch("COPY_NOTES_TO_CLIPBOARD"); + void store.actions.COPY_NOTES_TO_CLIPBOARD(); }, }); @@ -1440,7 +1430,7 @@ registerHotkeyWithCleanup({ if (selectedNoteIds.value.size === 0) { return; } - void store.dispatch("COMMAND_CUT_NOTES_TO_CLIPBOARD"); + void store.actions.COMMAND_CUT_NOTES_TO_CLIPBOARD(); }, }); @@ -1451,7 +1441,7 @@ registerHotkeyWithCleanup({ if (nowPreviewing.value) { return; } - void store.dispatch("COMMAND_PASTE_NOTES_FROM_CLIPBOARD"); + void store.actions.COMMAND_PASTE_NOTES_FROM_CLIPBOARD(); }, }); @@ -1462,7 +1452,7 @@ registerHotkeyWithCleanup({ if (nowPreviewing.value) { return; } - void store.dispatch("SELECT_ALL_NOTES_IN_TRACK", { + void store.actions.SELECT_ALL_NOTES_IN_TRACK({ trackId: selectedTrackId.value, }); }, @@ -1477,7 +1467,7 @@ const contextMenuData = computed(() => { label: "コピー", onClick: () => { contextMenu.value?.hide(); - void store.dispatch("COPY_NOTES_TO_CLIPBOARD"); + void store.actions.COPY_NOTES_TO_CLIPBOARD(); }, disabled: !isNoteSelected.value, disableWhenUiLocked: true, @@ -1487,7 +1477,7 @@ const contextMenuData = computed(() => { label: "切り取り", onClick: () => { contextMenu.value?.hide(); - void store.dispatch("COMMAND_CUT_NOTES_TO_CLIPBOARD"); + void store.actions.COMMAND_CUT_NOTES_TO_CLIPBOARD(); }, disabled: !isNoteSelected.value, disableWhenUiLocked: true, @@ -1497,7 +1487,7 @@ const contextMenuData = computed(() => { label: "貼り付け", onClick: () => { contextMenu.value?.hide(); - void store.dispatch("COMMAND_PASTE_NOTES_FROM_CLIPBOARD"); + void store.actions.COMMAND_PASTE_NOTES_FROM_CLIPBOARD(); }, disableWhenUiLocked: true, }, @@ -1507,7 +1497,7 @@ const contextMenuData = computed(() => { label: "すべて選択", onClick: () => { contextMenu.value?.hide(); - void store.dispatch("SELECT_ALL_NOTES_IN_TRACK", { + void store.actions.SELECT_ALL_NOTES_IN_TRACK({ trackId: selectedTrackId.value, }); }, @@ -1518,7 +1508,7 @@ const contextMenuData = computed(() => { label: "選択解除", onClick: () => { contextMenu.value?.hide(); - void store.dispatch("DESELECT_ALL_NOTES"); + void store.actions.DESELECT_ALL_NOTES(); }, disabled: !isNoteSelected.value, disableWhenUiLocked: true, @@ -1529,7 +1519,7 @@ const contextMenuData = computed(() => { label: "クオンタイズ", onClick: () => { contextMenu.value?.hide(); - void store.dispatch("COMMAND_QUANTIZE_SELECTED_NOTES"); + void store.actions.COMMAND_QUANTIZE_SELECTED_NOTES(); }, disabled: !isNoteSelected.value, disableWhenUiLocked: true, @@ -1540,7 +1530,7 @@ const contextMenuData = computed(() => { label: "削除", onClick: () => { contextMenu.value?.hide(); - void store.dispatch("COMMAND_REMOVE_SELECTED_NOTES"); + void store.actions.COMMAND_REMOVE_SELECTED_NOTES(); }, disabled: !isNoteSelected.value, disableWhenUiLocked: true, diff --git a/src/components/Sing/SequencerKeys.vue b/src/components/Sing/SequencerKeys.vue index cd53e2f7f7..40476f32fd 100644 --- a/src/components/Sing/SequencerKeys.vue +++ b/src/components/Sing/SequencerKeys.vue @@ -156,14 +156,14 @@ let resizeObserver: ResizeObserver | undefined; const onMouseDown = (noteNumber: number) => { noteNumberOfKeyBeingPressed.value = noteNumber; - void store.dispatch("PLAY_PREVIEW_SOUND", { noteNumber }); + void store.actions.PLAY_PREVIEW_SOUND({ noteNumber }); }; const onMouseUp = () => { if (noteNumberOfKeyBeingPressed.value != undefined) { const noteNumber = noteNumberOfKeyBeingPressed.value; noteNumberOfKeyBeingPressed.value = undefined; - void store.dispatch("STOP_PREVIEW_SOUND", { noteNumber }); + void store.actions.STOP_PREVIEW_SOUND({ noteNumber }); } }; @@ -172,11 +172,11 @@ const onMouseEnter = (noteNumber: number) => { noteNumberOfKeyBeingPressed.value != undefined && noteNumberOfKeyBeingPressed.value !== noteNumber ) { - void store.dispatch("STOP_PREVIEW_SOUND", { + void store.actions.STOP_PREVIEW_SOUND({ noteNumber: noteNumberOfKeyBeingPressed.value, }); noteNumberOfKeyBeingPressed.value = noteNumber; - void store.dispatch("PLAY_PREVIEW_SOUND", { noteNumber }); + void store.actions.PLAY_PREVIEW_SOUND({ noteNumber }); } }; diff --git a/src/components/Sing/SequencerNote.vue b/src/components/Sing/SequencerNote.vue index ba2d625828..849559b0c3 100644 --- a/src/components/Sing/SequencerNote.vue +++ b/src/components/Sing/SequencerNote.vue @@ -197,7 +197,7 @@ const contextMenuData = computed(() => { disabled: props.nowPreviewing, onClick: async () => { contextMenu.value?.hide(); - await store.dispatch("COPY_NOTES_TO_CLIPBOARD"); + await store.actions.COPY_NOTES_TO_CLIPBOARD(); }, disableWhenUiLocked: true, }, @@ -207,7 +207,7 @@ const contextMenuData = computed(() => { disabled: props.nowPreviewing, onClick: async () => { contextMenu.value?.hide(); - await store.dispatch("COMMAND_CUT_NOTES_TO_CLIPBOARD"); + await store.actions.COMMAND_CUT_NOTES_TO_CLIPBOARD(); }, disableWhenUiLocked: true, }, @@ -218,7 +218,7 @@ const contextMenuData = computed(() => { disabled: props.nowPreviewing || !props.isSelected, onClick: async () => { contextMenu.value?.hide(); - await store.dispatch("COMMAND_QUANTIZE_SELECTED_NOTES"); + await store.actions.COMMAND_QUANTIZE_SELECTED_NOTES(); }, disableWhenUiLocked: true, }, @@ -229,7 +229,7 @@ const contextMenuData = computed(() => { disabled: props.nowPreviewing || !props.isSelected, onClick: async () => { contextMenu.value?.hide(); - await store.dispatch("COMMAND_REMOVE_SELECTED_NOTES"); + await store.actions.COMMAND_REMOVE_SELECTED_NOTES(); }, disableWhenUiLocked: true, }, diff --git a/src/components/Sing/SequencerRuler/Container.vue b/src/components/Sing/SequencerRuler/Container.vue index e30f5db34b..94ebdc6c41 100644 --- a/src/components/Sing/SequencerRuler/Container.vue +++ b/src/components/Sing/SequencerRuler/Container.vue @@ -12,7 +12,7 @@ diff --git a/src/components/Sing/SideBar/SideBar.vue b/src/components/Sing/SideBar/SideBar.vue index 1c47c1db9a..c4ff6969bd 100644 --- a/src/components/Sing/SideBar/SideBar.vue +++ b/src/components/Sing/SideBar/SideBar.vue @@ -89,10 +89,10 @@ const selectedTrackId = computed(() => store.getters.SELECTED_TRACK_ID); const addTrack = async () => { const willNextSelectedTrackIndex = trackOrder.value.indexOf(selectedTrackId.value) + 1; - await store.dispatch("COMMAND_INSERT_EMPTY_TRACK", { + await store.actions.COMMAND_INSERT_EMPTY_TRACK({ prevTrackId: selectedTrackId.value, }); - await store.dispatch("SELECT_TRACK", { + await store.actions.SELECT_TRACK({ trackId: trackOrder.value[willNextSelectedTrackIndex], }); }; @@ -104,24 +104,24 @@ const deleteTrack = async () => { if (willNextSelectedTrackIndex < 0) { willNextSelectedTrackIndex = 0; } - await store.dispatch("COMMAND_DELETE_TRACK", { + await store.actions.COMMAND_DELETE_TRACK({ trackId: selectedTrackId.value, }); - await store.dispatch("SELECT_TRACK", { + await store.actions.SELECT_TRACK({ trackId: trackOrder.value[willNextSelectedTrackIndex], }); }; const unsoloAllTracks = () => { if (store.state.undoableTrackOperations.soloAndMute) { - void store.dispatch("COMMAND_UNSOLO_ALL_TRACKS"); + void store.actions.COMMAND_UNSOLO_ALL_TRACKS(); } else { - void store.dispatch("UNSOLO_ALL_TRACKS"); + void store.actions.UNSOLO_ALL_TRACKS(); } }; const reorderTracks = (trackOrder: TrackId[]) => { - void store.dispatch("COMMAND_REORDER_TRACKS", { + void store.actions.COMMAND_REORDER_TRACKS({ trackOrder, }); }; diff --git a/src/components/Sing/SideBar/TrackItem.vue b/src/components/Sing/SideBar/TrackItem.vue index c3b9f64a51..e9cd54178a 100644 --- a/src/components/Sing/SideBar/TrackItem.vue +++ b/src/components/Sing/SideBar/TrackItem.vue @@ -194,23 +194,23 @@ const shouldPlayTrack = computed(() => const setTrackPan = (pan: number) => { if (store.state.undoableTrackOperations.panAndGain) { - void store.dispatch("COMMAND_SET_TRACK_PAN", { + void store.actions.COMMAND_SET_TRACK_PAN({ trackId: props.trackId, pan, }); } else { - void store.dispatch("SET_TRACK_PAN", { trackId: props.trackId, pan }); + void store.actions.SET_TRACK_PAN({ trackId: props.trackId, pan }); } }; const setTrackGain = (gain: number) => { if (store.state.undoableTrackOperations.panAndGain) { - void store.dispatch("COMMAND_SET_TRACK_GAIN", { + void store.actions.COMMAND_SET_TRACK_GAIN({ trackId: props.trackId, gain, }); } else { - void store.dispatch("SET_TRACK_GAIN", { trackId: props.trackId, gain }); + void store.actions.SET_TRACK_GAIN({ trackId: props.trackId, gain }); } }; @@ -228,7 +228,7 @@ const updateTrackName = () => { return; } - void store.dispatch("COMMAND_SET_TRACK_NAME", { + void store.actions.COMMAND_SET_TRACK_NAME({ trackId: props.trackId, name: temporaryTrackName.value, }); @@ -236,23 +236,23 @@ const updateTrackName = () => { const setTrackMute = (mute: boolean) => { if (store.state.undoableTrackOperations.soloAndMute) { - void store.dispatch("COMMAND_SET_TRACK_MUTE", { + void store.actions.COMMAND_SET_TRACK_MUTE({ trackId: props.trackId, mute, }); } else { - void store.dispatch("SET_TRACK_MUTE", { trackId: props.trackId, mute }); + void store.actions.SET_TRACK_MUTE({ trackId: props.trackId, mute }); } }; const setTrackSolo = (solo: boolean) => { if (store.state.undoableTrackOperations.soloAndMute) { - void store.dispatch("COMMAND_SET_TRACK_SOLO", { + void store.actions.COMMAND_SET_TRACK_SOLO({ trackId: props.trackId, solo, }); } else { - void store.dispatch("SET_TRACK_SOLO", { trackId: props.trackId, solo }); + void store.actions.SET_TRACK_SOLO({ trackId: props.trackId, solo }); } }; @@ -275,16 +275,16 @@ const trackCharacter = computed< return undefined; }); const selectTrack = () => { - void store.dispatch("SET_SELECTED_TRACK", { trackId: props.trackId }); + void store.actions.SET_SELECTED_TRACK({ trackId: props.trackId }); }; const addTrack = async () => { const willNextSelectedTrackIndex = trackOrder.value.indexOf(props.trackId) + 1; - await store.dispatch("COMMAND_INSERT_EMPTY_TRACK", { + await store.actions.COMMAND_INSERT_EMPTY_TRACK({ prevTrackId: props.trackId, }); - await store.dispatch("SELECT_TRACK", { + await store.actions.SELECT_TRACK({ trackId: trackOrder.value[willNextSelectedTrackIndex], }); }; @@ -299,9 +299,9 @@ const deleteTrack = async () => { willNextSelectedTrackIndex = 0; } } - await store.dispatch("COMMAND_DELETE_TRACK", { trackId: props.trackId }); + await store.actions.COMMAND_DELETE_TRACK({ trackId: props.trackId }); if (willNextSelectedTrackIndex != undefined) { - await store.dispatch("SELECT_TRACK", { + await store.actions.SELECT_TRACK({ trackId: trackOrder.value[willNextSelectedTrackIndex], }); } diff --git a/src/components/Sing/SingEditor.vue b/src/components/Sing/SingEditor.vue index d2bdcf9eb5..4f5f4db6e2 100644 --- a/src/components/Sing/SingEditor.vue +++ b/src/components/Sing/SingEditor.vue @@ -75,7 +75,7 @@ watch( () => store.state.tracks.size, (tracksSize, oldTracksSize) => { if (oldTracksSize <= 1 && tracksSize > 1) { - void store.dispatch("SET_SONG_SIDEBAR_OPEN", { isSongSidebarOpen: true }); + void store.actions.SET_SONG_SIDEBAR_OPEN({ isSongSidebarOpen: true }); } }, ); @@ -88,7 +88,7 @@ const nowAudioExporting = computed(() => { }); const cancelExport = () => { - void store.dispatch("CANCEL_AUDIO_EXPORT"); + void store.actions.CANCEL_AUDIO_EXPORT(); }; const isCompletedInitialStartup = ref(false); @@ -100,17 +100,17 @@ onetimeWatch( return "continue"; if (!isProjectFileLoaded) { - await store.dispatch("SET_TPQN", { tpqn: DEFAULT_TPQN }); - await store.dispatch("SET_TEMPOS", { tempos: [createDefaultTempo(0)] }); - await store.dispatch("SET_TIME_SIGNATURES", { + await store.actions.SET_TPQN({ tpqn: DEFAULT_TPQN }); + await store.actions.SET_TEMPOS({ tempos: [createDefaultTempo(0)] }); + await store.actions.SET_TIME_SIGNATURES({ timeSignatures: [createDefaultTimeSignature(1)], }); const trackId = store.state.trackOrder[0]; - await store.dispatch("SET_NOTES", { notes: [], trackId }); + await store.actions.SET_NOTES({ notes: [], trackId }); // CI上のe2eテストのNemoエンジンには歌手がいないためエラーになるのでワークアラウンド // FIXME: 歌手をいると見せかけるmock APIを作り、ここのtry catchを削除する try { - await store.dispatch("SET_SINGER", { + await store.actions.SET_SINGER({ trackId, withRelated: true, }); @@ -119,9 +119,9 @@ onetimeWatch( } } - await store.dispatch("SET_VOLUME", { volume: 0.6 }); - await store.dispatch("SET_PLAYHEAD_POSITION", { position: 0 }); - await store.dispatch("SYNC_TRACKS_AND_TRACK_CHANNEL_STRIPS"); + await store.actions.SET_VOLUME({ volume: 0.6 }); + await store.actions.SET_PLAYHEAD_POSITION({ position: 0 }); + await store.actions.SYNC_TRACKS_AND_TRACK_CHANNEL_STRIPS(); isCompletedInitialStartup.value = true; return "unwatch"; diff --git a/src/components/Sing/ToolBar/ToolBar.vue b/src/components/Sing/ToolBar/ToolBar.vue index 4488a81174..65ebb5f09b 100644 --- a/src/components/Sing/ToolBar/ToolBar.vue +++ b/src/components/Sing/ToolBar/ToolBar.vue @@ -113,12 +113,7 @@ icon="stop" @click="stop" /> -
-
{{ playheadPositionMinSecStr }}
-
- .{{ playHeadPositionMilliSecStr }} -
-
+
@@ -164,7 +159,8 @@