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

ツールバーのボタンをカスタマイズ可能にする #489

Closed
wants to merge 73 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
1da38f2
make and use list of header buttons
y-chan Nov 13, 2021
fd3c3d9
move q-header
y-chan Nov 14, 2021
62a4dae
add temporary heaedr bar custom dialog
y-chan Nov 14, 2021
3cb9f21
remove undefined
y-chan Nov 14, 2021
bcd9dc5
move toolbar data to vuex store
y-chan Nov 14, 2021
0ba5a0e
remove preview title
y-chan Nov 15, 2021
48af645
add flat setting to preview card
y-chan Nov 15, 2021
2a7f87d
replace header bar
y-chan Nov 15, 2021
08e0223
add toolbar custom button (doesn't have func)
y-chan Nov 15, 2021
5588bac
Revert "move q-header"
y-chan Nov 15, 2021
131aec8
add style of radio button hover
y-chan Nov 15, 2021
73fcd3c
replace empty string by "空白"
y-chan Nov 15, 2021
9886dd0
replace space by empty button
y-chan Nov 15, 2021
0ceb4ca
カスタム -> カスタマイズ
y-chan Nov 15, 2021
ddf4b1b
fix bug (toolbar doesn't displayed at startup)
y-chan Nov 15, 2021
0c476e9
use ts
y-chan Nov 15, 2021
ba80040
fix bug of cannot edit toolbar
y-chan Nov 15, 2021
1aec854
add move left and right func to buttons
y-chan Nov 15, 2021
ca23ae0
revert remove card title
y-chan Nov 15, 2021
3381622
add setting save button
y-chan Nov 15, 2021
34b80bb
refactor and fix miss
y-chan Nov 15, 2021
bda7055
add remove func to buttons
y-chan Nov 15, 2021
80fef2c
fix error of not found selected button
y-chan Nov 17, 2021
be52685
set overflow hidden
y-chan Nov 17, 2021
63c79ce
use quaser css
y-chan Nov 17, 2021
b5ceafd
card actions -> toolbar
y-chan Nov 17, 2021
9a85b4a
specify preview toolbar height
y-chan Nov 17, 2021
611bd8e
add type of toolbar button
y-chan Nov 17, 2021
37b2a4a
add play button to toolbar's usable button list
y-chan Nov 17, 2021
359bde4
add button of exporting only one item to toolbar's usable button list
y-chan Nov 17, 2021
4caaebc
fix miss (ui lock)
y-chan Nov 17, 2021
e864b62
add button of exporting all item to toolbar's usable button list
y-chan Nov 17, 2021
6d23b4b
add button of importing text to toolbar's usable button list
y-chan Nov 17, 2021
b23dba8
make button to display selectable
y-chan Nov 17, 2021
5e32949
fix issue of being changed selected button when saving toolbar setting
y-chan Nov 17, 2021
6da6db0
automatically select added button
y-chan Nov 17, 2021
8a6b331
fix bug and improve implements
y-chan Nov 17, 2021
b13b4b8
fix order
y-chan Nov 17, 2021
f7fde2e
add finish or not dialog
y-chan Nov 17, 2021
54b5201
fix store test error
y-chan Nov 17, 2021
35ad793
remove active audio key props
y-chan Nov 17, 2021
143698e
update disable conditions for play button
y-chan Nov 17, 2021
0fe684b
remove ref
y-chan Nov 18, 2021
4c47e6d
show tooptip in preview toolbar
y-chan Nov 18, 2021
06be6e1
show space in preview toolbar and fix desc
y-chan Nov 18, 2021
b34801c
add red surrounding line
y-chan Nov 18, 2021
93f3fb4
move quasar dialog process of "generate and save all audio" to vuex
y-chan Nov 19, 2021
abddcea
move quasar dialog process of "generate and save one audio" to vuex
y-chan Nov 19, 2021
fcc25d4
improve toolbar customize ui
y-chan Nov 19, 2021
6102d78
enable save button if the old toolbar settings are different from cur…
y-chan Nov 19, 2021
cdd885a
fix ui
y-chan Nov 19, 2021
b2ad870
Merge remote-tracking branch 'upstream/main' into feature/custom-toolbar
y-chan Nov 19, 2021
6961461
remove unused import
y-chan Nov 21, 2021
45457c9
fix scss load error
y-chan Nov 21, 2021
c060970
fix empty button bug
y-chan Nov 21, 2021
d8c8562
reverse title bar and preview toolbar
y-chan Nov 21, 2021
94d5fc9
fix preview toolbar button color
y-chan Nov 21, 2021
0788ec3
fix color when dark theme
y-chan Nov 21, 2021
972b305
fix conditions of showing finish or not dialog
y-chan Nov 21, 2021
b4765ca
add undefined to selected button type
y-chan Nov 21, 2021
c25232e
add removable variable
y-chan Nov 21, 2021
fac732f
remove buttons
y-chan Nov 21, 2021
d68e8c9
add get default toolbar setting func
y-chan Nov 21, 2021
c390e5b
change background color
y-chan Nov 21, 2021
023414f
change select message
y-chan Nov 21, 2021
19315ca
set head item when close dialog
y-chan Nov 21, 2021
0ac8477
add apply default setting button
y-chan Nov 21, 2021
b6a483b
fix test case
y-chan Nov 21, 2021
1e144f2
move comment
y-chan Nov 21, 2021
702bd7d
add help dialog close process
y-chan Nov 23, 2021
8bb921e
Merge remote-tracking branch 'upstream/main' into feature/custom-toolbar
y-chan Nov 28, 2021
4fc2b13
remove "本当に"
y-chan Nov 28, 2021
fdd2813
refactor(remove parts no longer needed by menu bar lock)
y-chan Nov 28, 2021
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
28 changes: 28 additions & 0 deletions src/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
SavingSetting,
ThemeConf,
StyleInfo,
ToolbarSetting,
} from "./type/preload";

import log from "electron-log";
Expand Down Expand Up @@ -138,12 +139,21 @@ const defaultHotkeySettings: HotkeySetting[] = [
},
];

