Skip to content

Commit

Permalink
stash
Browse files Browse the repository at this point in the history
  • Loading branch information
Hiroshiba committed Jul 12, 2024
1 parent 1712692 commit b1b10e4
Show file tree
Hide file tree
Showing 13 changed files with 204 additions and 94 deletions.
30 changes: 29 additions & 1 deletion src/components/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import AllDialog from "@/components/Dialog/AllDialog.vue";
import MenuBar from "@/components/Menu/MenuBar/MenuBar.vue";
import { useMenuBarData as useTalkMenuBarData } from "@/components/Talk/menuBarData";
import { useMenuBarData as useSingMenuBarData } from "@/components/Sing/menuBarData";
import { setFont, themeToCss } from "@/domain/dom";
const store = useStore();
Expand Down Expand Up @@ -64,7 +65,7 @@ watch(
watch(
() => store.state.editorFont,
(editorFont) => {
document.body.setAttribute("data-editor-font", editorFont);
setFont(editorFont);
},
{ immediate: true },
);
Expand All @@ -79,6 +80,33 @@ watch(
},
);
// テーマの変更を監視してCSS変数を変更する
watch(
() =>
[
store.state.currentTheme,
store.state.availableThemes,
store.state.isVuexReady,
] as const,
([currentTheme, availableThemes, isVuexReady]) => {
const theme = availableThemes.find((value) => {
return value.name == currentTheme;
});
if (theme == undefined) {
// NOTE: Vuexが初期化されていない場合はまだテーマが読み込まれていないので無視
if (isVuexReady) {
throw Error(`Theme not found: ${currentTheme}`);
} else {
return;
}
}
themeToCss(theme);
},
{ immediate: true },
);
// ソフトウェアを初期化
const { hotkeyManager } = useHotkeyManager();
const isEnginesReady = ref(false);
Expand Down
120 changes: 78 additions & 42 deletions src/components/Talk/TalkEditor.stories.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,34 @@
import { userEvent, within, expect, fn } from "@storybook/test";
import { userEvent, within, expect, fn, waitFor } from "@storybook/test";
import hotkeys from "hotkeys-js";

import { Meta, StoryObj } from "@storybook/vue3";
import { provide, toRaw } from "vue";
import TalkEditor from "./TalkEditor.vue";
import { createStoreWrapper, storeKey } from "@/store";
import { HotkeyManager, hotkeyManagerKey } from "@/plugins/hotkeyPlugin";
import { StoreType } from "@/store/type";
import {
assetsPath,
createOpenAPIEngineMock,
mockHost,
} from "@/storybook/engineMock";
} from "@/mock/engineMock";
import { proxyStoreCreator } from "@/store/proxy";
import { CharacterInfo, EngineId, SpeakerId, StyleId } from "@/type/preload";
import { getEngineManifestMock } from "@/storybook/engineMock/manifestMock";
import {
CharacterInfo,
defaultHotkeySettings,
DefaultStyleId,
EngineId,
EngineInfo,
SpeakerId,
StyleId,
ThemeConf,
} from "@/type/preload";
import { getEngineManifestMock } from "@/mock/engineMock/manifestMock";
import {
getSpeakerInfoMock,
getSpeakersMock,
} from "@/storybook/engineMock/speakerResourceMock";
} from "@/mock/engineMock/speakerResourceMock";
import { setFont, themeToCss } from "@/domain/dom";
import defaultTheme from "@/../public/themes/default.json";

