[Update/Refactor/bugfix]
Update: Add functions and test ui. Update, backend: send latest vrct version to frontend. Refactor: Change the plugins data structure. bugfix: fix endless showing update button.
This commit is contained in:
@@ -447,11 +447,11 @@ class Controller:
|
|||||||
return {"status":200, "result":config.VERSION}
|
return {"status":200, "result":config.VERSION}
|
||||||
|
|
||||||
def checkSoftwareUpdated(self) -> dict:
|
def checkSoftwareUpdated(self) -> dict:
|
||||||
update_flag = model.checkSoftwareUpdated()
|
software_update_info = model.checkSoftwareUpdated()
|
||||||
self.run(
|
self.run(
|
||||||
200,
|
200,
|
||||||
self.run_mapping["update_software_flag"],
|
self.run_mapping["software_update_info"],
|
||||||
update_flag,
|
software_update_info,
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ run_mapping = {
|
|||||||
"mic_device_list":"/run/mic_device_list",
|
"mic_device_list":"/run/mic_device_list",
|
||||||
"speaker_device_list":"/run/speaker_device_list",
|
"speaker_device_list":"/run/speaker_device_list",
|
||||||
|
|
||||||
"update_software_flag":"/run/update_software_flag",
|
"software_update_info":"/run/software_update_info",
|
||||||
|
|
||||||
"initialization_progress":"/run/initialization_progress",
|
"initialization_progress":"/run/initialization_progress",
|
||||||
"initialization_complete":"/run/initialization_complete",
|
"initialization_complete":"/run/initialization_complete",
|
||||||
|
|||||||
@@ -320,6 +320,7 @@ class Model:
|
|||||||
def checkSoftwareUpdated():
|
def checkSoftwareUpdated():
|
||||||
# check update
|
# check update
|
||||||
update_flag = False
|
update_flag = False
|
||||||
|
version = ""
|
||||||
try:
|
try:
|
||||||
response = requests_get(config.GITHUB_URL)
|
response = requests_get(config.GITHUB_URL)
|
||||||
json_data = response.json()
|
json_data = response.json()
|
||||||
@@ -331,7 +332,10 @@ class Model:
|
|||||||
update_flag = True
|
update_flag = True
|
||||||
except Exception:
|
except Exception:
|
||||||
errorLogging()
|
errorLogging()
|
||||||
return update_flag
|
return {
|
||||||
|
"is_update_available": update_flag,
|
||||||
|
"new_version": version,
|
||||||
|
}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def updateSoftware():
|
def updateSoftware():
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export const PluginsController = ({ fetchPluginsHasRunRef }) => {
|
|||||||
currentPluginsData,
|
currentPluginsData,
|
||||||
updatePluginsData,
|
updatePluginsData,
|
||||||
currentSavedPluginsStatus,
|
currentSavedPluginsStatus,
|
||||||
|
updateIsPluginsInitialized,
|
||||||
} = usePlugins();
|
} = usePlugins();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -26,40 +27,55 @@ export const PluginsController = ({ fetchPluginsHasRunRef }) => {
|
|||||||
const info_map = new Map(info_array.map(info => [info.plugin_id, info]));
|
const info_map = new Map(info_array.map(info => [info.plugin_id, info]));
|
||||||
const prev_map = new Map(prev.data.map(item => [item.plugin_id, item]));
|
const prev_map = new Map(prev.data.map(item => [item.plugin_id, item]));
|
||||||
|
|
||||||
// info_array にある各アイテムについて、prev.data に同じ plugin_id があればマージ
|
const new_data = [];
|
||||||
const merged = info_array.map(info => {
|
for (const info of info_array) {
|
||||||
if (prev_map.has(info.plugin_id)) {
|
let new_plugin_info = {};
|
||||||
return {
|
if (prev_map.has(info.plugin_id)) { // plugin_id 登録済み
|
||||||
...info,
|
const target_downloaded_plugin = prev_map.get(info.plugin_id);
|
||||||
latest_plugin_version: info.plugin_version,
|
if (target_downloaded_plugin.is_downloaded) { // 既にダウンロード済み
|
||||||
...prev_map.get(info.plugin_id),
|
const is_latest_version_available = !(target_downloaded_plugin.plugin_version === info.plugin_version);
|
||||||
|
|
||||||
|
new_plugin_info = {
|
||||||
|
is_downloaded: true,
|
||||||
|
is_latest_version_already: (target_downloaded_plugin.downloaded_plugin_info?.plugin_version === info.plugin_version),
|
||||||
|
is_latest_version_available: is_latest_version_available,
|
||||||
|
latest_plugin_info: { ...info },
|
||||||
|
...target_downloaded_plugin,
|
||||||
|
};
|
||||||
|
} else { // infoにもあり登録済みだがダウンロードされていない
|
||||||
|
new_plugin_info = {
|
||||||
|
is_downloaded: false,
|
||||||
|
is_latest_version_already: false,
|
||||||
|
is_latest_version_available: info.is_latest_version_available,
|
||||||
|
latest_plugin_info: { ...info },
|
||||||
|
...target_downloaded_plugin,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // 未ダウンロード
|
||||||
|
new_plugin_info = {
|
||||||
|
plugin_id: info.plugin_id,
|
||||||
|
is_downloaded: false,
|
||||||
|
is_latest_version_already: false,
|
||||||
|
latest_plugin_info: { ...info },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
new_data.push(new_plugin_info);
|
||||||
...info,
|
}
|
||||||
latest_plugin_version: info.plugin_version,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// prev.data にのみ存在するアイテム = latest plugin infoには存在しない
|
// prev.data にのみ存在するアイテム = latest plugin infoには存在しない
|
||||||
// を追加し、is_outdated: true を付与
|
// を追加し、is_outdated: true を付与
|
||||||
prev.data.forEach(item => {
|
prev.data.forEach(item => {
|
||||||
if (!info_map.has(item.plugin_id)) {
|
if (!info_map.has(item.plugin_id)) {
|
||||||
merged.push({ ...item, is_outdated: true });
|
new_data.push({ ...item, is_outdated: true });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let new_value = [];
|
new_data.forEach(plugin => {
|
||||||
for (const plugin of merged) {
|
if (!plugin.is_outdated) {
|
||||||
if (plugin.downloaded_plugin_version !== plugin.latest_plugin_version && plugin.is_plugin_supported) {
|
plugin.is_latest_version_available = (plugin.latest_plugin_info.is_plugin_supported);
|
||||||
plugin.is_latest_version_available = true;
|
|
||||||
} else {
|
|
||||||
plugin.is_latest_version_available = false;
|
|
||||||
}
|
}
|
||||||
new_value.push(plugin);
|
});
|
||||||
}
|
return new_data;
|
||||||
|
|
||||||
return new_value;
|
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
@@ -68,6 +84,7 @@ export const PluginsController = ({ fetchPluginsHasRunRef }) => {
|
|||||||
|
|
||||||
if (!fetchPluginsHasRunRef.current) {
|
if (!fetchPluginsHasRunRef.current) {
|
||||||
loadPlugins();
|
loadPlugins();
|
||||||
|
updateIsPluginsInitialized(true);
|
||||||
}
|
}
|
||||||
return () => fetchPluginsHasRunRef.current = true;
|
return () => fetchPluginsHasRunRef.current = true;
|
||||||
}, []);
|
}, []);
|
||||||
@@ -76,13 +93,13 @@ export const PluginsController = ({ fetchPluginsHasRunRef }) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updatePluginsData(prev => {
|
updatePluginsData(prev => {
|
||||||
// currentSavedPluginsStatus.data の各要素を Map 化して plugin_id で参照
|
// currentSavedPluginsStatus.data の各要素を Map 化して plugin_id で参照
|
||||||
const savedMap = new Map(currentSavedPluginsStatus.data.map(saved => [saved.plugin_id, saved]));
|
const saved_map = new Map(currentSavedPluginsStatus.data.map(saved => [saved.plugin_id, saved]));
|
||||||
const prev_map = new Map(prev.data.map(item => [item.plugin_id, item]));
|
const prev_map = new Map(prev.data.map(item => [item.plugin_id, item]));
|
||||||
|
|
||||||
// prev.data にある各アイテムについて、保存済みの状態情報があればマージ
|
// prev.data にある各アイテムについて、保存済みの状態情報があればマージ
|
||||||
const merged = prev.data.map(item => {
|
const merged = prev.data.map(item => {
|
||||||
if (savedMap.has(item.plugin_id)) {
|
|
||||||
return { ...item, is_enabled: savedMap.get(item.plugin_id).is_enabled };
|
if (saved_map.has(item.plugin_id)) {
|
||||||
|
return { ...item, is_enabled: saved_map.get(item.plugin_id).is_enabled };
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
});
|
});
|
||||||
@@ -93,7 +110,6 @@ export const PluginsController = ({ fetchPluginsHasRunRef }) => {
|
|||||||
merged.push({ plugin_id: saved.plugin_id, is_enabled: saved.is_enabled });
|
merged.push({ plugin_id: saved.plugin_id, is_enabled: saved.is_enabled });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return merged;
|
return merged;
|
||||||
});
|
});
|
||||||
}, [currentSavedPluginsStatus]);
|
}, [currentSavedPluginsStatus]);
|
||||||
|
|||||||
@@ -1,31 +1,136 @@
|
|||||||
|
import React from "react";
|
||||||
import { SwitchBox } from "../index";
|
import { SwitchBox } from "../index";
|
||||||
import { _DownloadButton } from "../_atoms/_download_button/_DownloadButton";
|
import { _DownloadButton } from "../_atoms/_download_button/_DownloadButton";
|
||||||
import styles from "./PluginsControlComponent.module.scss";
|
import styles from "./PluginsControlComponent.module.scss";
|
||||||
|
|
||||||
export const PluginsControlComponent = ({ variable_state, plugin_status, toggleFunction, downloadStartFunction }) => {
|
// メインのコントロールコンポーネント。ダウンロード済み / 未ダウンロードで分岐して表示する
|
||||||
const { plugin_id, is_pending, is_downloaded, is_enabled, is_latest_version_available, is_plugin_supported, is_outdated } = plugin_status;
|
export const PluginsControlComponent = ({
|
||||||
|
variable_state,
|
||||||
|
plugin_status,
|
||||||
|
toggleFunction,
|
||||||
|
downloadStartFunction,
|
||||||
|
}) => {
|
||||||
|
// 共通オプション(各子コンポーネントに引き回す情報)
|
||||||
const option = {
|
const option = {
|
||||||
id: plugin_id,
|
id: plugin_status.plugin_id,
|
||||||
is_pending: is_pending,
|
is_pending: plugin_status.is_pending,
|
||||||
is_downloaded: is_downloaded,
|
is_downloaded: plugin_status.is_downloaded,
|
||||||
data: is_enabled,
|
data: plugin_status.is_enabled,
|
||||||
update_button: is_downloaded && is_latest_version_available,
|
update_button: plugin_status.is_downloaded && plugin_status.is_latest_version_available,
|
||||||
state: variable_state,
|
state: variable_state,
|
||||||
progress: null,
|
progress: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
const togglePlugin = () => toggleFunction(plugin_id);
|
if (plugin_status.is_downloaded) {
|
||||||
const is_turn_on_able = is_downloaded && (is_plugin_supported || is_outdated);
|
return (
|
||||||
|
<DownloadedPluginControl
|
||||||
|
option={option}
|
||||||
|
plugin_status={plugin_status}
|
||||||
|
toggleFunction={toggleFunction}
|
||||||
|
downloadStartFunction={downloadStartFunction}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<NotDownloadedPluginControl
|
||||||
|
option={option}
|
||||||
|
plugin_status={plugin_status}
|
||||||
|
downloadStartFunction={downloadStartFunction}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// -------------------------
|
||||||
|
// ダウンロード済みのプラグイン用コンポーネント
|
||||||
|
// 状態により以下の分岐を行う
|
||||||
|
// ・ is_latest_version_already が true なら「最新版を使用中」
|
||||||
|
// ・ is_latest_version_already が false かつ is_latest_version_available が true なら「最新版を利用可能」(アップデートボタン+スイッチ)
|
||||||
|
// ・ それ以外(is_latest_version_already:false && is_latest_version_available: false)なら、desc等の情報とスイッチのみ表示
|
||||||
|
const DownloadedPluginControl = ({
|
||||||
|
option,
|
||||||
|
plugin_status,
|
||||||
|
toggleFunction,
|
||||||
|
downloadStartFunction,
|
||||||
|
}) => {
|
||||||
|
// on/off トグル時の処理
|
||||||
|
const togglePlugin = () => {
|
||||||
|
toggleFunction(plugin_status.plugin_id);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// ダウンロード済みの場合、ダウンロードされた情報からタイトルやバージョンを取得
|
||||||
|
const title = plugin_status.downloaded_plugin_info?.title || plugin_status.latest_plugin_info.title;
|
||||||
|
const current_version =
|
||||||
|
plugin_status.downloaded_plugin_info?.plugin_version || plugin_status.latest_plugin_info.plugin_version;
|
||||||
|
|
||||||
|
// コンポーネントごとに表示内容を分岐
|
||||||
|
if (plugin_status.is_latest_version_already) {
|
||||||
|
// 最新版が既に使用中
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
{is_plugin_supported ? (
|
<p>{title}</p>
|
||||||
<_DownloadButton option={option} downloadStartFunction={downloadStartFunction} />
|
<p>現在のバージョン: {current_version}</p>
|
||||||
) : (
|
<p>最新版を使用中</p>
|
||||||
<div className={styles.unavailable_text}>Downloaded but outdated.</div>
|
<SwitchBox variable={option} toggleFunction={togglePlugin} />
|
||||||
)}
|
|
||||||
{is_turn_on_able && <SwitchBox variable={option} toggleFunction={togglePlugin} />}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
} else if (plugin_status.is_latest_version_available) {
|
||||||
|
// 最新版の利用可能なお知らせとアップデートボタン+スイッチ
|
||||||
|
return (
|
||||||
|
<div className={styles.container}>
|
||||||
|
<p>{title}</p>
|
||||||
|
<p>現在のバージョン: {current_version}</p>
|
||||||
|
<p>最新版を利用可能</p>
|
||||||
|
<_DownloadButton option={option} downloadStartFunction={downloadStartFunction} />
|
||||||
|
<SwitchBox variable={option} toggleFunction={togglePlugin} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// 最新版利用可能ではないがダウンロード済み
|
||||||
|
// ※「desc」に関しては、情報があればplugin_status.descやlatest_plugin_info.descを利用してください
|
||||||
|
const desc =
|
||||||
|
plugin_status.latest_plugin_info.desc ||
|
||||||
|
"追加情報がありません。";
|
||||||
|
return (
|
||||||
|
<div className={styles.container}>
|
||||||
|
<p>{title}</p>
|
||||||
|
<p>現在のバージョン: {current_version}</p>
|
||||||
|
<p>{desc}</p>
|
||||||
|
<SwitchBox variable={option} toggleFunction={togglePlugin} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// -------------------------
|
||||||
|
// 未ダウンロードのプラグイン用コンポーネント
|
||||||
|
// 状態により以下の分岐を行う
|
||||||
|
// ・ is_latest_version_available が true なら:info_title, 最新バージョン情報とダウンロードボタン
|
||||||
|
// ・ is_latest_version_available が false なら:info_title, 最新バージョン情報と「現在利用不可」
|
||||||
|
const NotDownloadedPluginControl = ({ option, plugin_status, downloadStartFunction }) => {
|
||||||
|
const title = plugin_status.latest_plugin_info.title;
|
||||||
|
const latest_version = plugin_status.latest_plugin_info.plugin_version;
|
||||||
|
// ※未ダウンロードの場合、current_versionは「未ダウンロード」や「なし」といった扱いとする
|
||||||
|
const current_version = "未ダウンロード";
|
||||||
|
|
||||||
|
if (plugin_status.is_latest_version_available) {
|
||||||
|
return (
|
||||||
|
<div className={styles.container}>
|
||||||
|
<p>{title}</p>
|
||||||
|
<p>現在のバージョン: {current_version}</p>
|
||||||
|
<p>最新バージョン: {latest_version}</p>
|
||||||
|
<_DownloadButton option={option} downloadStartFunction={downloadStartFunction} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<div className={styles.container}>
|
||||||
|
<p>{title}</p>
|
||||||
|
<p>現在のバージョン: {current_version}</p>
|
||||||
|
<p>最新バージョン: {latest_version}</p>
|
||||||
|
<p>現在利用不可</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
@@ -1,9 +1,15 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React from "react";
|
||||||
import { usePlugins } from "@logics_configs";
|
import { usePlugins } from "@logics_configs";
|
||||||
import styles from "./Plugins.module.scss";
|
import styles from "./Plugins.module.scss";
|
||||||
import { PluginsControlComponent } from "../_components";
|
import { PluginsControlComponent } from "../_components/plugins_control_component/PluginsControlComponent";
|
||||||
|
|
||||||
export const Plugins = () => {
|
export const Plugins = () => {
|
||||||
|
const {
|
||||||
|
currentIsPluginsInitialized,
|
||||||
|
} = usePlugins();
|
||||||
|
|
||||||
|
if (!currentIsPluginsInitialized.data) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<PluginDownloadContainer />
|
<PluginDownloadContainer />
|
||||||
@@ -11,6 +17,7 @@ export const Plugins = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const PluginDownloadContainer = () => {
|
const PluginDownloadContainer = () => {
|
||||||
const {
|
const {
|
||||||
downloadAndExtractPlugin,
|
downloadAndExtractPlugin,
|
||||||
@@ -18,40 +25,29 @@ const PluginDownloadContainer = () => {
|
|||||||
updatePluginsData,
|
updatePluginsData,
|
||||||
currentSavedPluginsStatus,
|
currentSavedPluginsStatus,
|
||||||
setSavedPluginsStatus,
|
setSavedPluginsStatus,
|
||||||
|
handlePendingPlugin,
|
||||||
} = usePlugins();
|
} = usePlugins();
|
||||||
|
|
||||||
|
// ダウンロード開始時の状態更新処理
|
||||||
const downloadStartFunction = async (target_plugin_id) => {
|
const downloadStartFunction = async (target_plugin_id) => {
|
||||||
updatePluginsData((old_value) => {
|
handlePendingPlugin(target_plugin_id, true);
|
||||||
const new_value = old_value.data.map(d => {
|
|
||||||
if (d.plugin_id === target_plugin_id) {
|
const target_plugin_info = currentPluginsData.data.find(
|
||||||
d.is_pending = true;
|
(d) => d.plugin_id === target_plugin_id
|
||||||
}
|
);
|
||||||
return d;
|
|
||||||
});
|
|
||||||
return new_value;
|
|
||||||
});
|
|
||||||
const target_plugin_info = currentPluginsData.data.find(d => d.plugin_id === target_plugin_id);
|
|
||||||
downloadAndExtractPlugin(target_plugin_info).then(() => {
|
downloadAndExtractPlugin(target_plugin_info).then(() => {
|
||||||
updatePluginsData((old_value) => {
|
handlePendingPlugin(target_plugin_id, false);
|
||||||
const new_value = old_value.data.map(d => {
|
|
||||||
if (d.plugin_id === target_plugin_id) {
|
|
||||||
d.is_pending = false;
|
|
||||||
d.is_downloaded = true;
|
|
||||||
}
|
|
||||||
return d;
|
|
||||||
});
|
});
|
||||||
return new_value;
|
|
||||||
});
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// プラグインのオンオフ切り替え処理
|
||||||
const toggleFunction = (target_plugin_id) => {
|
const toggleFunction = (target_plugin_id) => {
|
||||||
const is_exists = currentSavedPluginsStatus.data.some(d => d.plugin_id === target_plugin_id);
|
const is_exists = currentSavedPluginsStatus.data.some(
|
||||||
|
(d) => d.plugin_id === target_plugin_id
|
||||||
|
);
|
||||||
let new_value = [];
|
let new_value = [];
|
||||||
if (is_exists) {
|
if (is_exists) {
|
||||||
new_value = currentSavedPluginsStatus.data.map(d => {
|
new_value = currentSavedPluginsStatus.data.map((d) => {
|
||||||
if (d.plugin_id === target_plugin_id) {
|
if (d.plugin_id === target_plugin_id) {
|
||||||
d.is_enabled = !d.is_enabled;
|
d.is_enabled = !d.is_enabled;
|
||||||
}
|
}
|
||||||
@@ -65,40 +61,45 @@ const PluginDownloadContainer = () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 「currentPluginsData.data」でis_downloadedがtrueのものだけ残す
|
||||||
// currentPluginsData.data で、is_downloaded が true のものだけ残す
|
new_value = new_value.filter((item) =>
|
||||||
new_value = new_value.filter(item => {
|
currentPluginsData.data.some(
|
||||||
return currentPluginsData.data.some(plugin => plugin.plugin_id === item.plugin_id && plugin.is_downloaded);
|
(plugin) => plugin.plugin_id === item.plugin_id && plugin.is_downloaded
|
||||||
});
|
)
|
||||||
|
);
|
||||||
|
|
||||||
setSavedPluginsStatus(new_value);
|
setSavedPluginsStatus(new_value);
|
||||||
}
|
};
|
||||||
|
|
||||||
const variable_state = currentSavedPluginsStatus.state;
|
const variable_state = currentSavedPluginsStatus.state;
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.plugins_list_container}>
|
<div className={styles.plugins_list_container}>
|
||||||
{currentPluginsData.data.map((plugin) => (
|
{currentPluginsData.data.map((plugin) => (
|
||||||
<div key={plugin.plugin_id} className={styles.plugin_wrapper}>
|
<div key={plugin.plugin_id} className={styles.plugin_wrapper}>
|
||||||
<p className={styles.title}>{plugin.title}</p>
|
<p className={styles.title}>
|
||||||
|
{plugin.is_downloaded
|
||||||
|
? plugin.downloaded_plugin_info?.title || plugin.latest_plugin_info.title
|
||||||
|
: plugin.latest_plugin_info.title}
|
||||||
|
</p>
|
||||||
<p className={styles.plugin_id}>{plugin.plugin_id}</p>
|
<p className={styles.plugin_id}>{plugin.plugin_id}</p>
|
||||||
{plugin.error ? (
|
{plugin.error ? (
|
||||||
<p style={{ color: "red" }}>Error: {plugin.error}</p>
|
<p style={{ color: "red" }}>Error: {plugin.error}</p>
|
||||||
) : (
|
) : (
|
||||||
<div className={styles.plugin_info_wrapper}>
|
<div className={styles.plugin_info_wrapper}>
|
||||||
<div className={styles.plugin_info}>
|
<div className={styles.plugin_info}>
|
||||||
<p>Downloaded Version: {plugin.downloaded_plugin_version}</p>
|
{/* 状態に応じた情報表示(例:バージョン等) */}
|
||||||
<p>Latest Version: {plugin.latest_plugin_version}</p>
|
|
||||||
<p>
|
<p>
|
||||||
Compatible: {plugin.min_supported_vrct_version} ~ {plugin.max_supported_vrct_version}
|
{plugin.is_downloaded
|
||||||
|
? `現在のバージョン: ${plugin.downloaded_plugin_info?.plugin_version}`
|
||||||
|
: `最新バージョン: ${plugin.latest_plugin_info.plugin_version}`}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<PluginsControlComponent
|
<PluginsControlComponent
|
||||||
variable_state={variable_state}
|
variable_state={variable_state}
|
||||||
toggleFunction={toggleFunction}
|
toggleFunction={toggleFunction}
|
||||||
plugin_status={plugin}
|
|
||||||
downloadStartFunction={downloadStartFunction}
|
downloadStartFunction={downloadStartFunction}
|
||||||
|
plugin_status={plugin}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ import { useState } from "react";
|
|||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import styles from "./VersionLabel.module.scss";
|
import styles from "./VersionLabel.module.scss";
|
||||||
|
|
||||||
import { useSoftwareVersion } from "@logics_configs";
|
import { useSoftwareVersion, useComputeMode } from "@logics_common";
|
||||||
import { useComputeMode } from "@logics_common";
|
|
||||||
import CopySvg from "@images/copy.svg?react";
|
import CopySvg from "@images/copy.svg?react";
|
||||||
import CheckMarkSvg from "@images/check_mark.svg?react";
|
import CheckMarkSvg from "@images/check_mark.svg?react";
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { usePlugins } from "@logics_configs";
|
|||||||
export const MainSection = () => {
|
export const MainSection = () => {
|
||||||
const { currentPluginsData } = usePlugins();
|
const { currentPluginsData } = usePlugins();
|
||||||
|
|
||||||
const render_plugins = currentPluginsData.data.filter((plugin) => plugin.is_enabled && plugin.location === "main_section");
|
const render_plugins = currentPluginsData.data.filter((plugin) => (plugin.is_downloaded && plugin.is_enabled && plugin.downloaded_plugin_info.location === "main_section"));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import RefreshSvg from "@images/refresh.svg?react";
|
|||||||
import HelpSvg from "@images/help.svg?react";
|
import HelpSvg from "@images/help.svg?react";
|
||||||
|
|
||||||
import { useStore_OpenedQuickSetting } from "@store";
|
import { useStore_OpenedQuickSetting } from "@store";
|
||||||
import { useIsSoftwareUpdateAvailable } from "@logics_common";
|
import { useSoftwareVersion } from "@logics_common";
|
||||||
import { useIsEnabledOverlaySmallLog, useIsEnabledOverlayLargeLog, useEnableVrcMicMuteSync } from "@logics_configs";
|
import { useIsEnabledOverlaySmallLog, useIsEnabledOverlayLargeLog, useEnableVrcMicMuteSync } from "@logics_configs";
|
||||||
import { OpenQuickSettingButton } from "./_buttons/OpenQuickSettingButton";
|
import { OpenQuickSettingButton } from "./_buttons/OpenQuickSettingButton";
|
||||||
|
|
||||||
@@ -66,9 +66,9 @@ const OpenVrcMicMuteSyncQuickSetting = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const SoftwareUpdateAvailableButton = () => {
|
const SoftwareUpdateAvailableButton = () => {
|
||||||
const { currentIsSoftwareUpdateAvailable } = useIsSoftwareUpdateAvailable();
|
const { currentLatestSoftwareVersionInfo } = useSoftwareVersion();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
if (currentIsSoftwareUpdateAvailable.data === false) return null;
|
if (currentLatestSoftwareVersionInfo.data.is_update_available === false) return null;
|
||||||
|
|
||||||
const { updateOpenedQuickSetting } = useStore_OpenedQuickSetting();
|
const { updateOpenedQuickSetting } = useStore_OpenedQuickSetting();
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
import styles from "./UpdateModal.module.scss";
|
import styles from "./UpdateModal.module.scss";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useStore_OpenedQuickSetting } from "@store";
|
import { useStore_OpenedQuickSetting } from "@store";
|
||||||
import { useComputeMode, useUpdateSoftware } from "@logics_common";
|
import { usePlugins } from "@logics_configs";
|
||||||
import { useIsSoftwareUpdating, useIsSoftwareUpdateAvailable } from "@logics_common";
|
import {
|
||||||
|
useComputeMode,
|
||||||
|
useUpdateSoftware,
|
||||||
|
useIsSoftwareUpdating,
|
||||||
|
useSoftwareVersion,
|
||||||
|
} from "@logics_common";
|
||||||
|
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
|
|
||||||
export const UpdateModal = () => {
|
export const UpdateModal = () => {
|
||||||
@@ -11,9 +17,13 @@ export const UpdateModal = () => {
|
|||||||
const { updateSoftware, updateSoftware_CUDA } = useUpdateSoftware();
|
const { updateSoftware, updateSoftware_CUDA } = useUpdateSoftware();
|
||||||
const { updateIsSoftwareUpdating } = useIsSoftwareUpdating();
|
const { updateIsSoftwareUpdating } = useIsSoftwareUpdating();
|
||||||
const { currentComputeMode } = useComputeMode();
|
const { currentComputeMode } = useComputeMode();
|
||||||
const { currentIsSoftwareUpdateAvailable } = useIsSoftwareUpdateAvailable();
|
const { currentLatestSoftwareVersionInfo } = useSoftwareVersion();
|
||||||
|
const { isAnyPluginEnabled } = usePlugins();
|
||||||
|
|
||||||
const is_latest_version_already = currentIsSoftwareUpdateAvailable.data === false;
|
console.log(isAnyPluginEnabled());
|
||||||
|
|
||||||
|
|
||||||
|
const is_latest_version_already = currentLatestSoftwareVersionInfo.data.is_update_available === false;
|
||||||
const is_cpu_version = currentComputeMode.data === "cpu";
|
const is_cpu_version = currentComputeMode.data === "cpu";
|
||||||
|
|
||||||
const onClickUpdateSoftware = () => {
|
const onClickUpdateSoftware = () => {
|
||||||
@@ -37,6 +47,7 @@ export const UpdateModal = () => {
|
|||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<div className={styles.wrapper}>
|
<div className={styles.wrapper}>
|
||||||
|
{isAnyPluginEnabled() && <PluginUpdateNotification />}
|
||||||
<div className={styles.update_section}>
|
<div className={styles.update_section}>
|
||||||
<div className={styles.cpu_section}>
|
<div className={styles.cpu_section}>
|
||||||
<div className={styles.button_wrapper}>
|
<div className={styles.button_wrapper}>
|
||||||
@@ -86,3 +97,19 @@ const CurrentVersionLabel = (props) => {
|
|||||||
}
|
}
|
||||||
return <p className={clsx(styles.current_version_label, {[styles.is_cuda]: props.is_cuda})}>{t("update_modal.is_current_compute_device")}</p>;
|
return <p className={clsx(styles.current_version_label, {[styles.is_cuda]: props.is_cuda})}>{t("update_modal.is_current_compute_device")}</p>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const PluginUpdateNotification = () => {
|
||||||
|
const { enabledPluginsList } = usePlugins();
|
||||||
|
|
||||||
|
const incompatible_plugins_list = enabledPluginsList();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{incompatible_plugins_list.map(plugin => {
|
||||||
|
console.log(plugin);
|
||||||
|
|
||||||
|
return <p>{plugin.title}</p>
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
|
export { useSoftwareVersion } from "./useSoftwareVersion";
|
||||||
export { useComputeMode } from "./useComputeMode";
|
export { useComputeMode } from "./useComputeMode";
|
||||||
export { useInitProgress } from "./useInitProgress";
|
export { useInitProgress } from "./useInitProgress";
|
||||||
export { useIsBackendReady } from "./useIsBackendReady";
|
export { useIsBackendReady } from "./useIsBackendReady";
|
||||||
export { useWindow } from "./useWindow";
|
export { useWindow } from "./useWindow";
|
||||||
export { useIsOpenedConfigPage } from "./useIsOpenedConfigPage";
|
export { useIsOpenedConfigPage } from "./useIsOpenedConfigPage";
|
||||||
export { useIsSoftwareUpdateAvailable } from "./useIsSoftwareUpdateAvailable";
|
|
||||||
export { useIsSoftwareUpdating } from "./useIsSoftwareUpdating";
|
export { useIsSoftwareUpdating } from "./useIsSoftwareUpdating";
|
||||||
export { useNotificationStatus } from "./useNotificationStatus";
|
export { useNotificationStatus } from "./useNotificationStatus";
|
||||||
export { useOpenFolder } from "./useOpenFolder";
|
export { useOpenFolder } from "./useOpenFolder";
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
import { useStore_IsSoftwareUpdateAvailable } from "@store";
|
|
||||||
|
|
||||||
export const useIsSoftwareUpdateAvailable = () => {
|
|
||||||
const { currentIsSoftwareUpdateAvailable, updateIsSoftwareUpdateAvailable } = useStore_IsSoftwareUpdateAvailable();
|
|
||||||
|
|
||||||
return {
|
|
||||||
currentIsSoftwareUpdateAvailable,
|
|
||||||
updateIsSoftwareUpdateAvailable,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
40
src-ui/logics/common/useSoftwareVersion.js
Normal file
40
src-ui/logics/common/useSoftwareVersion.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import semver from "semver";
|
||||||
|
|
||||||
|
import { useStore_SoftwareVersion, useStore_LatestSoftwareVersionInfo } from "@store";
|
||||||
|
import { useStdoutToPython } from "@logics/useStdoutToPython";
|
||||||
|
|
||||||
|
export const useSoftwareVersion = () => {
|
||||||
|
const { asyncStdoutToPython } = useStdoutToPython();
|
||||||
|
const { currentLatestSoftwareVersionInfo, updateLatestSoftwareVersionInfo } = useStore_LatestSoftwareVersionInfo();
|
||||||
|
const { currentSoftwareVersion, updateSoftwareVersion, pendingSoftwareVersion } = useStore_SoftwareVersion();
|
||||||
|
|
||||||
|
const getSoftwareVersion = () => {
|
||||||
|
pendingSoftwareVersion();
|
||||||
|
asyncStdoutToPython("/get/data/version");
|
||||||
|
};
|
||||||
|
|
||||||
|
const isPluginCompatible = (main_version, lower_version, upper_version) => {
|
||||||
|
// lower_version 以上かつ upper_version 以下なら互換性ありと判定
|
||||||
|
return semver.gte(main_version, lower_version) && semver.lte(main_version, upper_version);
|
||||||
|
};
|
||||||
|
|
||||||
|
const checkVrctVerCompatibility = (min_version, max_version) => {
|
||||||
|
const current_vrct_version = currentSoftwareVersion.data;
|
||||||
|
const latest_vrct_version = currentLatestSoftwareVersionInfo.data.new_version;
|
||||||
|
|
||||||
|
const is_plugin_supported = isPluginCompatible(current_vrct_version, min_version, max_version);
|
||||||
|
const is_plugin_supported_latest_vrct = isPluginCompatible(latest_vrct_version, min_version, max_version);
|
||||||
|
return { is_plugin_supported, is_plugin_supported_latest_vrct };
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
currentSoftwareVersion,
|
||||||
|
getSoftwareVersion,
|
||||||
|
updateSoftwareVersion,
|
||||||
|
|
||||||
|
currentLatestSoftwareVersionInfo,
|
||||||
|
updateLatestSoftwareVersionInfo,
|
||||||
|
|
||||||
|
checkVrctVerCompatibility,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -62,6 +62,4 @@ export { useSupporters } from "./supporters/useSupporters";
|
|||||||
|
|
||||||
export { usePlugins } from "./plugins/usePlugins";
|
export { usePlugins } from "./plugins/usePlugins";
|
||||||
|
|
||||||
|
|
||||||
export { useSettingBoxScrollPosition } from "./useSettingBoxScrollPosition";
|
export { useSettingBoxScrollPosition } from "./useSettingBoxScrollPosition";
|
||||||
export { useSoftwareVersion } from "./useSoftwareVersion";
|
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
import semver from "semver";
|
|
||||||
|
|
||||||
import { invoke } from "@tauri-apps/api/tauri";
|
import { invoke } from "@tauri-apps/api/tauri";
|
||||||
import {
|
import {
|
||||||
createAtomWithHook,
|
createAtomWithHook,
|
||||||
useStore_SavedPluginsStatus,
|
useStore_SavedPluginsStatus,
|
||||||
useStore_PluginsData,
|
useStore_PluginsData,
|
||||||
|
useStore_IsPluginsInitialized,
|
||||||
} from "@store";
|
} from "@store";
|
||||||
import { useStdoutToPython } from "@logics/useStdoutToPython";
|
import { useStdoutToPython } from "@logics/useStdoutToPython";
|
||||||
|
|
||||||
@@ -21,8 +20,7 @@ dev_plugins.forEach(async ({entry_path}) => {
|
|||||||
|
|
||||||
import JSZip from "jszip";
|
import JSZip from "jszip";
|
||||||
|
|
||||||
import { useFetch } from "@logics_common";
|
import { useFetch, useSoftwareVersion } from "@logics_common";
|
||||||
import { useSoftwareVersion } from "@logics_configs";
|
|
||||||
|
|
||||||
import * as logics_configs from "@logics_configs";
|
import * as logics_configs from "@logics_configs";
|
||||||
import * as logics_main from "@logics_main";
|
import * as logics_main from "@logics_main";
|
||||||
@@ -36,30 +34,66 @@ export const usePlugins = () => {
|
|||||||
const { asyncStdoutToPython } = useStdoutToPython();
|
const { asyncStdoutToPython } = useStdoutToPython();
|
||||||
const { currentSavedPluginsStatus, updateSavedPluginsStatus, pendingSavedPluginsStatus } = useStore_SavedPluginsStatus();
|
const { currentSavedPluginsStatus, updateSavedPluginsStatus, pendingSavedPluginsStatus } = useStore_SavedPluginsStatus();
|
||||||
const { currentPluginsData, updatePluginsData, pendingPluginsData } = useStore_PluginsData();
|
const { currentPluginsData, updatePluginsData, pendingPluginsData } = useStore_PluginsData();
|
||||||
const { currentSoftwareVersion } = useSoftwareVersion();
|
const { currentIsPluginsInitialized, updateIsPluginsInitialized, pendingIsPluginsInitialized } = useStore_IsPluginsInitialized();
|
||||||
|
const { checkVrctVerCompatibility } = useSoftwareVersion();
|
||||||
|
|
||||||
const { asyncTauriFetchGithub } = useFetch();
|
const { asyncTauriFetchGithub } = useFetch();
|
||||||
|
|
||||||
const generatePluginContext= (plugin_info) => {
|
const generatePluginContext= (downloaded_plugin_info) => {
|
||||||
const plugin_context = {
|
const plugin_context = {
|
||||||
registerComponent: (component) => {
|
registerComponent: (component) => {
|
||||||
if (!plugin_info.plugin_id || !plugin_info.location || !component) {
|
if (!downloaded_plugin_info.plugin_id || !downloaded_plugin_info.location || !component) {
|
||||||
return console.error("An invalid plugin was detected.", plugin_info.plugin_id, plugin_info.location, component);
|
return console.error("An invalid plugin was detected.", downloaded_plugin_info.plugin_id, downloaded_plugin_info.location, component);
|
||||||
}
|
}
|
||||||
updatePluginsData(prev => {
|
updatePluginsData(prev => {
|
||||||
const new_value = prev.data.map(old_value =>
|
const prev_map = new Map(prev.data.map(item => [item.plugin_id, item]));
|
||||||
old_value.plugin_id === plugin_info.plugin_id
|
const new_data = [];
|
||||||
? {
|
let new_value = {};
|
||||||
...old_value,
|
|
||||||
...plugin_info,
|
if (!prev_map.has(downloaded_plugin_info.plugin_id)) { // 未ダウンロード 新規登録
|
||||||
downloaded_plugin_version: plugin_info.plugin_version,
|
new_value = {
|
||||||
|
plugin_id: downloaded_plugin_info.plugin_id,
|
||||||
component: component,
|
component: component,
|
||||||
is_downloaded: true,
|
is_downloaded: true,
|
||||||
is_latest_version_available: false,
|
is_latest_version_available: false,
|
||||||
} : old_value
|
downloaded_plugin_info: {
|
||||||
);
|
...downloaded_plugin_info,
|
||||||
|
component: component,
|
||||||
|
is_plugin_supported: is_plugin_supported,
|
||||||
|
is_plugin_supported_latest_vrct: is_plugin_supported_latest_vrct,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return [...prev.data, new_value];
|
||||||
|
}
|
||||||
|
|
||||||
return new_value;
|
for (const old_plugin_data of prev.data) {
|
||||||
|
const { is_plugin_supported, is_plugin_supported_latest_vrct } = checkVrctVerCompatibility(downloaded_plugin_info.min_supported_vrct_version, downloaded_plugin_info.max_supported_vrct_version);
|
||||||
|
|
||||||
|
if (prev_map.has(downloaded_plugin_info.plugin_id) && old_plugin_data.plugin_id === downloaded_plugin_info.plugin_id) { // ダウンロード済み
|
||||||
|
|
||||||
|
|
||||||
|
const target_prev_plugin = prev_map.get(downloaded_plugin_info.plugin_id);
|
||||||
|
const is_latest_version_available = (target_prev_plugin.is_downloaded) && !(downloaded_plugin_info.plugin_version === target_prev_plugin.latest_plugin_info.plugin_version);
|
||||||
|
|
||||||
|
new_value = {
|
||||||
|
...target_prev_plugin,
|
||||||
|
plugin_id: downloaded_plugin_info.plugin_id,
|
||||||
|
component: component,
|
||||||
|
is_downloaded: true,
|
||||||
|
is_latest_version_available: is_latest_version_available,
|
||||||
|
downloaded_plugin_info: {
|
||||||
|
...downloaded_plugin_info,
|
||||||
|
component: component,
|
||||||
|
is_plugin_supported: is_plugin_supported,
|
||||||
|
is_plugin_supported_latest_vrct: is_plugin_supported_latest_vrct,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
new_value = old_plugin_data;
|
||||||
|
}
|
||||||
|
new_data.push(new_value);
|
||||||
|
}
|
||||||
|
return new_data;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
createAtomWithHook: (...args) => createAtomWithHook(...args),
|
createAtomWithHook: (...args) => createAtomWithHook(...args),
|
||||||
@@ -70,11 +104,11 @@ export const usePlugins = () => {
|
|||||||
|
|
||||||
const asyncLoadPlugin = async (plugin_folder_relative_path) => {
|
const asyncLoadPlugin = async (plugin_folder_relative_path) => {
|
||||||
const init_path = "plugins/" + plugin_folder_relative_path + "/index.esm.js";
|
const init_path = "plugins/" + plugin_folder_relative_path + "/index.esm.js";
|
||||||
const plugin_info_path = "plugins/" + plugin_folder_relative_path + "/plugin_info.json";
|
const downloaded_plugin_info_path = "plugins/" + plugin_folder_relative_path + "/plugin_info.json";
|
||||||
const plugin_css_path = "plugins/" + plugin_folder_relative_path + "/main.css";
|
const plugin_css_path = "plugins/" + plugin_folder_relative_path + "/main.css";
|
||||||
try {
|
try {
|
||||||
const plugin_info_json = await readTextFile(plugin_info_path, { dir: BaseDirectory.Resource, recursive: true });
|
const downloaded_plugin_info_json = await readTextFile(downloaded_plugin_info_path, { dir: BaseDirectory.Resource, recursive: true });
|
||||||
const plugin_info = JSON.parse(plugin_info_json);
|
const downloaded_plugin_info = JSON.parse(downloaded_plugin_info_json);
|
||||||
|
|
||||||
const plugin_code = await readTextFile(init_path, { dir: BaseDirectory.Resource, recursive: true });
|
const plugin_code = await readTextFile(init_path, { dir: BaseDirectory.Resource, recursive: true });
|
||||||
const cleaned_code = removeImportStatements(plugin_code);
|
const cleaned_code = removeImportStatements(plugin_code);
|
||||||
@@ -91,7 +125,7 @@ export const usePlugins = () => {
|
|||||||
URL.revokeObjectURL(blob_url);
|
URL.revokeObjectURL(blob_url);
|
||||||
|
|
||||||
if (plugin_module && plugin_module.init) {
|
if (plugin_module && plugin_module.init) {
|
||||||
plugin_module.init(generatePluginContext(plugin_info));
|
plugin_module.init(generatePluginContext(downloaded_plugin_info));
|
||||||
}
|
}
|
||||||
await loadPluginCSS(plugin_css_path);
|
await loadPluginCSS(plugin_css_path);
|
||||||
|
|
||||||
@@ -102,16 +136,16 @@ export const usePlugins = () => {
|
|||||||
|
|
||||||
const asyncLoadAllPlugins = async () => {
|
const asyncLoadAllPlugins = async () => {
|
||||||
if (!import.meta.env.DEV) {
|
if (!import.meta.env.DEV) {
|
||||||
imported_dev_plugins.forEach(({ index, plugin_info }) => {
|
imported_dev_plugins.forEach(({ index, downloaded_plugin_info }) => {
|
||||||
if (!index || !plugin_info) {
|
if (!index || !downloaded_plugin_info) {
|
||||||
console.error("Invalid development plugin detected", index, plugin_info);
|
console.error("Invalid development plugin detected", index, downloaded_plugin_info);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const plugin_context = generatePluginContext(plugin_info);
|
const plugin_context = generatePluginContext(downloaded_plugin_info);
|
||||||
if (index.init) {
|
if (index.init) {
|
||||||
index.init(plugin_context);
|
index.init(plugin_context);
|
||||||
} else {
|
} else {
|
||||||
console.error("Plugin missing init function", plugin_info);
|
console.error("Plugin missing init function", downloaded_plugin_info);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -128,8 +162,9 @@ export const usePlugins = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const downloadAndExtractPlugin = async (plugin) => {
|
const downloadAndExtractPlugin = async (plugin) => {
|
||||||
|
const latest_plugin_info = plugin.latest_plugin_info;
|
||||||
try {
|
try {
|
||||||
const plugin_zip_url = await fetchLatestPluginZipUrl(plugin);
|
const plugin_zip_url = await fetchLatestPluginZipUrl(latest_plugin_info);
|
||||||
// Rust コマンド経由で ZIP をダウンロード
|
// Rust コマンド経由で ZIP をダウンロード
|
||||||
const base64_zip = await invoke("download_zip_asset", { url: plugin_zip_url });
|
const base64_zip = await invoke("download_zip_asset", { url: plugin_zip_url });
|
||||||
// base64_zip をデコードして Uint8Array に変換
|
// base64_zip をデコードして Uint8Array に変換
|
||||||
@@ -144,7 +179,7 @@ export const usePlugins = () => {
|
|||||||
const zip = await JSZip.loadAsync(bytes);
|
const zip = await JSZip.loadAsync(bytes);
|
||||||
|
|
||||||
// 展開先ディレクトリのパス(例:"plugins/<plugin_id>" とする)
|
// 展開先ディレクトリのパス(例:"plugins/<plugin_id>" とする)
|
||||||
const target_plugin_path = "plugins/" + plugin.plugin_id;
|
const target_plugin_path = "plugins/" + latest_plugin_info.plugin_id;
|
||||||
// 既に存在する場合は削除してから新規作成
|
// 既に存在する場合は削除してから新規作成
|
||||||
if (await exists(target_plugin_path, { dir: BaseDirectory.Resource, recursive: true })) {
|
if (await exists(target_plugin_path, { dir: BaseDirectory.Resource, recursive: true })) {
|
||||||
await removeDir(target_plugin_path, { dir: BaseDirectory.Resource, recursive: true });
|
await removeDir(target_plugin_path, { dir: BaseDirectory.Resource, recursive: true });
|
||||||
@@ -220,13 +255,13 @@ export const usePlugins = () => {
|
|||||||
plugins_data.map(async (plugin_data) => {
|
plugins_data.map(async (plugin_data) => {
|
||||||
try {
|
try {
|
||||||
const plugin_info = await asyncFetchPluginInfo(plugin_data.url);
|
const plugin_info = await asyncFetchPluginInfo(plugin_data.url);
|
||||||
return { ...plugin_info };
|
return plugin_info;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching plugin info for URL:", plugin_data.url, error);
|
console.error("Error fetching plugin info for URL:", plugin_data.url, error);
|
||||||
// エラー発生時は、plugin_data.title とエラーメッセージを返す
|
|
||||||
return {
|
return {
|
||||||
title: plugin_data.title,
|
title: plugin_data.title,
|
||||||
plugin_id: plugin_data.plugin_id || plugin_data.title,
|
plugin_id: plugin_data.plugin_id || plugin_data.title,
|
||||||
|
is_error: true,
|
||||||
error: error.message,
|
error: error.message,
|
||||||
url: plugin_data.url
|
url: plugin_data.url
|
||||||
};
|
};
|
||||||
@@ -254,14 +289,8 @@ export const usePlugins = () => {
|
|||||||
}
|
}
|
||||||
const plugin_info = plugin_info_json_response.data;
|
const plugin_info = plugin_info_json_response.data;
|
||||||
|
|
||||||
const isPluginCompatible = (main_version, lower_version, upper_version) => {
|
|
||||||
console.log(main_version, lower_version, upper_version);
|
|
||||||
|
|
||||||
// lower_version 以上かつ upper_version 以下なら互換性ありと判定
|
const { is_plugin_supported, is_plugin_supported_latest_vrct } = checkVrctVerCompatibility(plugin_info.min_supported_vrct_version, plugin_info.max_supported_vrct_version);
|
||||||
return semver.gte(main_version, lower_version) && semver.lte(main_version, upper_version);
|
|
||||||
};
|
|
||||||
|
|
||||||
const is_plugin_supported = isPluginCompatible(currentSoftwareVersion.data, plugin_info.min_supported_vrct_version, plugin_info.max_supported_vrct_version);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: plugin_info.title,
|
title: plugin_info.title,
|
||||||
@@ -270,21 +299,47 @@ export const usePlugins = () => {
|
|||||||
min_supported_vrct_version: plugin_info.min_supported_vrct_version,
|
min_supported_vrct_version: plugin_info.min_supported_vrct_version,
|
||||||
max_supported_vrct_version: plugin_info.max_supported_vrct_version,
|
max_supported_vrct_version: plugin_info.max_supported_vrct_version,
|
||||||
is_plugin_supported: is_plugin_supported,
|
is_plugin_supported: is_plugin_supported,
|
||||||
|
is_plugin_supported_latest_vrct: is_plugin_supported_latest_vrct,
|
||||||
asset_name: plugin_info.asset_name,
|
asset_name: plugin_info.asset_name,
|
||||||
url: plugin_info_asset_url
|
url: plugin_info_asset_url
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handlePendingPlugin = (target_plugin_id, is_pending) => {
|
||||||
|
updatePluginsData((old_value) => {
|
||||||
|
const new_value = old_value.data.map((d) => {
|
||||||
|
if (d.plugin_id === target_plugin_id) {
|
||||||
|
d.is_pending = is_pending;
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
});
|
||||||
|
return new_value;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const setSavedPluginsStatus = (plugins_status) => {
|
const setSavedPluginsStatus = (plugins_status) => {
|
||||||
pendingSavedPluginsStatus();
|
pendingSavedPluginsStatus();
|
||||||
asyncStdoutToPython("/set/data/plugins_status", plugins_status);
|
asyncStdoutToPython("/set/data/plugins_status", plugins_status);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isAnyPluginEnabled = () => {
|
||||||
|
return currentPluginsData.data.some(plugin => plugin.is_enabled);
|
||||||
|
};
|
||||||
|
|
||||||
|
const enabledPluginsList = () => {
|
||||||
|
return currentPluginsData.data.filter(plugin => plugin.is_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
asyncFetchPluginsInfo,
|
asyncFetchPluginsInfo,
|
||||||
|
|
||||||
|
isAnyPluginEnabled,
|
||||||
|
enabledPluginsList,
|
||||||
|
|
||||||
asyncLoadAllPlugins,
|
asyncLoadAllPlugins,
|
||||||
downloadAndExtractPlugin,
|
downloadAndExtractPlugin,
|
||||||
|
|
||||||
@@ -294,7 +349,12 @@ export const usePlugins = () => {
|
|||||||
currentPluginsData,
|
currentPluginsData,
|
||||||
updatePluginsData,
|
updatePluginsData,
|
||||||
|
|
||||||
|
currentIsPluginsInitialized,
|
||||||
|
updateIsPluginsInitialized,
|
||||||
|
|
||||||
setSavedPluginsStatus,
|
setSavedPluginsStatus,
|
||||||
|
|
||||||
|
handlePendingPlugin,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
import { useStore_SoftwareVersion } from "@store";
|
|
||||||
import { useStdoutToPython } from "@logics/useStdoutToPython";
|
|
||||||
|
|
||||||
export const useSoftwareVersion = () => {
|
|
||||||
const { asyncStdoutToPython } = useStdoutToPython();
|
|
||||||
const { currentSoftwareVersion, updateSoftwareVersion, pendingSoftwareVersion } = useStore_SoftwareVersion();
|
|
||||||
|
|
||||||
const getSoftwareVersion = () => {
|
|
||||||
pendingSoftwareVersion();
|
|
||||||
asyncStdoutToPython("/get/data/version");
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
currentSoftwareVersion,
|
|
||||||
getSoftwareVersion,
|
|
||||||
updateSoftwareVersion,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -8,13 +8,13 @@ import {
|
|||||||
useNotificationStatus,
|
useNotificationStatus,
|
||||||
useHandleNetworkConnection,
|
useHandleNetworkConnection,
|
||||||
|
|
||||||
|
useSoftwareVersion,
|
||||||
useComputeMode,
|
useComputeMode,
|
||||||
useInitProgress,
|
useInitProgress,
|
||||||
useIsBackendReady,
|
useIsBackendReady,
|
||||||
useWindow,
|
useWindow,
|
||||||
useMessage,
|
useMessage,
|
||||||
useVolume,
|
useVolume,
|
||||||
useIsSoftwareUpdateAvailable,
|
|
||||||
} from "@logics_common";
|
} from "@logics_common";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -26,7 +26,6 @@ import {
|
|||||||
} from "@logics_main";
|
} from "@logics_main";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
useSoftwareVersion,
|
|
||||||
useEnableAutoMicSelect,
|
useEnableAutoMicSelect,
|
||||||
useEnableAutoSpeakerSelect,
|
useEnableAutoSpeakerSelect,
|
||||||
useMicHostList,
|
useMicHostList,
|
||||||
@@ -105,7 +104,7 @@ export const useReceiveRoutes = () => {
|
|||||||
addSentMessageLog,
|
addSentMessageLog,
|
||||||
addReceivedMessageLog,
|
addReceivedMessageLog,
|
||||||
} = useMessage();
|
} = useMessage();
|
||||||
const { updateIsSoftwareUpdateAvailable } = useIsSoftwareUpdateAvailable();
|
const { updateLatestSoftwareVersionInfo } = useSoftwareVersion();
|
||||||
const { updateSoftwareVersion } = useSoftwareVersion();
|
const { updateSoftwareVersion } = useSoftwareVersion();
|
||||||
const { updateEnableAutoMicSelect } = useEnableAutoMicSelect();
|
const { updateEnableAutoMicSelect } = useEnableAutoMicSelect();
|
||||||
const { updateEnableAutoSpeakerSelect } = useEnableAutoSpeakerSelect();
|
const { updateEnableAutoSpeakerSelect } = useEnableAutoSpeakerSelect();
|
||||||
@@ -207,7 +206,7 @@ export const useReceiveRoutes = () => {
|
|||||||
"/set/data/main_window_geometry": () => {},
|
"/set/data/main_window_geometry": () => {},
|
||||||
"/run/open_filepath_logs": () => console.log("Opened Directory, Message Logs"),
|
"/run/open_filepath_logs": () => console.log("Opened Directory, Message Logs"),
|
||||||
"/run/open_filepath_config_file": () => console.log("Opened Directory, Config File"),
|
"/run/open_filepath_config_file": () => console.log("Opened Directory, Config File"),
|
||||||
"/run/update_software_flag": updateIsSoftwareUpdateAvailable,
|
"/run/software_update_info": updateLatestSoftwareVersionInfo,
|
||||||
"/run/connected_network": handleNetworkConnection,
|
"/run/connected_network": handleNetworkConnection,
|
||||||
|
|
||||||
// Main Page
|
// Main Page
|
||||||
|
|||||||
@@ -114,7 +114,10 @@ export const { atomInstance: Atom_MainFunctionsStateMemory, useHook: useStore_Ma
|
|||||||
transcription_receive: false,
|
transcription_receive: false,
|
||||||
}, "MainFunctionsStateMemory");
|
}, "MainFunctionsStateMemory");
|
||||||
export const { atomInstance: Atom_OpenedQuickSetting, useHook: useStore_OpenedQuickSetting } = createAtomWithHook("", "OpenedQuickSetting");
|
export const { atomInstance: Atom_OpenedQuickSetting, useHook: useStore_OpenedQuickSetting } = createAtomWithHook("", "OpenedQuickSetting");
|
||||||
export const { atomInstance: Atom_IsSoftwareUpdateAvailable, useHook: useStore_IsSoftwareUpdateAvailable } = createAtomWithHook(false, "IsSoftwareUpdateAvailable");
|
export const { atomInstance: Atom_LatestSoftwareVersionInfo, useHook: useStore_LatestSoftwareVersionInfo } = createAtomWithHook({
|
||||||
|
is_update_available: false,
|
||||||
|
new_version: "",
|
||||||
|
}, "LatestSoftwareVersionInfo");
|
||||||
export const { atomInstance: Atom_InitProgress, useHook: useStore_InitProgress } = createAtomWithHook(0, "InitProgress");
|
export const { atomInstance: Atom_InitProgress, useHook: useStore_InitProgress } = createAtomWithHook(0, "InitProgress");
|
||||||
export const { atomInstance: Atom_IsBreakPoint, useHook: useStore_IsBreakPoint } = createAtomWithHook(false, "IsBreakPoint");
|
export const { atomInstance: Atom_IsBreakPoint, useHook: useStore_IsBreakPoint } = createAtomWithHook(false, "IsBreakPoint");
|
||||||
export const { atomInstance: Atom_IsSoftwareUpdating, useHook: useStore_IsSoftwareUpdating } = createAtomWithHook(false, "IsSoftwareUpdating");
|
export const { atomInstance: Atom_IsSoftwareUpdating, useHook: useStore_IsSoftwareUpdating } = createAtomWithHook(false, "IsSoftwareUpdating");
|
||||||
@@ -275,7 +278,7 @@ export const { atomInstance: Atom_Hotkeys, useHook: useStore_Hotkeys } = createA
|
|||||||
}, "Hotkeys");
|
}, "Hotkeys");
|
||||||
|
|
||||||
// Plugins
|
// Plugins
|
||||||
// export const { atomInstance: Atom_LoadedPluginsList, useHook: useStore_LoadedPluginsList } = createAtomWithHook([], "LoadedPluginsList");
|
export const { atomInstance: Atom_IsPluginsInitialized, useHook: useStore_IsPluginsInitialized } = createAtomWithHook(false, "IsPluginsInitialized");
|
||||||
export const { atomInstance: Atom_SavedPluginsStatus, useHook: useStore_SavedPluginsStatus } = createAtomWithHook([], "SavedPluginsStatus");
|
export const { atomInstance: Atom_SavedPluginsStatus, useHook: useStore_SavedPluginsStatus } = createAtomWithHook([], "SavedPluginsStatus");
|
||||||
export const { atomInstance: Atom_PluginsData, useHook: useStore_PluginsData } = createAtomWithHook([], "PluginsData");
|
export const { atomInstance: Atom_PluginsData, useHook: useStore_PluginsData } = createAtomWithHook([], "PluginsData");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user