Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

script setup:キャラクター系を移行 #1216

Merged
merged 3 commits into from
Feb 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
216 changes: 101 additions & 115 deletions src/components/CharacterButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -178,133 +178,119 @@
</q-btn>
</template>

<script lang="ts">
<script setup lang="ts">
import { base64ImageToUri } from "@/helpers/imageHelper";
import { useStore } from "@/store";
import { CharacterInfo, SpeakerId, Voice } from "@/type/preload";
import { debounce } from "quasar";
import { computed, defineComponent, PropType, ref } from "vue";

export default defineComponent({
name: "CharacterButton",

props: {
characterInfos: {
type: Array as PropType<CharacterInfo[]>,
required: true,
},
loading: { type: Boolean, default: false },
selectedVoice: { type: Object as PropType<Voice> },
showEngineInfo: { type: Boolean, default: false },
emptiable: { type: Boolean, default: false },
uiLocked: { type: Boolean, required: true },
},

emits: {
"update:selectedVoice"(selectedVoice: Voice | undefined) {
return (
selectedVoice == undefined ||
(typeof selectedVoice.engineId === "string" &&
typeof selectedVoice.speakerId === "string" &&
typeof selectedVoice.styleId === "number")
);
},
import { computed, ref } from "vue";

const props = withDefaults(
defineProps<{
characterInfos: CharacterInfo[];
loading?: boolean;
selectedVoice: Voice | undefined;
showEngineInfo?: boolean;
emptiable?: boolean;
uiLocked: boolean;
}>(),
{
loading: false,
showEngineInfo: false,
emptiable: false,
}
);

const emit = defineEmits({
"update:selectedVoice": (selectedVoice: Voice | undefined) => {
return (
selectedVoice == undefined ||
(typeof selectedVoice.engineId === "string" &&
typeof selectedVoice.speakerId === "string" &&
typeof selectedVoice.styleId === "number")
);
},
});

setup(props, { emit }) {
const store = useStore();

const selectedCharacter = computed(() => {
const selectedVoice = props.selectedVoice;
if (selectedVoice == undefined) return undefined;
const character = props.characterInfos.find(
(characterInfo) =>
characterInfo.metas.speakerUuid === selectedVoice?.speakerId &&
characterInfo.metas.styles.some(
(style) =>
style.engineId === selectedVoice.engineId &&
style.styleId === selectedVoice.styleId
)
);
return character;
});

const isSelectedItem = (characterInfo: CharacterInfo) =>
selectedCharacter.value != undefined &&
characterInfo.metas.speakerUuid ===
selectedCharacter.value?.metas.speakerUuid;
const store = useStore();

const selectedStyleInfo = computed(() => {
const selectedVoice = props.selectedVoice;
const style = selectedCharacter.value?.metas.styles.find(
const selectedCharacter = computed(() => {
const selectedVoice = props.selectedVoice;
if (selectedVoice == undefined) return undefined;
const character = props.characterInfos.find(
(characterInfo) =>
characterInfo.metas.speakerUuid === selectedVoice?.speakerId &&
characterInfo.metas.styles.some(
(style) =>
style.engineId === selectedVoice?.engineId &&
style.engineId === selectedVoice.engineId &&
style.styleId === selectedVoice.styleId
);
return style;
});

const engineIcons = computed(() =>
Object.fromEntries(
store.state.engineIds.map((engineId) => [
engineId,
base64ImageToUri(store.state.engineManifests[engineId].icon),
])
)
);

const getDefaultStyle = (speakerUuid: SpeakerId) => {
// FIXME: 同一キャラが複数エンジンにまたがっているとき、順番が先のエンジンが必ず選択される
const characterInfo = props.characterInfos.find(
(info) => info.metas.speakerUuid === speakerUuid
);
const defaultStyleId = store.state.defaultStyleIds.find(
(x) => x.speakerUuid === speakerUuid
)?.defaultStyleId;

const defaultStyle =
characterInfo?.metas.styles.find(
(style) => style.styleId === defaultStyleId
) ?? characterInfo?.metas.styles[0]; // デフォルトのスタイルIDが見つからない場合stylesの先頭を選択する

if (defaultStyle == undefined)
throw new Error("defaultStyle == undefined");

return defaultStyle;
};

const onSelectSpeaker = (speakerUuid: SpeakerId) => {
const style = getDefaultStyle(speakerUuid);
emit("update:selectedVoice", {
engineId: style.engineId,
speakerId: speakerUuid,
styleId: style.styleId,
});
};

const subMenuOpenFlags = ref(
[...Array(props.characterInfos.length)].map(() => false)
);

const reassignSubMenuOpen = debounce((idx: number) => {
if (subMenuOpenFlags.value[idx]) return;
const arr = [...Array(props.characterInfos.length)].map(() => false);
arr[idx] = true;
subMenuOpenFlags.value = arr;
}, 100);
);
return character;
});

return {
selectedCharacter,
selectedStyleInfo,
engineIcons,
isSelectedItem,
getDefaultStyle,
onSelectSpeaker,
subMenuOpenFlags,
reassignSubMenuOpen,
};
},
const isSelectedItem = (characterInfo: CharacterInfo) =>
selectedCharacter.value != undefined &&
characterInfo.metas.speakerUuid ===
selectedCharacter.value?.metas.speakerUuid;

const selectedStyleInfo = computed(() => {
const selectedVoice = props.selectedVoice;
const style = selectedCharacter.value?.metas.styles.find(
(style) =>
style.engineId === selectedVoice?.engineId &&
style.styleId === selectedVoice.styleId
);
return style;
});

const engineIcons = computed(() =>
Object.fromEntries(
store.state.engineIds.map((engineId) => [
engineId,
base64ImageToUri(store.state.engineManifests[engineId].icon),
])
)
);

const getDefaultStyle = (speakerUuid: SpeakerId) => {
// FIXME: 同一キャラが複数エンジンにまたがっているとき、順番が先のエンジンが必ず選択される
const characterInfo = props.characterInfos.find(
(info) => info.metas.speakerUuid === speakerUuid
);
const defaultStyleId = store.state.defaultStyleIds.find(
(x) => x.speakerUuid === speakerUuid
)?.defaultStyleId;

const defaultStyle =
characterInfo?.metas.styles.find(
(style) => style.styleId === defaultStyleId
) ?? characterInfo?.metas.styles[0]; // デフォルトのスタイルIDが見つからない場合stylesの先頭を選択する

if (defaultStyle == undefined) throw new Error("defaultStyle == undefined");

return defaultStyle;
};

const onSelectSpeaker = (speakerUuid: SpeakerId) => {
const style = getDefaultStyle(speakerUuid);
emit("update:selectedVoice", {
engineId: style.engineId,
speakerId: speakerUuid,
styleId: style.styleId,
});
};

const subMenuOpenFlags = ref(
[...Array(props.characterInfos.length)].map(() => false)
);

const reassignSubMenuOpen = debounce((idx: number) => {
if (subMenuOpenFlags.value[idx]) return;
const arr = [...Array(props.characterInfos.length)].map(() => false);
arr[idx] = true;
subMenuOpenFlags.value = arr;
}, 100);
</script>

<style scoped lang="scss">
Expand Down
Loading