const meta: Meta<typeof TalkEditor> = {
component: TalkEditor,
Expand All @@ -27,20 +38,51 @@ const meta: Meta<typeof TalkEditor> = {
},
decorators: [
(story, context) => {
// CSS関連
themeToCss(defaultTheme as ThemeConf);
setFont("default");

// ショートカットキーの管理
const hotkeyManager = new HotkeyManager();
provide(hotkeyManagerKey, hotkeyManager);
hotkeyManager.load(defaultHotkeySettings);

hotkeyManager.onEditorChange("talk");

// setup store
const store = createStoreWrapper({
proxyStoreDI: proxyStoreCreator(createOpenAPIEngineMock()),
});
store.dispatch("HYDRATE_SETTING_STORE"); // FIXME: 色設定取得のため。設定も読み込んでしまうため不要にしたい。
provide(storeKey, store);

// context.parameters.store = store;
// なぜか必要、これがないとdispatch内でcommitしたときにエラーになる
store.replaceState({
...structuredClone(toRaw(store.state)),
});

// エンジンの情報
const engineManifest = getEngineManifestMock();
const engineId = EngineId(engineManifest.uuid);
const engineInfo: EngineInfo = {
uuid: engineId,
host: mockHost,
name: engineManifest.name,
path: undefined,
executionEnabled: false,
executionFilePath: "not_found",
executionArgs: [],
type: "default",
};
store.commit("SET_ENGINE_INFOS", {
engineIds: [engineId],
engineInfos: [engineInfo],
});
store.commit("SET_ENGINE_MANIFESTS", {
engineManifests: { [engineId]: engineManifest },
});
store.commit("SET_ENGINE_STATE", { engineId, engineState: "READY" });

// setup store
// キャラクター情報
const speakers = getSpeakersMock();
const characterInfos: CharacterInfo[] = speakers.map((speaker) => {
const speakerInfo = getSpeakerInfoMock(speaker.speakerUuid, assetsPath);
Expand All @@ -66,45 +108,24 @@ const meta: Meta<typeof TalkEditor> = {
},
};
});

store.replaceState({
...structuredClone(toRaw(store.state)),
engineIds: [engineId],
engineStates: {
[engineId]: "READY",
},
engineInfos: {
[engineId]: {
uuid: engineId,
host: mockHost,
name: engineManifest.name,
path: undefined,
executionEnabled: false,
executionFilePath: "not_found",
executionArgs: [],
type: "default",
},
},
engineManifests: {
[engineId]: engineManifest,
},
characterInfos: { [engineId]: characterInfos },
defaultStyleIds: speakers.map((speaker) => ({
engineId: engineId,
speakerUuid: SpeakerId(speaker.speakerUuid),
defaultStyleId: StyleId(speaker.styles[0].id),
})),
store.commit("SET_CHARACTER_INFOS", { engineId, characterInfos });
store.commit("SET_USER_CHARACTER_ORDER", {
userCharacterOrder: store.state.characterInfos[engineId].map(
(c) => c.metas.speakerUuid,
),
});

provide(storeKey, store);
// デフォルトスタイルID
const defaultStyleIds: DefaultStyleId[] = speakers.map((speaker) => ({
engineId: engineId,
speakerUuid: SpeakerId(speaker.speakerUuid),
defaultStyleId: StyleId(speaker.styles[0].id),
}));
store.commit("SET_DEFAULT_STYLE_IDS", { defaultStyleIds });

return story();
},
],
beforeEach: async ({ parameters }) => {
// const store = parameters.store; // TODO: 型を付けたい
// await store.dispatch("LOAD_CHARACTER", { engineId: EngineId(mockHost) });
},
};

export default meta;
Expand All @@ -120,3 +141,18 @@ export const NowLoading: Story = {
isProjectFileLoaded: "waiting",
},
};

export const KeyboardShortcuts: Story = {
name: "キーボードショートカットのテスト ",
play: async ({ args, canvasElement }) => {
await waitFor(() => {
expect(args.onCompleteInitialStartup).toHaveBeenCalled();
});

// Shift+Enter でテキスト欄を追加
// await userEvent.keyboard("{Shift>}[Enter]{/Shift}");
// await userEvent.keyboard("AAAAAA{Escape}");
hotkeys.trigger("shift+enter", "talk");
たぶんショートカットは使えない!

Check failure on line 156 in src/components/Talk/TalkEditor.stories.ts

View workflow job for this annotation

GitHub Actions / build-test

Invalid character.

Check failure on line 156 in src/components/Talk/TalkEditor.stories.ts

View workflow job for this annotation

GitHub Actions / lint

Invalid character.
},
};
8 changes: 7 additions & 1 deletion src/components/Talk/TalkEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ const props = defineProps<{
isProjectFileLoaded: boolean | "waiting";
}>();
const emit = defineEmits<{
/** トークエディタの準備が完了するときに呼ばれる */
completeInitialStartup: [];
}>();
const store = useStore();
const audioKeys = computed(() => store.state.audioKeys);
Expand Down Expand Up @@ -508,7 +513,7 @@ watch(userOrderedCharacterInfos, (userOrderedCharacterInfos) => {
}
});
// エンジン初期化後の処理
/** トークエディタの準備が完了したフラグ */
const isCompletedInitialStartup = ref(false);
// TODO: Vueっぽくないので解体する
onetimeWatch(
Expand All @@ -533,6 +538,7 @@ onetimeWatch(
}
isCompletedInitialStartup.value = true;
emit("completeInitialStartup");
return "unwatch";
},
Expand Down
42 changes: 42 additions & 0 deletions src/domain/dom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { colors, Dark, setCssVar } from "quasar";
import { EditorFontType, ThemeColorType, ThemeConf } from "@/type/preload";

