Skip to content

Commit

Permalink
音声書き出し時に進捗がわかるような表示を実装 (VOICEVOX#1038)
Browse files Browse the repository at this point in the history
  • Loading branch information
k-chop authored Dec 12, 2022
1 parent c1ae436 commit 04e0887
Show file tree
Hide file tree
Showing 7 changed files with 246 additions and 18 deletions.
44 changes: 31 additions & 13 deletions src/components/Dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
import SaveAllResultDialog from "@/components/SaveAllResultDialog.vue";
import { QVueGlobals } from "quasar";
import { Dispatch } from "@/store/vuex";
import { withProgress } from "@/store/ui";

type QuasarDialog = QVueGlobals["dialog"];

Expand All @@ -23,13 +24,18 @@ export async function generateAndSaveOneAudioWithDialog({
filePath?: string;
encoding?: EncodingType;
}): Promise<void> {
const result: SaveResultObject = await dispatch("GENERATE_AND_SAVE_AUDIO", {
audioKey,
filePath,
encoding,
});
const result: SaveResultObject = await withProgress(
dispatch("GENERATE_AND_SAVE_AUDIO", {
audioKey,
filePath,
encoding,
}),
dispatch
);

if (result.result === "SUCCESS" || result.result === "CANCELED") return;
let msg = "";

switch (result.result) {
case "WRITE_ERROR":
if (result.errorMessage) {
Expand Down Expand Up @@ -65,13 +71,20 @@ export async function generateAndSaveAllAudioWithDialog({
dirPath?: string;
encoding?: EncodingType;
}): Promise<void> {
const result = await dispatch("GENERATE_AND_SAVE_ALL_AUDIO", {
dirPath,
encoding,
});
const result = await withProgress(
dispatch("GENERATE_AND_SAVE_ALL_AUDIO", {
dirPath,
encoding,
callback: (finishedCount, totalCount) =>
dispatch("SET_PROGRESS_FROM_COUNT", { finishedCount, totalCount }),
}),
dispatch
);

const successArray: Array<string | undefined> = [];
const writeErrorArray: Array<WriteErrorTypeForSaveAllResultDialog> = [];
const engineErrorArray: Array<string | undefined> = [];

if (result) {
for (const item of result) {
let msg = "";
Expand Down Expand Up @@ -121,10 +134,15 @@ export async function generateAndConnectAndSaveAudioWithDialog({
filePath?: string;
encoding?: EncodingType;
}): Promise<void> {
const result = await dispatch("GENERATE_AND_CONNECT_AND_SAVE_AUDIO", {
filePath,
encoding,
});
const result = await withProgress(
dispatch("GENERATE_AND_CONNECT_AND_SAVE_AUDIO", {
filePath,
encoding,
callback: (finishedCount, totalCount) =>
dispatch("SET_PROGRESS_FROM_COUNT", { finishedCount, totalCount }),
}),
dispatch
);

if (
result === undefined ||
Expand Down
107 changes: 107 additions & 0 deletions src/components/ProgressDialog.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<template>
<div v-if="isShowProgress" class="progress">
<div>
<q-circular-progress
v-if="isDeterminate"
show-value
:value="progress"
:min="0"
:max="1"
rounded
font-size="12px"
color="primary"
size="xl"
:thickness="0.3"
>
{{ formattedProgress }}%
</q-circular-progress>
<q-circular-progress
v-if="!isDeterminate"
indeterminate
color="primary"
rounded
:thickness="0.3"
size="xl"
/>
<div class="q-mt-md">生成中です...</div>
</div>
</div>
</template>

<script lang="ts">
import { useStore } from "@/store";
import { computed, defineComponent, onUnmounted, ref, watch } from "vue";
export default defineComponent({
name: "ProgressDialog",
setup() {
const store = useStore();
const progress = computed(() => store.getters.PROGRESS);
const isShowProgress = ref<boolean>(false);
const isDeterminate = ref<boolean>(false);
let timeoutId: ReturnType<typeof setTimeout>;
const deferredProgressStart = () => {
// 3秒待ってから表示する
timeoutId = setTimeout(() => {
isShowProgress.value = true;
}, 3000);
};
watch(progress, (newValue, oldValue) => {
if (newValue === -1) {
// → 非表示
clearTimeout(timeoutId);
isShowProgress.value = false;
} else if (oldValue === -1 && newValue <= 1) {
// 非表示 → 処理中
deferredProgressStart();
isDeterminate.value = false;
} else if (oldValue !== -1 && 0 < newValue) {
// 処理中 → 処理中(0%より大きな値)
// 0 < value <= 1の間のみ進捗を%で表示する
isDeterminate.value = true;
}
});
onUnmounted(() => clearTimeout(timeoutId));
const formattedProgress = computed(() =>
(store.getters.PROGRESS * 100).toFixed()
);
return {
isShowProgress,
isDeterminate,
progress,
formattedProgress,
};
},
});
</script>

<style lang="scss" scoped>
@use '@/styles/colors' as colors;
.progress {
background-color: rgba(colors.$display-rgb, 0.15);
position: absolute;
inset: 0;
z-index: 10;
display: flex;
text-align: center;
align-items: center;
justify-content: center;
> div {
color: colors.$display;
background: colors.$surface;
width: 200px;
border-radius: 6px;
padding: 14px 48px;
}
}
</style>
38 changes: 34 additions & 4 deletions src/store/audio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
AudioCommandStoreTypes,
transformCommandStore,
} from "./type";
import { createUILockAction } from "./ui";
import { createUILockAction, withProgress } from "./ui";
import {
CharacterInfo,
DefaultStyleId,
Expand Down Expand Up @@ -1232,7 +1232,15 @@ export const audioStore = createPartialStore<AudioStoreTypes>({
action: createUILockAction(
async (
{ state, dispatch },
{ dirPath, encoding }: { dirPath?: string; encoding?: EncodingType }
{
dirPath,
encoding,
callback,
}: {
dirPath?: string;
encoding?: EncodingType;
callback?: (finishedCount: number, totalCount: number) => void;
}
) => {
if (state.savingSetting.fixedExportEnabled) {
dirPath = state.savingSetting.fixedExportDir;
Expand All @@ -1243,12 +1251,19 @@ export const audioStore = createPartialStore<AudioStoreTypes>({
}
if (dirPath) {
const _dirPath = dirPath;

const totalCount = state.audioKeys.length;
let finishedCount = 0;

const promises = state.audioKeys.map((audioKey) => {
const name = buildFileName(state, audioKey);
return dispatch("GENERATE_AND_SAVE_AUDIO", {
audioKey,
filePath: path.join(_dirPath, name),
encoding,
}).then((value) => {
callback?.(++finishedCount, totalCount);
return value;
});
});
return Promise.all(promises);
Expand All @@ -1261,7 +1276,15 @@ export const audioStore = createPartialStore<AudioStoreTypes>({
action: createUILockAction(
async (
{ state, dispatch },
{ filePath, encoding }: { filePath?: string; encoding?: EncodingType }
{
filePath,
encoding,
callback,
}: {
filePath?: string;
encoding?: EncodingType;
callback?: (finishedCount: number, totalCount: number) => void;
}
): Promise<SaveResultObject> => {
const defaultFileName = buildProjectFileName(state, "wav");

Expand Down Expand Up @@ -1313,10 +1336,14 @@ export const audioStore = createPartialStore<AudioStoreTypes>({
});
};

const totalCount = state.audioKeys.length;
let finishedCount = 0;

for (const audioKey of state.audioKeys) {
let blob = await dispatch("GET_AUDIO_CACHE", { audioKey });
if (!blob) {
blob = await dispatch("GENERATE_AUDIO", { audioKey });
callback?.(++finishedCount, totalCount);
}
if (blob === null) {
return { result: "ENGINE_ERROR", path: filePath };
Expand Down Expand Up @@ -1521,7 +1548,10 @@ export const audioStore = createPartialStore<AudioStoreTypes>({
audioKey,
nowGenerating: true,
});
blob = await dispatch("GENERATE_AUDIO", { audioKey });
blob = await withProgress(
dispatch("GENERATE_AUDIO", { audioKey }),
dispatch
);
commit("SET_AUDIO_NOW_GENERATING", {
audioKey,
nowGenerating: false,
Expand Down
24 changes: 24 additions & 0 deletions src/store/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -365,13 +365,15 @@ export type AudioStoreTypes = {
action(payload: {
dirPath?: string;
encoding?: EncodingType;
callback?: (finishedCount: number, totalCount: number) => void;
}): SaveResultObject[] | undefined;
};

GENERATE_AND_CONNECT_AND_SAVE_AUDIO: {
action(payload: {
filePath?: string;
encoding?: EncodingType;
callback?: (finishedCount: number, totalCount: number) => void;
}): SaveResultObject | undefined;
};

Expand Down Expand Up @@ -979,6 +981,7 @@ export type UiStoreState = {
isMaximized: boolean;
isPinned: boolean;
isFullscreen: boolean;
progress: number;
};

export type UiStoreTypes = {
Expand All @@ -990,6 +993,10 @@ export type UiStoreTypes = {
getter: boolean;
};

PROGRESS: {
getter: number;
};

ASYNC_UI_LOCK: {
action(payload: { callback: () => Promise<void> }): void;
};
Expand Down Expand Up @@ -1109,6 +1116,23 @@ export type UiStoreTypes = {
RESTART_APP: {
action(obj: { isSafeMode?: boolean }): void;
};

START_PROGRESS: {
action(): void;
};

SET_PROGRESS: {
mutation: { progress: number };
action(payload: { progress: number }): void;
};

SET_PROGRESS_FROM_COUNT: {
action(payload: { finishedCount: number; totalCount: number }): void;
};

RESET_PROGRESS: {
action(): void;
};
};

/*
Expand Down
Loading

0 comments on commit 04e0887

Please sign in to comment.