Skip to content

Commit

Permalink
エディターのメイン画面でアップデートを通知する (#1616)
Browse files Browse the repository at this point in the history
Co-authored-by: Hiroshiba <[email protected]>
  • Loading branch information
liszt01 and Hiroshiba authored Nov 3, 2023
1 parent 88330de commit cd028dc
Show file tree
Hide file tree
Showing 10 changed files with 194 additions and 44 deletions.
2 changes: 2 additions & 0 deletions .env.production
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ VITE_DEFAULT_ENGINE_INFOS=`[
"host": "http://127.0.0.1:50021"
}
]`
VITE_OFFICIAL_WEBSITE_URL=https://voicevox.hiroshiba.jp/
VITE_LATEST_UPDATE_INFOS_URL=https://raw.githubusercontent.com/VOICEVOX/voicevox_blog/master/src/data/updateInfos.json
VITE_GTM_CONTAINER_ID=GTM-DUMMY
2 changes: 2 additions & 0 deletions .env.test
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ VITE_DEFAULT_ENGINE_INFOS=`[
"host": "http://127.0.0.1:50021"
}
]`
VITE_OFFICIAL_WEBSITE_URL=https://voicevox.hiroshiba.jp/
VITE_LATEST_UPDATE_INFOS_URL=https://raw.githubusercontent.com/VOICEVOX/voicevox_blog/master/src/data/updateInfos.json
VITE_GTM_CONTAINER_ID=GTM-DUMMY
107 changes: 107 additions & 0 deletions src/components/UpdateNotificationDialog.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<template>
<q-dialog v-model="modelValueComputed">
<q-card class="q-py-sm q-px-md">
<q-card-section class="q-pb-sm" align="center">
<div class="text-h6">
<q-icon name="info" color="primary" />アップデート通知
</div>
</q-card-section>
<q-card-section class="q-pt-sm" align="center">
<div class="text-body1">
最新バージョン {{ props.latestVersion }} が利用可能です。<br />
公式サイトから最新バージョンをダウンロードできます。
</div>
</q-card-section>
<q-card-section class="q-py-none scrollable-area">
<template
v-for="(info, infoIndex) of props.newUpdateInfos"
:key="infoIndex"
>
<div class="text-h6">バージョン {{ info.version }}</div>
<ul>
<template
v-for="(item, descriptionIndex) of info.descriptions"
:key="descriptionIndex"
>
<li>{{ item }}</li>
</template>
</ul>
</template>
</q-card-section>
<q-card-actions align="center" class="button-area">
<q-btn
padding="xs md"
label="キャンセル"
unelevated
color="surface"
text-color="display"
class="q-mt-sm"
@click="closeUpdateNotificationDialog()"
/>
<q-btn
padding="xs md"
label="公式サイトを開く"
unelevated
color="primary"
text-color="display-on-primary"
class="q-mt-sm"
@click="
openOfficialWebsite();
closeUpdateNotificationDialog();
"
/>
</q-card-actions>
</q-card>
</q-dialog>
</template>

<script setup lang="ts">
import { computed } from "vue";
import { UpdateInfo } from "@/type/preload";
const props =
defineProps<{
modelValue: boolean;
latestVersion: string;
newUpdateInfos: UpdateInfo[];
}>();
const emit =
defineEmits<{
(e: "update:modelValue", value: boolean): void;
}>();
const modelValueComputed = computed({
get: () => props.modelValue,
set: (val) => emit("update:modelValue", val),
});
const closeUpdateNotificationDialog = () => {
modelValueComputed.value = false;
};
const openOfficialWebsite = () => {
window.open(import.meta.env.VITE_OFFICIAL_WEBSITE_URL, "_blank");
};
</script>

<style scoped lang="scss">
@use '@/styles/colors' as colors;
.scrollable-area {
overflow-y: auto;
max-height: 250px;
}
.scrollable-area h5 {
margin: 10px 0;
}
.scrollable-area h6 {
margin: 15px 0;
}
.button-area {
border-top: 1px solid colors.$splitter;
/* ボタン領域の上部に線を引く */
}
</style>
47 changes: 3 additions & 44 deletions src/components/help/HelpDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@

<script setup lang="ts">
import { computed, ref, type Component } from "vue";
import semver from "semver";
import HelpPolicy from "./HelpPolicy.vue";
import LibraryPolicy from "./LibraryPolicy.vue";
import HowToUse from "./HowToUse.vue";
Expand All @@ -97,6 +96,7 @@ import QAndA from "./QAndA.vue";
import ContactInfo from "./ContactInfo.vue";
import { UpdateInfo as UpdateInfoObject } from "@/type/preload";
import { useStore } from "@/store";
import { useFetchNewUpdateInfos } from "@/composables/useFetchNewUpdateInfos";
type PageItem = {
type: "item";
Expand Down Expand Up @@ -131,48 +131,7 @@ const store = useStore();
const updateInfos = ref<UpdateInfoObject[]>();
store.dispatch("GET_UPDATE_INFOS").then((obj) => (updateInfos.value = obj));
const isCheckingFinished = ref<boolean>(false);
// 最新版があるか調べる
const currentVersion = ref("");
const latestVersion = ref("");
window.electron
.getAppInfos()
.then((obj) => {
currentVersion.value = obj.version;
})
.then(() => {
fetch("https://api.github.com/repos/VOICEVOX/voicevox/releases", {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
})
.then((response) => {
if (!response.ok) throw new Error("Network response was not ok.");
return response.json();
})
.then((json) => {
const newerVersion = json.find(
(item: { prerelease: boolean; tag_name: string }) => {
return (
!item.prerelease &&
semver.valid(currentVersion.value) &&
semver.valid(item.tag_name) &&
semver.lt(currentVersion.value, item.tag_name)
);
}
);
if (newerVersion) {
latestVersion.value = newerVersion.tag_name;
}
isCheckingFinished.value = true;
})
.catch((err) => {
throw new Error(err);
});
});
const { isCheckingFinished, latestVersion } = useFetchNewUpdateInfos();
const isUpdateAvailable = computed(() => {
return isCheckingFinished.value && latestVersion.value !== "";
Expand Down Expand Up @@ -223,7 +182,7 @@ const pagedata = computed(() => {
name: "アップデート情報",
component: UpdateInfo,
props: {
downloadLink: "https://voicevox.hiroshiba.jp/",
downloadLink: import.meta.env.VITE_OFFICIAL_WEBSITE_URL,
updateInfos: updateInfos.value,
isUpdateAvailable: isUpdateAvailable.value,
latestVersion: latestVersion.value,
Expand Down
47 changes: 47 additions & 0 deletions src/composables/useFetchNewUpdateInfos.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { ref } from "vue";
import semver from "semver";
import { UpdateInfo } from "@/type/preload";

// 最新版があるか調べる
// 現バージョンより新しい最新版があれば`latestVersion`に代入される
export const useFetchNewUpdateInfos = () => {
const isCheckingFinished = ref<boolean>(false);
const currentVersion = ref("");
const latestVersion = ref("");
const newUpdateInfos = ref<UpdateInfo[]>([]);

window.electron
.getAppInfos()
.then((obj) => {
currentVersion.value = obj.version;
})
.then(() => {
const url: string | undefined = import.meta.env
.VITE_LATEST_UPDATE_INFOS_URL;
if (!url) {
throw new Error(
"VITE_LATEST_UPDATE_INFOS_URLが未設定です。.env内に記載してください。"
);
}
fetch(url)
.then((response) => {
if (!response.ok) throw new Error("Network response was not ok.");
return response.json();
})
.then((json) => {
newUpdateInfos.value = json.filter((item: UpdateInfo) => {
return semver.lt(currentVersion.value, item.version);
});
if (newUpdateInfos.value?.length) {
latestVersion.value = newUpdateInfos.value[0].version;
}
isCheckingFinished.value = true;
});
});

return {
isCheckingFinished,
latestVersion,
newUpdateInfos,
};
};
3 changes: 3 additions & 0 deletions src/store/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1166,6 +1166,7 @@ export type UiStoreState = {
isAcceptTermsDialogOpen: boolean;
isDictionaryManageDialogOpen: boolean;
isEngineManageDialogOpen: boolean;
isUpdateNotificationDialogOpen: boolean;
isMaximized: boolean;
isPinned: boolean;
isFullscreen: boolean;
Expand Down Expand Up @@ -1231,6 +1232,7 @@ export type UiStoreTypes = {
isToolbarSettingDialogOpen?: boolean;
isCharacterOrderDialogOpen?: boolean;
isEngineManageDialogOpen?: boolean;
isUpdateNotificationDialogOpen?: boolean;
};
action(payload: {
isDefaultStyleSelectDialogOpen?: boolean;
Expand All @@ -1243,6 +1245,7 @@ export type UiStoreTypes = {
isToolbarSettingDialogOpen?: boolean;
isCharacterOrderDialogOpen?: boolean;
isEngineManageDialogOpen?: boolean;
isUpdateNotificationDialogOpen?: boolean;
}): void;
};

Expand Down
2 changes: 2 additions & 0 deletions src/store/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export const uiStoreState: UiStoreState = {
isAcceptTermsDialogOpen: false,
isDictionaryManageDialogOpen: false,
isEngineManageDialogOpen: false,
isUpdateNotificationDialogOpen: false,
isMaximized: false,
isPinned: false,
isFullscreen: false,
Expand Down Expand Up @@ -169,6 +170,7 @@ export const uiStore = createPartialStore<UiStoreTypes>({
isToolbarSettingDialogOpen?: boolean;
isCharacterOrderDialogOpen?: boolean;
isEngineManageDialogOpen?: boolean;
isUpdateNotificationDialogOpen?: boolean;
}
) {
for (const [key, value] of Object.entries(dialogState)) {
Expand Down
25 changes: 25 additions & 0 deletions src/views/EditorHome.vue
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,11 @@
v-model="isAcceptRetrieveTelemetryDialogOpenComputed"
/>
<accept-terms-dialog v-model="isAcceptTermsDialogOpenComputed" />
<update-notification-dialog
v-model="isUpdateNotificationDialogOpenComputed"
:latest-version="latestVersion"
:new-update-infos="newUpdateInfos"
/>
</template>

<script setup lang="ts">
Expand Down Expand Up @@ -203,6 +208,8 @@ import AcceptTermsDialog from "@/components/AcceptTermsDialog.vue";
import DictionaryManageDialog from "@/components/DictionaryManageDialog.vue";
import EngineManageDialog from "@/components/EngineManageDialog.vue";
import ProgressDialog from "@/components/ProgressDialog.vue";
import UpdateNotificationDialog from "@/components/UpdateNotificationDialog.vue";
import { useFetchNewUpdateInfos } from "@/composables/useFetchNewUpdateInfos";
import { AudioItem, EngineState } from "@/store/type";
import {
AudioKey,
Expand Down Expand Up @@ -541,6 +548,13 @@ watch(userOrderedCharacterInfos, (userOrderedCharacterInfos) => {
}
});
// エディタのアップデート確認
const { isCheckingFinished, latestVersion, newUpdateInfos } =
useFetchNewUpdateInfos();
const isUpdateAvailable = computed(() => {
return isCheckingFinished.value && latestVersion.value !== "";
});
// ソフトウェアを初期化
const isCompletedInitialStartup = ref(false);
onMounted(async () => {
Expand Down Expand Up @@ -623,6 +637,8 @@ onMounted(async () => {
import.meta.env.MODE !== "development" &&
store.state.acceptTerms !== "Accepted";
isUpdateNotificationDialogOpenComputed.value = isUpdateAvailable.value;
isCompletedInitialStartup.value = true;
});
Expand Down Expand Up @@ -798,6 +814,15 @@ const isAcceptRetrieveTelemetryDialogOpenComputed = computed({
}),
});
// アップデート通知
const isUpdateNotificationDialogOpenComputed = computed({
get: () => store.state.isUpdateNotificationDialogOpen,
set: (val) =>
store.dispatch("SET_DIALOG_OPEN", {
isUpdateNotificationDialogOpen: val,
}),
});
// ドラッグ&ドロップ
const dragEventCounter = ref(0);
const loadDraggedFile = (event: { dataTransfer: DataTransfer | null }) => {
Expand Down
2 changes: 2 additions & 0 deletions src/vite-env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ interface ImportMetaEnv {
readonly VITE_APP_NAME: string;
readonly VITE_APP_VERSION: string;
readonly VITE_DEFAULT_ENGINE_INFOS: string;
readonly VITE_OFFICIAL_WEBSITE_URL: string;
readonly VITE_LATEST_UPDATE_INFOS_URL: string;
readonly VITE_GTM_CONTAINER_ID: string;
readonly VITE_TARGET: "electron" | "browser";
}
Expand Down
1 change: 1 addition & 0 deletions tests/unit/store/Vuex.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ describe("store/vuex.js test", () => {
isDefaultStyleSelectDialogOpen: false,
isDictionaryManageDialogOpen: false,
isEngineManageDialogOpen: false,
isUpdateNotificationDialogOpen: false,
isAcceptRetrieveTelemetryDialogOpen: false,
isAcceptTermsDialogOpen: false,
isMaximized: false,
Expand Down

0 comments on commit cd028dc

Please sign in to comment.