/** テーマの設定をCSSへ反映する */
export function themeToCss(theme: ThemeConf) {
for (const key in theme.colors) {
const color = theme.colors[key as ThemeColorType];
const { r, g, b } = colors.hexToRgb(color);
document.documentElement.style.setProperty(`--color-${key}`, color);
document.documentElement.style.setProperty(
`--color-${key}-rgb`,
`${r}, ${g}, ${b}`,
);
}
const mixColors: ThemeColorType[][] = [
["primary", "background"],
["warning", "background"],
];
for (const [color1, color2] of mixColors) {
const color1Rgb = colors.hexToRgb(theme.colors[color1]);
const color2Rgb = colors.hexToRgb(theme.colors[color2]);
const r = Math.trunc((color1Rgb.r + color2Rgb.r) / 2);
const g = Math.trunc((color1Rgb.g + color2Rgb.g) / 2);
const b = Math.trunc((color1Rgb.b + color2Rgb.b) / 2);
const propertyName = `--color-mix-${color1}-${color2}-rgb`;
const cssColor = `${r}, ${g}, ${b}`;
document.documentElement.style.setProperty(propertyName, cssColor);
}
Dark.set(theme.isDark);
setCssVar("primary", theme.colors["primary"]);
setCssVar("warning", theme.colors["warning"]);

document.documentElement.setAttribute(
"is-dark-theme",
theme.isDark ? "true" : "false",
);
}

/** フォントを設定する */
export function setFont(font: EditorFontType) {
document.body.setAttribute("data-editor-font", font);
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
28 changes: 28 additions & 0 deletions src/mock/geneareNormalizedRandomState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { State } from "@/store/type";
import { AudioKey } from "@/type/preload";

function generateIncrementalUuid(index: number) {
return `00000000-0000-0000-0000-${index.toString().padStart(12, "0")}`;
}

/** Stateのランダムな部分を正規化する便利関数。テスト用。 */
export function geneareNormalizedRandomState(state: State) {
// これだと入れ替えたときとかにテストできない
// ので、やっぱりrandomUuidを使う側をmockにしたい
// globalにステートを作って、reset関数を1個まとめてあげる形がまるそう
// どうやって1箇所に集めるかは課題
// フォルダ名storybookに戻しても良さそう

// AudioKey
const oldAudioKeys = state.audioKeys;
const newAudioKeys = oldAudioKeys.map((_, index) =>
AudioKey(generateIncrementalUuid(index)),
);
state.audioItems = Object.fromEntries(
oldAudioKeys.map((oldKey, index) => [
newAudioKeys[index],
state.audioItems[oldKey],
]),
);
state.audioKeys = newAudioKeys;
}
36 changes: 18 additions & 18 deletions src/store/audio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -684,8 +684,8 @@ export const audioStore = createPartialStore<AudioStoreTypes>({

const query = getters.IS_ENGINE_READY(voice.engineId)
? await dispatch("FETCH_AUDIO_QUERY", fetchQueryParams).catch(
() => undefined,
)
() => undefined,

Check failure on line 687 in src/store/audio.ts

View workflow job for this annotation

GitHub Actions / build-test

Insert `··`
)

Check failure on line 688 in src/store/audio.ts

View workflow job for this annotation

GitHub Actions / build-test

Insert `··`
: undefined;

const newAudioItem: AudioItem = { text, voice };
Expand Down Expand Up @@ -2003,16 +2003,16 @@ export const audioCommandStore = transformCommandStore(
changes: Record<
AudioKey,
| {
update: "AccentPhrases";
accentPhrases: AccentPhrase[];
}
update: "AccentPhrases";

Check failure on line 2006 in src/store/audio.ts

View workflow job for this annotation

GitHub Actions / build-test

Insert `··`
accentPhrases: AccentPhrase[];

Check failure on line 2007 in src/store/audio.ts

View workflow job for this annotation

GitHub Actions / build-test

Insert `··`
}
| {
update: "AudioQuery";
query: AudioQuery;
}
update: "AudioQuery";
query: AudioQuery;
}
| {
update: "OnlyVoice";
}
update: "OnlyVoice";
}
>;
},
) {
Expand Down Expand Up @@ -2067,16 +2067,16 @@ export const audioCommandStore = transformCommandStore(
const changes: Record<
AudioKey,
| {
update: "AccentPhrases";
accentPhrases: AccentPhrase[];
}
update: "AccentPhrases";
accentPhrases: AccentPhrase[];
}
| {
update: "AudioQuery";
query: AudioQuery;
}
update: "AudioQuery";
query: AudioQuery;
}
| {
update: "OnlyVoice";
}
update: "OnlyVoice";
}
> = {};

for (const audioKey of audioKeys) {
Expand Down
Loading

0 comments on commit b1b10e4

Please sign in to comment.