-
Notifications
You must be signed in to change notification settings - Fork 310
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ソング] Improve: エンジン起動前の画面を良い感じにする (#1790)
* Add: エンジン起動中のポップアップを追加 * Refactor: 共通化 * Change: slotを使わないように * Update: スタイルを移動 * Add: スケルトンを追加 * Fix: 細かいところを修正 * Fix: スタイルが消えてたので修正 * Change: EngineStartupPopup -> EngineStartupOverlay * Change: コンポーネントを分割 * Change: ToolBarは無効化で表現するように * Fix: スクロールバーが消えてたのを修正 * Delete: 未使用のスタイルを削除 * Delete: 未使用のスタイルを削除 --------- Co-authored-by: Hiroshiba <hihokaruta@gmail.com>
- Loading branch information
1 parent
e159b3c
commit 33167d8
Showing
6 changed files
with
286 additions
and
230 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
<template> | ||
<!-- TODO: 複数エンジン対応 --> | ||
<!-- TODO: allEngineStateが "ERROR" のときエラーになったエンジンを探してトーストで案内 --> | ||
<div v-if="allEngineState === 'FAILED_STARTING'" class="waiting-engine"> | ||
<div>エンジンの起動に失敗しました。エンジンの再起動をお試しください。</div> | ||
</div> | ||
<div | ||
v-else-if=" | ||
!props.isCompletedInitialStartup || allEngineState === 'STARTING' | ||
" | ||
class="waiting-engine" | ||
> | ||
<div> | ||
<q-spinner color="primary" size="2.5rem" /> | ||
<div class="q-mt-xs"> | ||
{{ | ||
allEngineState === "STARTING" | ||
? "エンジン起動中・・・" | ||
: "データ準備中・・・" | ||
}} | ||
</div> | ||
|
||
<template v-if="isEngineWaitingLong"> | ||
<q-separator spaced /> | ||
エンジン起動に時間がかかっています。<br /> | ||
<q-btn | ||
v-if="isMultipleEngine" | ||
outline | ||
:disable="reloadingLocked" | ||
@click="reloadAppWithMultiEngineOffMode" | ||
> | ||
マルチエンジンをオフにして再読み込みする</q-btn | ||
> | ||
<q-btn v-else outline @click="openQa">Q&Aを見る</q-btn> | ||
</template> | ||
</div> | ||
</div> | ||
</template> | ||
<script setup lang="ts"> | ||
import { computed, ref, watch } from "vue"; | ||
import { useStore } from "@/store"; | ||
import { EngineState } from "@/store/type"; | ||
const store = useStore(); | ||
const props = | ||
defineProps<{ | ||
isCompletedInitialStartup: boolean; | ||
}>(); | ||
const reloadingLocked = computed(() => store.state.reloadingLock); | ||
const isMultipleEngine = computed(() => store.state.engineIds.length > 1); | ||
// エンジン待機 | ||
// TODO: 個別のエンジンの状態をUIで確認できるようにする | ||
const allEngineState = computed(() => { | ||
const engineStates = store.state.engineStates; | ||
let lastEngineState: EngineState | undefined = undefined; | ||
// 登録されているすべてのエンジンについて状態を確認する | ||
for (const engineId of store.state.engineIds) { | ||
const engineState: EngineState | undefined = engineStates[engineId]; | ||
if (engineState == undefined) | ||
throw new Error(`No such engineState set: engineId == ${engineId}`); | ||
// FIXME: 1つでも接続テストに成功していないエンジンがあれば、暫定的に起動中とする | ||
if (engineState === "STARTING") { | ||
return engineState; | ||
} | ||
lastEngineState = engineState; | ||
} | ||
return lastEngineState; // FIXME: 暫定的に1つのエンジンの状態を返す | ||
}); | ||
const isEngineWaitingLong = ref<boolean>(false); | ||
let engineTimer: number | undefined = undefined; | ||
watch(allEngineState, (newEngineState) => { | ||
if (engineTimer != undefined) { | ||
clearTimeout(engineTimer); | ||
engineTimer = undefined; | ||
} | ||
if (newEngineState === "STARTING") { | ||
isEngineWaitingLong.value = false; | ||
engineTimer = window.setTimeout(() => { | ||
isEngineWaitingLong.value = true; | ||
}, 30000); | ||
} else { | ||
isEngineWaitingLong.value = false; | ||
} | ||
}); | ||
const reloadAppWithMultiEngineOffMode = () => { | ||
store.dispatch("CHECK_EDITED_AND_NOT_SAVE", { | ||
closeOrReload: "reload", | ||
isMultiEngineOffMode: true, | ||
}); | ||
}; | ||
const openQa = () => { | ||
window.open("https://voicevox.hiroshiba.jp/qa/", "_blank"); | ||
}; | ||
</script> | ||
|
||
<style scoped lang="scss"> | ||
@use '@/styles/colors' as colors; | ||
@use '@/styles/variables' as vars; | ||
.waiting-engine { | ||
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; | ||
border-radius: 6px; | ||
padding: 14px; | ||
} | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
132 changes: 132 additions & 0 deletions
132
src/components/Sing/CharacterMenuButton/SelectedCharacter.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
<template> | ||
<div v-if="props.showSkeleton" class="selected-character"> | ||
<q-skeleton class="character-avatar" type="QAvatar" size="52px" /> | ||
<div class="character-info"> | ||
<q-skeleton | ||
class="character-name skeleton" | ||
type="rect" | ||
width="65px" | ||
height="15px" | ||
/> | ||
<q-skeleton | ||
class="character-style" | ||
type="rect" | ||
width="110px" | ||
height="12px" | ||
/> | ||
</div> | ||
</div> | ||
<div v-else class="selected-character"> | ||
<q-avatar | ||
v-if="selectedStyleIconPath" | ||
class="character-avatar" | ||
size="3.5rem" | ||
> | ||
<img :src="selectedStyleIconPath" class="character-avatar-icon" /> | ||
</q-avatar> | ||
<div class="character-info"> | ||
<div class="character-name"> | ||
{{ selectedCharacterName }} | ||
</div> | ||
<div class="character-style"> | ||
{{ selectedCharacterStyleDescription }} | ||
</div> | ||
</div> | ||
<q-icon | ||
name="arrow_drop_down" | ||
size="sm" | ||
class="character-menu-dropdown-icon" | ||
/> | ||
</div> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import { computed } from "vue"; | ||
import { Singer } from "@/store/type"; | ||
import { CharacterInfo } from "@/type/preload"; | ||
import { getStyleDescription } from "@/sing/viewHelper"; | ||
const props = | ||
defineProps<{ | ||
showSkeleton: boolean; | ||
selectedCharacterInfo: CharacterInfo | undefined; | ||
selectedSinger: Singer | undefined; | ||
}>(); | ||
const selectedCharacterName = computed(() => { | ||
return props.selectedCharacterInfo?.metas.speakerName; | ||
}); | ||
const selectedCharacterStyleDescription = computed(() => { | ||
const style = props.selectedCharacterInfo?.metas.styles.find((style) => { | ||
return ( | ||
style.styleId === props.selectedSinger?.styleId && | ||
style.engineId === props.selectedSinger?.engineId | ||
); | ||
}); | ||
return style != undefined ? getStyleDescription(style) : ""; | ||
}); | ||
const selectedStyleIconPath = computed(() => { | ||
if (!props.selectedCharacterInfo || !props.selectedSinger) { | ||
return; | ||
} | ||
const styles = props.selectedCharacterInfo.metas.styles; | ||
return styles?.find((style) => { | ||
return ( | ||
style.styleId === props.selectedSinger?.styleId && | ||
style.engineId === props.selectedSinger?.engineId | ||
); | ||
})?.iconPath; | ||
}); | ||
</script> | ||
|
||
<style scoped lang="scss"> | ||
@use '@/styles/variables' as vars; | ||
@use '@/styles/colors' as colors; | ||
.selected-character { | ||
align-items: center; | ||
display: flex; | ||
padding: 0.25rem 0.5rem 0.25rem 0.25rem; | ||
position: relative; | ||
.character-avatar-icon { | ||
display: block; | ||
height: 100%; | ||
object-fit: cover; | ||
width: 100%; | ||
} | ||
.character-info { | ||
align-items: start; | ||
display: flex; | ||
flex-direction: column; | ||
margin-left: 0.5rem; | ||
text-align: left; | ||
justify-content: center; | ||
white-space: nowrap; | ||
} | ||
.character-name { | ||
font-size: 0.875rem; | ||
font-weight: bold; | ||
line-height: 1rem; | ||
padding-top: 0.5rem; | ||
&.skeleton { | ||
margin-top: 0.4rem; | ||
margin-bottom: 0.2rem; | ||
} | ||
} | ||
.character-style { | ||
color: rgba(colors.$display-rgb, 0.6); | ||
font-size: 0.75rem; | ||
font-weight: bold; | ||
line-height: 1rem; | ||
} | ||
.character-menu-dropdown-icon { | ||
color: rgba(colors.$display-rgb, 0.8); | ||
margin-left: 0.25rem; | ||
} | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.