const defaultToolbarButtonSetting: ToolbarSetting = [
"連続再生",
"停止",
"空白",
"元に戻す",
"やり直す",
];

// 設定ファイル
const store = new Store<{
useGpu: boolean;
inheritAudioInfo: boolean;
savingSetting: SavingSetting;
hotkeySettings: HotkeySetting[];
toolbarSetting: ToolbarSetting;
defaultStyleIds: DefaultStyleId[];
currentTheme: string;
}>({
Expand Down Expand Up @@ -200,6 +210,13 @@ const store = new Store<{
},
default: defaultHotkeySettings,
},
toolbarSetting: {
type: "array",
items: {
type: "string",
},
default: defaultToolbarButtonSetting,
},
defaultStyleIds: {
type: "array",
items: {
Expand Down Expand Up @@ -658,6 +675,13 @@ ipcMainHandle("SAVING_SETTING", (_, { newData }) => {
return store.get("savingSetting");
});

ipcMainHandle("TOOLBAR_SETTING", (_, { newData }) => {
if (newData !== undefined) {
store.set("toolbarSetting", newData);
}
return store.get("toolbarSetting");
});

ipcMainHandle("HOTKEY_SETTINGS", (_, { newData }) => {
if (newData !== undefined) {
const hotkeySettings = store.get("hotkeySettings");
Expand Down Expand Up @@ -727,6 +751,10 @@ ipcMainHandle("GET_DEFAULT_HOTKEY_SETTINGS", () => {
return defaultHotkeySettings;
});

ipcMainHandle("GET_DEFAULT_TOOLBAR_SETTING", () => {
return defaultToolbarButtonSetting;
});

// app callback
app.on("web-contents-created", (e, contents) => {
// リンククリック時はブラウザを開く
Expand Down
194 changes: 141 additions & 53 deletions src/components/HeaderBar.vue
Original file line number Diff line number Diff line change
@@ -1,54 +1,44 @@
<template>
<q-header class="q-py-sm">
<q-toolbar>
<q-btn
unelevated
color="background-light"
text-color="display-dark"
class="text-no-wrap text-bold q-mr-sm"
:disable="uiLocked"
@click="playContinuously"
>連続再生</q-btn
>
<q-btn
unelevated
color="background-light"
text-color="display-dark"
class="text-no-wrap text-bold q-mr-sm"
:disable="!nowPlayingContinuously"
@click="stopContinuously"
>停止</q-btn
>

<q-space />
<q-btn
unelevated
color="background-light"
text-color="display-dark"
class="text-no-wrap text-bold q-mr-sm"
:disable="!canUndo || uiLocked"
@click="undo"
>元に戻す</q-btn
>
<q-btn
unelevated
color="background-light"
text-color="display-dark"
class="text-no-wrap text-bold q-mr-sm"
:disable="!canRedo || uiLocked"
@click="redo"
>やり直す</q-btn
>
<template v-for="button in headerButtons" :key="button.text">
<q-space v-if="button.text === null" />
<q-btn
v-else
unelevated
color="background-light"
text-color="display-dark"
class="text-no-wrap text-bold q-mr-sm"
:disable="button.disable.value"
@click="button.click"
>{{ button.text }}</q-btn
>
</template>
</q-toolbar>
</q-header>
</template>

<script lang="ts">
import { defineComponent, computed } from "vue";
import { defineComponent, computed, ComputedRef } from "vue";
import { useStore } from "@/store";
import { useQuasar } from "quasar";
import { setHotkeyFunctions } from "@/store/setting";
import { HotkeyAction, HotkeyReturnType } from "@/type/preload";
import {
HotkeyAction,
HotkeyReturnType,
ToolbarButtonsType,
} from "@/type/preload";
import SaveAllResultDialog from "@/components/SaveAllResultDialog.vue";

type ButtonContent =
| {
text: ToolbarButtonsType;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ToolButtonsTypeを表示するテキストそのものにしているため,テキストだけを変更したいときにも状態のマイグレーションが必要になってしまいます.(表示の為の要素がstateの中に混在してしまっています).
代わりに,そのボタンの機能ごとにタグを付けて管理してはどうでしょうか?(識別子とテキストの分離)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

なるほど、確かに言われてみれば、テキストだけを変更したい時を考えていませんでした。
識別子化は非常に良い解決策だと思うので、対応に当たりたいと思います。

click(): void;
disable: ComputedRef<boolean>;
}
| {
text: null;
};

export default defineComponent({
setup() {
Expand All @@ -61,6 +51,15 @@ export default defineComponent({
const nowPlayingContinuously = computed(
() => store.state.nowPlayingContinuously
);
const activeAudioKey = computed(() => store.getters.ACTIVE_AUDIO_KEY);
const nowPlaying = computed(() =>
activeAudioKey.value
? store.state.audioStates[activeAudioKey.value]?.nowPlaying
: false
);
const toolbarSetting = computed(() => store.state.toolbarSetting);

let continuouslyFlag = true;

const undoRedoHotkeyMap = new Map<HotkeyAction, () => HotkeyReturnType>([
// undo
Expand Down Expand Up @@ -93,7 +92,7 @@ export default defineComponent({
() => {
if (!uiLocked.value) {
if (nowPlayingContinuously.value) {
stopContinuously();
stop();
} else {
playContinuously();
}
Expand All @@ -110,9 +109,17 @@ export default defineComponent({
const redo = () => {
store.dispatch("REDO");
};
const playContinuously = async () => {
const playAudio = async () => {
try {
await store.dispatch("PLAY_CONTINUOUSLY_AUDIO");
if (continuouslyFlag) {
await store.dispatch("PLAY_CONTINUOUSLY_AUDIO");
} else if (activeAudioKey.value !== undefined) {
await store.dispatch("PLAY_AUDIO", {
audioKey: activeAudioKey.value,
});
} else {
throw Error();
}
} catch {
$q.dialog({
title: "再生に失敗しました",
Expand All @@ -125,19 +132,100 @@ export default defineComponent({
});
}
};
const stopContinuously = () => {
store.dispatch("STOP_CONTINUOUSLY_AUDIO");
const playContinuously = async () => {
continuouslyFlag = true;
await playAudio();
};
const play = async () => {
continuouslyFlag = false;
await playAudio();
};
const stop = () => {
if (continuouslyFlag) {
store.dispatch("STOP_CONTINUOUSLY_AUDIO");
} else if (activeAudioKey.value !== undefined) {
store.dispatch("STOP_AUDIO", { audioKey: activeAudioKey.value });
}
};
Segu-g marked this conversation as resolved.
Show resolved Hide resolved
const generateAndSaveAllAudio = async () => {
await store.dispatch("GENERATE_AND_SAVE_ALL_AUDIO_WITH_DIALOG", {
encoding: store.state.savingSetting.fileEncoding,
$q,
saveAllResultDialog: SaveAllResultDialog,
});
};
const generateAndSaveOneAudio = async () => {
await store.dispatch("GENERATE_AND_SAVE_AUDIO_WITH_DIALOG", {
audioKey: activeAudioKey.value as string,
$q,
encoding: store.state.savingSetting.fileEncoding,
});
};
const importTextFile = () => {
store.dispatch("COMMAND_IMPORT_FROM_FILE", {});
};

const usableButtons: ButtonContent[] = [
{
text: "連続再生",
click: playContinuously,
disable: uiLocked,
},
{
text: "再生",
click: play,
disable: computed(() => !activeAudioKey.value || uiLocked.value),
},
{
text: "停止",
click: stop,
disable: computed(
() => !nowPlayingContinuously.value && !nowPlaying.value
),
},
{
text: "音声書き出し",
click: generateAndSaveAllAudio,
disable: uiLocked,
},
{
text: "一つだけ書き出し",
click: generateAndSaveOneAudio,
disable: computed(() => !activeAudioKey.value || uiLocked.value),
},
{
text: "元に戻す",
click: undo,
disable: computed(() => !canUndo.value || uiLocked.value),
},
{
text: "やり直す",
click: redo,
disable: computed(() => !canRedo.value || uiLocked.value),
},
{
text: "テキスト読み込み",
click: importTextFile,
disable: uiLocked,
},
];
Comment on lines +168 to +211
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

textもcomputedにすれば,連続再生ボタンを連続再生停止の為にも使えます.

また,ツールバーに配置可能なactionの多くはHotKeyでも操作可能な処理が多いと思うので,その辺りと処理を纏めてactionを作ったり,disableをgetterで返したりするstoreを作ってしまってもいいかもしれません.
もっとも,ホットキーで使用可能な操作とツールバーで使用可能な操作が真に等しいかはもう少し議論すべきでしょうから,安易に纏めずにここに書き下しても構わないと思います.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

textもcomputedにすれば

確かに、これを機に再生と停止を同じボタンにまとめてしまうのは良いと思いました。
そうすれば、上のレビューであったcontinuouslyFlagの利用をしなくて済むので、複雑度が下がりそうです。
ただ、このPR内で再生と停止をまとめてしまっていいかが微妙な気がします。

また、ボタンカスタマイズの時点で、再生と停止の両方を行えるボタンであることを示すことが難しいような気もしています。
何かいい方法はないですかね...?

ツールバーに配置可能なactionの多くはHotKeyでも操作可能な処理

actionにまとめてしまう感じのことは、WITH_DIALOG系の処理で一度行っていますが、それ以外はこれ以上まとめられないような気がしています。getterを増やすのは良いかもと思いました。ちょっと検討してみます。

Copy link
Member

@Segu-g Segu-g Dec 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ボタンカスタマイズの時点で、再生と停止の両方を行えるボタンであることを示すことが難しいような気もしています。

UIについて私は詳しくないので素人なのですが,押してみれば分かりますしこれまで使っていた人が最初見た時に混乱する程度でしょうか.特に記載を行わなくても問題はなさそうな気もしますが@Hiroshiba さんに意見を貰いたいです.

それとは別に今気づいたのですが,ContinuslyフラグをAudioStateに置くべきだと思いました.どちらにしても現在の実装ではShift+Space等の別経路で連続再生したときに,連続再生したか単体再生したかHeaderBarでは判別ができないからです.
とはいっても今の実装では,STOP_AUDIOを叩いてもSTOP_CONTINUOUSLY_AUDIOを叩いてもどちらでも停止してくれるようなので分岐を間違えてもバグにはないようです.STOP_CONTINUOUSLY_AUDIOだけ叩いていても問題にはならないのですが...

ツールバーに配置可能なactionの多くはHotKeyでも操作可能な処理

ショートカットキーは一部を除いてコンポーネントに所属しないグローバルな操作なのでショートカットキーの多くはactionとして記載でき,ツールバーにも置けるかなと思いましたがこのPRでする必要は特にないと思いました.testablityが改善しそうだったので提案しましたが忙しいならこのままでも構わないと思います.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

再生と停止を同じボタンにするのは別機能なので、とりあえずこのPRではしない方針で良いと思います。
UI上もそこまで大きな問題ではないので、要望が来るまではまあ良いかなと。

別経路で連続再生したときに,連続再生したか単体再生したかHeaderBarでは判別ができない

こちら目からウロコでした。見逃していました・・・レビュー感謝です。

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ボタンカスタマイズの時点で、再生と停止の両方を行えるボタンであることを示すことが難しいような気もしています。

押してみれば分かりますし

確かに、プレビュー時点で押せば表記が切り替わるみたいな挙動をさせるのは良いと思いました。

ただ、やはり再生(連続再生)と停止のボタン統合は別PRで行うべきな気がします。
一旦切り出したいところですね。

ContinuslyフラグをAudioStateに置くべき

おっと、この問題は気づきませんでした...(私がボイボにおいてほとんどホットキーを使わないので、そこまで頭が回っていませんでした...)
この問題を解決する(continuslyをstateに持っていく)ついでに、ショートカットキーの多くをactionに移行するというのはありな気がします。
ただ、一部の例外を置いておくなどはそれはそれで気持ち悪いような気もしますが....
どちらにせよ、このPRの規模が大きくなる一方な気がするので、やるならば別PRへの切り出しが必要そうです。

STOP_CONTINUOUSLY_AUDIOだけ叩いていても問題にはならないのですが...

(もうSTOP_CONTINUOUSLY_AUDIOをSTOP_AUDIOと統合してもいいんじゃないかなって個人的には思います...)


const searchButton = (button: ToolbarButtonsType): ButtonContent => {
if (button === "空白") {
return {
text: null,
};
} else {
return usableButtons.find((b) => b.text === button) as ButtonContent;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

タグで管理し,プロパティでアクセスする方が明示的です.
(このコードだと,as ButtonContentでundefinedableを潰していますが, オブジェクトならそのプロパティが存在することを型レベルで強制できます.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

型レベルで強制できる、確かに仰る通りです。

findの使い過ぎは私も少し感じていたので、オブジェクト化を試みようと思います。

}
};

const headerButtons = computed(() =>
toolbarSetting.value.map(searchButton)
);

return {
uiLocked,
canUndo,
canRedo,
nowPlayingContinuously,
undo,
redo,
playContinuously,
stopContinuously,
headerButtons,
};
},
});
Expand Down
Loading