diff --git a/src-ui/app/App.jsx b/src-ui/app/App.jsx index 8c33ed37..f8314681 100644 --- a/src-ui/app/App.jsx +++ b/src-ui/app/App.jsx @@ -29,7 +29,10 @@ export const App = () => { const { currentIsBackendReady } = useIsBackendReady(); const { WindowGeometryController } = useWindow(); const { i18n } = useTranslation(); - const fetchPluginsHasRunRef = useRef(false); + const fetchPluginsHasRunRef = useRef({ + is_initialized_load_plugin: false, + is_fetched_plugins_info: false, + }); return (
diff --git a/src-ui/app/_app_controllers/PluginsController.jsx b/src-ui/app/_app_controllers/PluginsController.jsx index 98327baf..9939bfe3 100644 --- a/src-ui/app/_app_controllers/PluginsController.jsx +++ b/src-ui/app/_app_controllers/PluginsController.jsx @@ -1,142 +1,15 @@ -import React, { useEffect, useRef } from "react"; -import { usePlugins } from "@logics_configs"; -import clsx from "clsx"; +import React, { useEffect } from "react"; +import { LoadPluginsController } from "./plugins_controllers/LoadPluginsController"; +import { FetchLatestPluginsDataController } from "./plugins_controllers/FetchLatestPluginsDataController"; +import { MergeSavedPluginsStatusController } from "./plugins_controllers/MergeSavedPluginsStatusController"; -if (typeof window !== "undefined") { - window.React = React; - window.clsx = clsx; -} +export const PluginsController = () => { -export const PluginsController = ({ fetchPluginsHasRunRef }) => { - const { - asyncLoadAllPlugins, - asyncFetchPluginsInfo, - currentPluginsData, - updatePluginsData, - currentSavedPluginsStatus, - updateIsPluginsInitialized, - downloadAndExtractPlugin, - } = usePlugins(); - - useEffect(() => { - const loadPlugins = async () => { - try { - await asyncLoadAllPlugins(); - const info_array = await asyncFetchPluginsInfo(); - updatePluginsData(prev => { - // Map を利用してそれぞれの配列を plugin_id で参照できるようにする - 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 new_data = []; - for (const info of info_array) { - let new_plugin_info = {}; - if (prev_map.has(info.plugin_id)) { // plugin_id 登録済み - const target_downloaded_plugin = prev_map.get(info.plugin_id); - if (target_downloaded_plugin.is_downloaded) { // 既にダウンロード済み - const is_latest_version_available = !(target_downloaded_plugin.plugin_version === info.plugin_version); - - new_plugin_info = { - ...target_downloaded_plugin, - is_downloaded: true, - latest_plugin_info: { ...info }, - is_latest_version_available: is_latest_version_available, - is_latest_version_already: (target_downloaded_plugin.downloaded_plugin_info?.plugin_version === info.plugin_version), - }; - } else { // infoにもあり登録済みだがダウンロードされていない - new_plugin_info = { - ...target_downloaded_plugin, - is_downloaded: false, - is_latest_version_already: false, - is_latest_version_available: info.is_latest_version_available, - latest_plugin_info: { ...info }, - } - } - } else { // 未ダウンロード - new_plugin_info = { - plugin_id: info.plugin_id, - is_downloaded: false, - is_latest_version_already: false, - latest_plugin_info: { ...info }, - }; - } - new_data.push(new_plugin_info); - } - - // prev.data にのみ存在するアイテム = latest plugin infoには存在しない - // を追加し、is_outdated: true を付与 - prev.data.forEach(item => { - if (!info_map.has(item.plugin_id)) { - new_data.push({ ...item, is_outdated: true }); - } - }); - - new_data.forEach(plugin => { - if (!plugin.is_outdated) { - plugin.is_latest_version_available = (plugin.latest_plugin_info.is_plugin_supported); - } - }); - - // ダウンロード済みで最新版じゃない場合、自動的にアップデート - // is_latest_version_supported: true のみ。 - // 失敗した場合、現在のバージョンが非対応の場合はdisabledにする。 - new_data.forEach(async plugin => { - if (plugin.is_enabled) { - if (!plugin.is_latest_version_already && plugin.is_latest_version_available) { - await downloadAndExtractPlugin(plugin); - } - } - }); - - new_data.forEach(async plugin => { - if (plugin.is_enabled) { - if (!plugin.downloaded_plugin_info?.is_plugin_supported) { - plugin.is_enabled = false - } - } - }); - - return new_data; - }); - - } catch (error) { - console.error(error); - } - }; - - if (!fetchPluginsHasRunRef.current) { - loadPlugins(); - updateIsPluginsInitialized(true); - } - return () => fetchPluginsHasRunRef.current = true; - }, []); - - - useEffect(() => { - updatePluginsData(prev => { - // currentSavedPluginsStatus.data の各要素を Map 化して plugin_id で参照 - 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])); - // prev.data にある各アイテムについて、保存済みの状態情報があればマージ - const merged = prev.data.map(item => { - - if (saved_map.has(item.plugin_id)) { - return { ...item, is_enabled: saved_map.get(item.plugin_id).is_enabled }; - } - return item; - }); - - // currentSavedPluginsStatus.data にのみ存在する項目があれば追加 - currentSavedPluginsStatus.data.forEach(saved => { - if (!prev_map.has(saved.plugin_id)) { - merged.push({ plugin_id: saved.plugin_id, is_enabled: saved.is_enabled }); - } - }); - return merged; - }); - }, [currentSavedPluginsStatus]); - - - - return null; + return ( + <> + + + + + ); }; \ No newline at end of file diff --git a/src-ui/app/_app_controllers/plugins_controllers/FetchLatestPluginsDataController.jsx b/src-ui/app/_app_controllers/plugins_controllers/FetchLatestPluginsDataController.jsx new file mode 100644 index 00000000..e0fde914 --- /dev/null +++ b/src-ui/app/_app_controllers/plugins_controllers/FetchLatestPluginsDataController.jsx @@ -0,0 +1,115 @@ +import { useEffect } from "react"; +import { usePlugins } from "@logics_configs"; + +export const FetchLatestPluginsDataController = () => { + const { + asyncFetchPluginsInfo, + updatePluginsData, + downloadAndExtractPlugin, + currentIsInitializedLoadPlugin, + currentIsFetchedPluginsInfo, + updateIsFetchedPluginsInfo, + } = usePlugins(); + + const asyncUpdateLatestPluginsData = async () => { + try { + const info_array = await asyncFetchPluginsInfo(); + updatePluginsData(prev => { + // Map を利用してそれぞれの配列を plugin_id で参照できるようにする + 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])); + + console.log(prev_map); + + const new_data = []; + for (const info of info_array) { + let new_plugin_info = {}; + if (prev_map.has(info.plugin_id)) { // plugin_id 登録済み + const target_downloaded_plugin = prev_map.get(info.plugin_id); + + if (target_downloaded_plugin.is_downloaded) { // 既にダウンロード済み + const is_latest_version_available = !(target_downloaded_plugin.plugin_version === info.plugin_version); + + new_plugin_info = { + ...target_downloaded_plugin, + is_downloaded: true, + latest_plugin_info: { ...info }, + is_latest_version_available: is_latest_version_available, + is_latest_version_already: (target_downloaded_plugin.downloaded_plugin_info?.plugin_version === info.plugin_version), + }; + } else { // infoにもあり登録済みだがダウンロードされていない + new_plugin_info = { + ...target_downloaded_plugin, + is_downloaded: false, + is_latest_version_already: false, + is_latest_version_available: info.is_latest_version_available, + latest_plugin_info: { ...info }, + } + } + } else { // 未ダウンロード + new_plugin_info = { + plugin_id: info.plugin_id, + is_downloaded: false, + is_latest_version_already: false, + latest_plugin_info: { ...info }, + }; + } + + new_data.push(new_plugin_info); + } + + // prev.data にのみ存在するアイテム = latest plugin infoには存在しない + // を追加し、is_outdated: true を付与 + prev.data.forEach(item => { + if (!info_map.has(item.plugin_id)) { + new_data.push({ ...item, is_outdated: true }); + } + }); + + new_data.forEach(plugin => { + if (!plugin.is_outdated) { + plugin.is_latest_version_available = (plugin.latest_plugin_info.is_plugin_supported); + } + }); + + // ダウンロード済みで最新版じゃない場合、自動的にアップデート + // is_latest_version_supported: true のみ。 + // 失敗した場合、現在のバージョンが非対応の場合はdisabledにする。 + new_data.forEach(async plugin => { + if (plugin.is_enabled) { + console.log(plugin); + + if (!plugin.is_latest_version_already && plugin.is_latest_version_available) { + await downloadAndExtractPlugin(plugin); + } + } + }); + + new_data.forEach(async plugin => { + if (plugin.is_downloaded && plugin.is_enabled) { + if (!plugin.downloaded_plugin_info?.is_plugin_supported && !plugin.latest_plugin_info?.is_plugin_supported) { + plugin.is_enabled = false + } + } + }); + + return new_data; + }); + + } catch (error) { + console.error(error); + } + }; + + useEffect(() => { + console.log(currentIsInitializedLoadPlugin.data); + if (currentIsInitializedLoadPlugin.data && !currentIsFetchedPluginsInfo.data) { + asyncUpdateLatestPluginsData().then(() => { + updateIsFetchedPluginsInfo(true); + }); + } + + }, [currentIsInitializedLoadPlugin.data]); + + return null; +}; \ No newline at end of file diff --git a/src-ui/app/_app_controllers/plugins_controllers/LoadPluginsController.jsx b/src-ui/app/_app_controllers/plugins_controllers/LoadPluginsController.jsx new file mode 100644 index 00000000..23422cc5 --- /dev/null +++ b/src-ui/app/_app_controllers/plugins_controllers/LoadPluginsController.jsx @@ -0,0 +1,36 @@ +import React, { useEffect } from "react"; +import { usePlugins } from "@logics_configs"; +import clsx from "clsx"; + +if (typeof window !== "undefined") { + window.React = React; + window.clsx = clsx; +} + +export const LoadPluginsController = () => { + + const { + asyncLoadAllPlugins, + currentIsInitializedLoadPlugin, + updateIsInitializedLoadPlugin, + } = usePlugins(); + + const asyncInitLoadPlugins = async () => { + try { + await asyncLoadAllPlugins(); + } catch (error) { + console.error(error); + } + }; + + useEffect(() => { + + if (!currentIsInitializedLoadPlugin.data) { + asyncInitLoadPlugins().then(() => { + updateIsInitializedLoadPlugin(true); + }); + } + }, []); + + return null; +}; \ No newline at end of file diff --git a/src-ui/app/_app_controllers/plugins_controllers/MergeSavedPluginsStatusController.jsx b/src-ui/app/_app_controllers/plugins_controllers/MergeSavedPluginsStatusController.jsx new file mode 100644 index 00000000..9b3dcb23 --- /dev/null +++ b/src-ui/app/_app_controllers/plugins_controllers/MergeSavedPluginsStatusController.jsx @@ -0,0 +1,35 @@ +import { useEffect } from "react"; +import { usePlugins } from "@logics_configs"; + +export const MergeSavedPluginsStatusController = () => { + const { + updatePluginsData, + currentSavedPluginsStatus, + } = usePlugins(); + + useEffect(() => { + updatePluginsData(prev => { + // currentSavedPluginsStatus.data の各要素を Map 化して plugin_id で参照 + 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])); + // prev.data にある各アイテムについて、保存済みの状態情報があればマージ + const merged = prev.data.map(item => { + + if (saved_map.has(item.plugin_id)) { + return { ...item, is_enabled: saved_map.get(item.plugin_id).is_enabled }; + } + return item; + }); + + // currentSavedPluginsStatus.data にのみ存在する項目があれば追加 + currentSavedPluginsStatus.data.forEach(saved => { + if (!prev_map.has(saved.plugin_id)) { + merged.push({ plugin_id: saved.plugin_id, is_enabled: saved.is_enabled }); + } + }); + return merged; + }); + }, [currentSavedPluginsStatus]); + + return null; +}; \ No newline at end of file diff --git a/src-ui/app/config_page/setting_section/setting_box/_components/plugins_control_component/PluginsControlComponent.jsx b/src-ui/app/config_page/setting_section/setting_box/_components/plugins_control_component/PluginsControlComponent.jsx index e6ddd500..9c33c90d 100644 --- a/src-ui/app/config_page/setting_section/setting_box/_components/plugins_control_component/PluginsControlComponent.jsx +++ b/src-ui/app/config_page/setting_section/setting_box/_components/plugins_control_component/PluginsControlComponent.jsx @@ -54,11 +54,27 @@ const DownloadedPluginControl = ({ if (!plugin_status.downloaded_plugin_info.is_plugin_supported) { + if (plugin_status.is_latest_version_available) { + return ( +
+

最新のバージョン: {latest_version}

+

最新版にアップデート後 利用可能

+ <_DownloadButton option={option} downloadStartFunction={downloadStartFunction} /> +
+ ); + } return (

現在利用不可 使用中VRCTバージョンとの互換性なし

); + } else if (plugin_status.is_outdated) { + return ( +
+

最新情報が取得できません

+ +
+ ); } else if (plugin_status.is_latest_version_already) { return (
diff --git a/src-ui/app/modal_controller/update_modal/UpdateModal.jsx b/src-ui/app/modal_controller/update_modal/UpdateModal.jsx index 4fef1c71..caf89d43 100644 --- a/src-ui/app/modal_controller/update_modal/UpdateModal.jsx +++ b/src-ui/app/modal_controller/update_modal/UpdateModal.jsx @@ -20,9 +20,6 @@ export const UpdateModal = () => { const { currentLatestSoftwareVersionInfo } = useSoftwareVersion(); const { isAnyPluginEnabled } = usePlugins(); - console.log(isAnyPluginEnabled()); - - const is_latest_version_already = currentLatestSoftwareVersionInfo.data.is_update_available === false; const is_cpu_version = currentComputeMode.data === "cpu"; @@ -101,14 +98,17 @@ const CurrentVersionLabel = (props) => { const PluginUpdateNotification = () => { const { enabledPluginsList } = usePlugins(); - const incompatible_plugins_list = enabledPluginsList(); + // ダウンロード済みのもの or プラグイン最新版が、VRCT最新版(VRCTアプデ後)に非対応のもの + const incompatible_plugins_list = enabledPluginsList().filter(plugin => { + if (!plugin.is_downloaded) return false; + if (!plugin.downloaded_plugin_info?.is_plugin_supported_latest_vrct || !plugin.latest_plugin_info.is_plugin_supported_latest_vrct) return true; + }); return (
{incompatible_plugins_list.map(plugin => { - console.log(plugin); - - return

{plugin.title}

+ const target_data = plugin.downloaded_plugin_info; + return

{target_data.title}

})}
); diff --git a/src-ui/logics/configs/plugins/usePlugins.js b/src-ui/logics/configs/plugins/usePlugins.js index 9f1be315..aa8c5ad7 100644 --- a/src-ui/logics/configs/plugins/usePlugins.js +++ b/src-ui/logics/configs/plugins/usePlugins.js @@ -5,6 +5,8 @@ import { useStore_SavedPluginsStatus, useStore_PluginsData, useStore_IsPluginsInitialized, + useStore_IsInitializedLoadPlugin, + useStore_IsFetchedPluginsInfo, } from "@store"; import { useStdoutToPython } from "@logics/useStdoutToPython"; @@ -33,6 +35,11 @@ const PLUGIN_LIST_URL = getPluginsList(); export const usePlugins = () => { const { asyncStdoutToPython } = useStdoutToPython(); + + const { currentIsInitializedLoadPlugin, updateIsInitializedLoadPlugin, pendingIsInitializedLoadPlugin } = useStore_IsInitializedLoadPlugin(); + const { currentIsFetchedPluginsInfo, updateIsFetchedPluginsInfo, pendingIsFetchedPluginsInfo } = useStore_IsFetchedPluginsInfo(); + + const { currentSavedPluginsStatus, updateSavedPluginsStatus, pendingSavedPluginsStatus } = useStore_SavedPluginsStatus(); const { currentPluginsData, updatePluginsData, pendingPluginsData } = useStore_PluginsData(); const { currentIsPluginsInitialized, updateIsPluginsInitialized, pendingIsPluginsInitialized } = useStore_IsPluginsInitialized(); @@ -40,13 +47,15 @@ export const usePlugins = () => { const { asyncTauriFetchGithub } = useFetch(); - const generatePluginContext= (downloaded_plugin_info) => { + const generatePluginContext = (downloaded_plugin_info) => { const plugin_context = { registerComponent: (component) => { if (!downloaded_plugin_info.plugin_id || !downloaded_plugin_info.location || !component) { return console.error("An invalid plugin was detected.", downloaded_plugin_info.plugin_id, downloaded_plugin_info.location, component); } updatePluginsData(prev => { + console.log("-----updated downloaded plugin info----"); + const prev_map = new Map(prev.data.map(item => [item.plugin_id, item])); const new_data = []; let new_value = {}; @@ -74,7 +83,7 @@ export const usePlugins = () => { if (old_plugin_data.plugin_id === downloaded_plugin_info.plugin_id) { // ダウンロード済み or 登録済 アップデート 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); + const is_latest_version_available = (target_prev_plugin.is_downloaded) && (target_prev_plugin.latest_plugin_info?.plugin_version) && !(downloaded_plugin_info.plugin_version === target_prev_plugin.latest_plugin_info?.plugin_version); new_value = { ...target_prev_plugin, @@ -357,6 +366,11 @@ export const usePlugins = () => { currentIsPluginsInitialized, updateIsPluginsInitialized, + currentIsInitializedLoadPlugin, + updateIsInitializedLoadPlugin, + currentIsFetchedPluginsInfo, + updateIsFetchedPluginsInfo, + setSavedPluginsStatus, handlePendingPlugin, diff --git a/src-ui/logics/useReceiveRoutes.js b/src-ui/logics/useReceiveRoutes.js index b73fe62e..fb826f8c 100644 --- a/src-ui/logics/useReceiveRoutes.js +++ b/src-ui/logics/useReceiveRoutes.js @@ -206,7 +206,13 @@ export const useReceiveRoutes = () => { "/set/data/main_window_geometry": () => {}, "/run/open_filepath_logs": () => console.log("Opened Directory, Message Logs"), "/run/open_filepath_config_file": () => console.log("Opened Directory, Config File"), - "/run/software_update_info": updateLatestSoftwareVersionInfo, + "/run/software_update_info": () => { + updateLatestSoftwareVersionInfo({ + is_update_available: true, + new_version: "3.0.3", + }) + }, + // "/run/software_update_info": updateLatestSoftwareVersionInfo, "/run/connected_network": handleNetworkConnection, // Main Page diff --git a/src-ui/store.js b/src-ui/store.js index 5adbb4c7..58012777 100644 --- a/src-ui/store.js +++ b/src-ui/store.js @@ -279,6 +279,9 @@ export const { atomInstance: Atom_Hotkeys, useHook: useStore_Hotkeys } = createA // Plugins export const { atomInstance: Atom_IsPluginsInitialized, useHook: useStore_IsPluginsInitialized } = createAtomWithHook(false, "IsPluginsInitialized"); +export const { atomInstance: Atom_IsInitializedLoadPlugin, useHook: useStore_IsInitializedLoadPlugin } = createAtomWithHook(false, "IsInitializedLoadPlugin"); +export const { atomInstance: Atom_IsFetchedPluginsInfo, useHook: useStore_IsFetchedPluginsInfo } = createAtomWithHook(false, "IsFetchedPluginsInfo"); +export const { atomInstance: Atom_FetchedPluginsInfo, useHook: useStore_FetchedPluginsInfo } = createAtomWithHook(false, "FetchedPluginsInfo"); export const { atomInstance: Atom_SavedPluginsStatus, useHook: useStore_SavedPluginsStatus } = createAtomWithHook([], "SavedPluginsStatus"); export const { atomInstance: Atom_PluginsData, useHook: useStore_PluginsData } = createAtomWithHook([], "PluginsData");