[Refactor] Move to src-ui/views and src-ui/logics structure.
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
import { useEffect } from "react";
|
||||
|
||||
import {
|
||||
useVolume,
|
||||
useIsOpenedConfigPage,
|
||||
} from "@logics_common";
|
||||
|
||||
import {
|
||||
useMainFunction,
|
||||
} from "@logics_main";
|
||||
|
||||
import { useHotkeys } from "@logics_configs";
|
||||
|
||||
import { useStore_MainFunctionsStateMemory } from "@store";
|
||||
|
||||
export const ConfigPageCloseTriggerController = () => {
|
||||
const { currentIsOpenedConfigPage } = useIsOpenedConfigPage();
|
||||
const {
|
||||
currentMainFunctionsStateMemory,
|
||||
updateMainFunctionsStateMemory,
|
||||
} = useStore_MainFunctionsStateMemory();
|
||||
|
||||
const {
|
||||
currentTranslationStatus,
|
||||
setTranslation,
|
||||
pendingTranslationStatus,
|
||||
currentTranscriptionSendStatus,
|
||||
setTranscriptionSend,
|
||||
pendingTranscriptionSendStatus,
|
||||
currentTranscriptionReceiveStatus,
|
||||
setTranscriptionReceive,
|
||||
pendingTranscriptionReceiveStatus,
|
||||
} = useMainFunction();
|
||||
const {
|
||||
currentMicThresholdCheckStatus,
|
||||
volumeCheckStop_Mic,
|
||||
currentSpeakerThresholdCheckStatus,
|
||||
volumeCheckStop_Speaker,
|
||||
} = useVolume();
|
||||
|
||||
const { registerShortcuts, unregisterAll } = useHotkeys();
|
||||
|
||||
|
||||
const memorizeLatestMainFunctionsState = () => {
|
||||
updateMainFunctionsStateMemory({
|
||||
translation: currentTranslationStatus.data,
|
||||
transcription_send: currentTranscriptionSendStatus.data,
|
||||
transcription_receive: currentTranscriptionReceiveStatus.data,
|
||||
});
|
||||
};
|
||||
|
||||
const restoreMainFunctionState = () => {
|
||||
// First, set loading status all before waiting a backend process.
|
||||
if (currentMainFunctionsStateMemory.data.translation === true) pendingTranslationStatus();
|
||||
if (currentMainFunctionsStateMemory.data.transcription_send === true) pendingTranscriptionSendStatus();
|
||||
if (currentMainFunctionsStateMemory.data.transcription_receive === true) pendingTranscriptionReceiveStatus();
|
||||
|
||||
// Then, restore them.
|
||||
if (currentMainFunctionsStateMemory.data.translation === true) setTranslation(true);
|
||||
if (currentMainFunctionsStateMemory.data.transcription_send === true) setTranscriptionSend(true);
|
||||
if (currentMainFunctionsStateMemory.data.transcription_receive === true) setTranscriptionReceive(true);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (currentIsOpenedConfigPage.data === true) { // When config page is opened.
|
||||
memorizeLatestMainFunctionsState();
|
||||
unregisterAll();
|
||||
if (currentTranslationStatus.data === true) setTranslation(false);
|
||||
if (currentTranscriptionSendStatus.data === true) setTranscriptionSend(false);
|
||||
if (currentTranscriptionReceiveStatus.data === true) setTranscriptionReceive(false);
|
||||
} else if (currentIsOpenedConfigPage.data === false) { // When config page is closed.
|
||||
registerShortcuts();
|
||||
if (currentMicThresholdCheckStatus.data === true) volumeCheckStop_Mic();
|
||||
if (currentSpeakerThresholdCheckStatus.data === true) volumeCheckStop_Speaker();
|
||||
restoreMainFunctionState();
|
||||
}
|
||||
}, [currentIsOpenedConfigPage.data]);
|
||||
return null;
|
||||
};
|
||||
54
src-ui/views/app/_app_controllers/CornerRadiusController.jsx
Normal file
54
src-ui/views/app/_app_controllers/CornerRadiusController.jsx
Normal file
@@ -0,0 +1,54 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { store } from "@store";
|
||||
|
||||
export const CornerRadiusController = () => {
|
||||
const [is_win11, setIsWin11] = useState(false);
|
||||
const [is_maximized, setIsMaximized] = useState(false);
|
||||
|
||||
const appWindow = store.appWindow;
|
||||
|
||||
// OS 判定(Win11 なら platformVersion の major ≥13)
|
||||
useEffect(() => {
|
||||
if (navigator.userAgentData?.getHighEntropyValues) {
|
||||
navigator.userAgentData
|
||||
.getHighEntropyValues(["platformVersion"])
|
||||
.then(({ platformVersion }) => {
|
||||
const major = parseInt(platformVersion.split(".")[0], 10);
|
||||
setIsWin11(major >= 13);
|
||||
})
|
||||
.catch(() => {
|
||||
setIsWin11(false);
|
||||
})
|
||||
} else {
|
||||
// フォールバックで Win10 扱い
|
||||
setIsWin11(false);
|
||||
}
|
||||
}, [])
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
let unlisten;
|
||||
const setup = async () => {
|
||||
// 初期状態取得
|
||||
setIsMaximized(await appWindow.isMaximized());
|
||||
// リサイズ時にも再取得
|
||||
const updateMax = () => appWindow.isMaximized().then(setIsMaximized);
|
||||
unlisten = await appWindow.listen("tauri://resize", updateMax);
|
||||
}
|
||||
setup();
|
||||
|
||||
return () => {
|
||||
if (unlisten) {
|
||||
unlisten();
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
// 角丸の適用
|
||||
useEffect(() => {
|
||||
const radius = is_win11 && !is_maximized ? "10px" : "0";
|
||||
document.body.style.borderRadius = radius;
|
||||
}, [is_win11, is_maximized]);
|
||||
|
||||
return null;;
|
||||
}
|
||||
11
src-ui/views/app/_app_controllers/FontFamilyController.jsx
Normal file
11
src-ui/views/app/_app_controllers/FontFamilyController.jsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import { useEffect } from "react";
|
||||
import { useAppearance } from "@logics_configs";
|
||||
|
||||
export const FontFamilyController = () => {
|
||||
const { currentSelectedFontFamily } = useAppearance();
|
||||
useEffect(() => {
|
||||
document.documentElement.style.setProperty("--font_family", currentSelectedFontFamily.data);
|
||||
}, [currentSelectedFontFamily.data]);
|
||||
|
||||
return null;
|
||||
};
|
||||
25
src-ui/views/app/_app_controllers/GlobalHotKeyController.jsx
Normal file
25
src-ui/views/app/_app_controllers/GlobalHotKeyController.jsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import { useEffect } from "react";
|
||||
import { useHotkeys } from "@logics_configs";
|
||||
import { useIsBackendReady, useIsSoftwareUpdating, useIsVrctAvailable } from "@logics_common";
|
||||
|
||||
export const GlobalHotKeyController = () => {
|
||||
const { currentIsBackendReady } = useIsBackendReady();
|
||||
const { currentIsSoftwareUpdating } = useIsSoftwareUpdating();
|
||||
const { registerShortcuts, unregisterAll } = useHotkeys();
|
||||
|
||||
const { currentIsVrctAvailable } = useIsVrctAvailable();
|
||||
|
||||
useEffect(() => {
|
||||
const is_backend_ready = currentIsBackendReady.data;
|
||||
const is_software_updating = currentIsSoftwareUpdating.data;
|
||||
const is_vrct_available = currentIsVrctAvailable.data;
|
||||
|
||||
if (is_vrct_available && is_backend_ready && !is_software_updating) {
|
||||
registerShortcuts();
|
||||
} else {
|
||||
unregisterAll();
|
||||
}
|
||||
}, [currentIsBackendReady.data, currentIsSoftwareUpdating.data, currentIsVrctAvailable.data]);
|
||||
|
||||
return null;
|
||||
};
|
||||
31
src-ui/views/app/_app_controllers/KeyEventController.jsx
Normal file
31
src-ui/views/app/_app_controllers/KeyEventController.jsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import { useEffect } from "react";
|
||||
|
||||
export const KeyEventController = () => {
|
||||
useEffect(() => {
|
||||
const handleKeydown = (event) => {
|
||||
if (
|
||||
event.key === "F5" || // Page reload
|
||||
event.key === "F10" || // Focus thw window menu (maybe)
|
||||
event.key === "F12" || // Open dev tool
|
||||
(event.ctrlKey && event.key === "r") ||
|
||||
(event.metaKey && event.key === "r")
|
||||
) {
|
||||
event.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
const handleContextmenu = (event) => {
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
document.addEventListener("keydown", handleKeydown);
|
||||
document.addEventListener("contextmenu", handleContextmenu);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("keydown", handleKeydown);
|
||||
document.removeEventListener("contextmenu", handleContextmenu);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return null;
|
||||
};
|
||||
24
src-ui/views/app/_app_controllers/PluginsController.jsx
Normal file
24
src-ui/views/app/_app_controllers/PluginsController.jsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import React from "react";
|
||||
import clsx from "clsx";
|
||||
import * as reactI18next from "react-i18next";
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
window.React = React;
|
||||
window.clsx = clsx;
|
||||
window.reactI18next = reactI18next;
|
||||
}
|
||||
|
||||
import { LoadPluginsController } from "./plugins_controllers/LoadPluginsController";
|
||||
import { FetchLatestPluginsDataController } from "./plugins_controllers/FetchLatestPluginsDataController";
|
||||
import { MergePluginsController } from "./plugins_controllers/MergePluginsController";
|
||||
|
||||
export const PluginsController = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<MergePluginsController />
|
||||
<LoadPluginsController />
|
||||
<FetchLatestPluginsDataController />
|
||||
</>
|
||||
);
|
||||
};
|
||||
81
src-ui/views/app/_app_controllers/StartPythonController.jsx
Normal file
81
src-ui/views/app/_app_controllers/StartPythonController.jsx
Normal file
@@ -0,0 +1,81 @@
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { Command } from "@tauri-apps/plugin-shell";
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
import { useStdoutToPython } from "@useStdoutToPython";
|
||||
import { useReceiveRoutes } from "@useReceiveRoutes";
|
||||
import { store, useStore_SelectableFontFamilyList } from "@store";
|
||||
import { arrayToObject } from "@utils";
|
||||
|
||||
import {
|
||||
useNotificationStatus,
|
||||
} from "@logics_common";
|
||||
|
||||
export const StartPythonController = () => {
|
||||
const { asyncStartPython } = useStartPython();
|
||||
const hasRunRef = useRef(false);
|
||||
const { asyncFetchFonts } = useAsyncFetchFonts();
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasRunRef.current) {
|
||||
asyncStartPython().then(() => {
|
||||
startFeedingToWatchDogController();
|
||||
asyncFetchFonts();
|
||||
}).catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
return () => hasRunRef.current = true;
|
||||
}, []);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const useStartPython = () => {
|
||||
const { receiveRoutes } = useReceiveRoutes();
|
||||
const { showNotification_Success, showNotification_Error } = useNotificationStatus();
|
||||
|
||||
const asyncStartPython = async () => {
|
||||
const command = Command.sidecar("bin/VRCT-sidecar");
|
||||
command.on("error", error => console.error(`error: "${error}"`));
|
||||
command.stdout.on("data", (line) => {
|
||||
let parsed_data = "";
|
||||
try {
|
||||
parsed_data = JSON.parse(line);
|
||||
receiveRoutes(parsed_data);
|
||||
} catch (error) {
|
||||
console.log(error, line);
|
||||
}
|
||||
});
|
||||
command.stderr.on("data", line => {
|
||||
showNotification_Error(
|
||||
`An error occurred. Please restart VRCT or contact the developers. The last line:${JSON.stringify(line)}`, { hide_duration: null });
|
||||
console.error("stderr", line);
|
||||
});
|
||||
const backend_subprocess = await command.spawn();
|
||||
store.backend_subprocess = backend_subprocess;
|
||||
};
|
||||
|
||||
return { asyncStartPython };
|
||||
};
|
||||
|
||||
const useAsyncFetchFonts = () => {
|
||||
const { updateSelectableFontFamilyList } = useStore_SelectableFontFamilyList();
|
||||
const asyncFetchFonts = async () => {
|
||||
try {
|
||||
let fonts = await invoke("get_font_list");
|
||||
fonts = fonts.sort((a, b) => a.localeCompare(b, undefined, { sensitivity: "base" }));
|
||||
updateSelectableFontFamilyList(arrayToObject(fonts));
|
||||
} catch (error) {
|
||||
console.error("Error fetching fonts:", error);
|
||||
}
|
||||
};
|
||||
return { asyncFetchFonts };
|
||||
};
|
||||
|
||||
const startFeedingToWatchDogController = () => {
|
||||
const { asyncStdoutToPython } = useStdoutToPython();
|
||||
setInterval(() => {
|
||||
asyncStdoutToPython("/run/feed_watchdog");
|
||||
}, 20000); // 20000ミリ秒 = 20秒
|
||||
};
|
||||
11
src-ui/views/app/_app_controllers/TransparencyController.jsx
Normal file
11
src-ui/views/app/_app_controllers/TransparencyController.jsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import { useEffect } from "react";
|
||||
import { useAppearance } from "@logics_configs";
|
||||
|
||||
export const TransparencyController = () => {
|
||||
const { currentTransparency } = useAppearance();
|
||||
useEffect(() => {
|
||||
document.documentElement.style.setProperty("opacity", `${currentTransparency.data / 100}`);
|
||||
}, [currentTransparency.data]);
|
||||
|
||||
return null;
|
||||
};
|
||||
14
src-ui/views/app/_app_controllers/UiLanguageController.jsx
Normal file
14
src-ui/views/app/_app_controllers/UiLanguageController.jsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import { useEffect } from "react";
|
||||
|
||||
import { useI18n } from "@useI18n";
|
||||
import { useAppearance } from "@logics_configs";
|
||||
|
||||
export const UiLanguageController = () => {
|
||||
const { currentUiLanguage } = useAppearance();
|
||||
const { i18n } = useI18n();
|
||||
|
||||
useEffect(() => {
|
||||
i18n.changeLanguage(currentUiLanguage.data);
|
||||
}, [currentUiLanguage.data]);
|
||||
return null;
|
||||
};
|
||||
13
src-ui/views/app/_app_controllers/UiSizeController.jsx
Normal file
13
src-ui/views/app/_app_controllers/UiSizeController.jsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import { useEffect } from "react";
|
||||
import { useAppearance } from "@logics_configs";
|
||||
|
||||
export const UiSizeController = () => {
|
||||
const { currentUiScaling } = useAppearance();
|
||||
const font_size = 62.5 * currentUiScaling.data / 100;
|
||||
|
||||
useEffect(() => {
|
||||
document.documentElement.style.setProperty("font-size", `${font_size}%`);
|
||||
}, [currentUiScaling.data]);
|
||||
|
||||
return null;
|
||||
};
|
||||
10
src-ui/views/app/_app_controllers/index.js
Normal file
10
src-ui/views/app/_app_controllers/index.js
Normal file
@@ -0,0 +1,10 @@
|
||||
export { KeyEventController } from "./KeyEventController";
|
||||
export { StartPythonController } from "./StartPythonController";
|
||||
export { GlobalHotKeyController } from "./GlobalHotKeyController";
|
||||
export { UiLanguageController } from "./UiLanguageController";
|
||||
export { ConfigPageCloseTriggerController } from "./ConfigPageCloseTriggerController";
|
||||
export { UiSizeController } from "./UiSizeController";
|
||||
export { FontFamilyController } from "./FontFamilyController";
|
||||
export { TransparencyController } from "./TransparencyController";
|
||||
export { PluginsController } from "./PluginsController";
|
||||
export { CornerRadiusController } from "./CornerRadiusController";
|
||||
@@ -0,0 +1,17 @@
|
||||
import { useEffect } from "react";
|
||||
import { usePlugins } from "@logics_configs";
|
||||
|
||||
export const FetchLatestPluginsDataController = () => {
|
||||
const {
|
||||
asyncFetchPluginsInfo,
|
||||
isAnyPluginEnabled_Init,
|
||||
} = usePlugins();
|
||||
|
||||
useEffect(() => {
|
||||
if (isAnyPluginEnabled_Init()) {
|
||||
asyncFetchPluginsInfo();
|
||||
}
|
||||
}, []);
|
||||
|
||||
return null;
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
import { useEffect } from "react";
|
||||
import { usePlugins } from "@logics_configs";
|
||||
import { store } from "@store";
|
||||
|
||||
export const LoadPluginsController = () => {
|
||||
const {
|
||||
asyncLoadAllPlugins,
|
||||
} = usePlugins();
|
||||
|
||||
const asyncInitLoadPlugins = async () => {
|
||||
try {
|
||||
await asyncLoadAllPlugins();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!store.is_initialized_load_plugin) {
|
||||
asyncInitLoadPlugins();
|
||||
store.is_initialized_load_plugin = true;
|
||||
}
|
||||
}, []);
|
||||
|
||||
return null;
|
||||
};
|
||||
@@ -0,0 +1,205 @@
|
||||
import { useEffect, useRef } from "react";
|
||||
import { useI18n } from "@useI18n";
|
||||
import { store } from "@store";
|
||||
import { usePlugins } from "@logics_configs";
|
||||
import { useSoftwareVersion } from "@logics_common";
|
||||
import { useNotificationStatus } from "@logics_common";
|
||||
|
||||
export const MergePluginsController = () => {
|
||||
const { t } = useI18n();
|
||||
const {
|
||||
currentLoadedPlugins,
|
||||
updatePluginsData,
|
||||
currentPluginsData,
|
||||
currentFetchedPluginsInfo,
|
||||
currentSavedPluginsStatus,
|
||||
downloadAndExtractPlugin,
|
||||
setTargetSavedPluginsStatus_Init,
|
||||
} = usePlugins();
|
||||
const { checkVrctVerCompatibility } = useSoftwareVersion();
|
||||
const { showNotification_Success, showNotification_Error } = useNotificationStatus();
|
||||
|
||||
// downloaded, fetched, saved の各情報をまとめてマージ
|
||||
useEffect(() => {
|
||||
const mergePluginData = () => {
|
||||
updatePluginsData(prev => {
|
||||
// downloaded, fetched, 保存済み状態のMapをそれぞれ作成(plugin_id をキー)
|
||||
const downloaded_map = new Map(
|
||||
currentLoadedPlugins.data.map(info => [info.plugin_id, info])
|
||||
);
|
||||
const fetched_map = new Map(
|
||||
currentFetchedPluginsInfo.data.map(info => [info.plugin_id, info])
|
||||
);
|
||||
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])
|
||||
);
|
||||
|
||||
// union_keys: Saved以外の情報に対して重複なくキーを取得する
|
||||
const union_keys = new Set([
|
||||
...downloaded_map.keys(),
|
||||
...fetched_map.keys(),
|
||||
...prev_map.keys(),
|
||||
]);
|
||||
|
||||
const new_data = [];
|
||||
for (const id of union_keys) {
|
||||
const downloaded = downloaded_map.get(id);
|
||||
const fetched = fetched_map.get(id);
|
||||
const prev_plugin = prev_map.get(id);
|
||||
let plugin = {};
|
||||
|
||||
if (downloaded) {
|
||||
// ダウンロード済み情報に対してサポート確認
|
||||
const { is_plugin_supported, is_plugin_supported_latest_vrct } =
|
||||
checkVrctVerCompatibility(
|
||||
downloaded.min_supported_vrct_version,
|
||||
downloaded.max_supported_vrct_version
|
||||
);
|
||||
plugin = {
|
||||
// prevの情報があれば引き継ぎつつ上書き
|
||||
...(prev_plugin || {}),
|
||||
plugin_id: downloaded.plugin_id,
|
||||
component: downloaded.component,
|
||||
is_downloaded: true,
|
||||
downloaded_plugin_info: {
|
||||
...downloaded,
|
||||
is_plugin_supported,
|
||||
is_plugin_supported_latest_vrct,
|
||||
},
|
||||
};
|
||||
|
||||
if (fetched) {
|
||||
const is_latest_version_available =
|
||||
(downloaded.plugin_version !== fetched.plugin_version && fetched.is_plugin_supported);
|
||||
plugin = {
|
||||
...plugin,
|
||||
is_outdated: false,
|
||||
latest_plugin_info: { ...fetched },
|
||||
is_latest_version_available:
|
||||
plugin.is_downloaded && is_latest_version_available,
|
||||
is_latest_version_already:
|
||||
downloaded.plugin_version === fetched.plugin_version,
|
||||
};
|
||||
} else {
|
||||
// フェッチ情報がない場合の初期状態
|
||||
plugin = {
|
||||
...plugin,
|
||||
is_latest_version_available: false,
|
||||
is_latest_version_already: true,
|
||||
};
|
||||
}
|
||||
} else if (fetched) {
|
||||
// フェッチ情報のみの場合は、ダウンロードしていない初期状態
|
||||
plugin = {
|
||||
...(prev_plugin || {}),
|
||||
plugin_id: fetched.plugin_id,
|
||||
is_downloaded: false,
|
||||
is_latest_version_available: fetched.is_plugin_supported,
|
||||
is_latest_version_already: false,
|
||||
is_outdated: false,
|
||||
latest_plugin_info: { ...fetched },
|
||||
};
|
||||
} else if (prev_plugin) {
|
||||
// 既存情報のみ存在する場合は outdated フラグを付与
|
||||
plugin = { ...prev_plugin, is_outdated: true };
|
||||
}
|
||||
// いずれかの情報がある場合のみ new_data に追加
|
||||
if (plugin.plugin_id) {
|
||||
new_data.push(plugin);
|
||||
}
|
||||
}
|
||||
|
||||
// 保存済み状態(currentSavedPluginsStatus)のマージ
|
||||
// ・new_dataに存在する各プラグインに対して、保存済みの is_enabled を上書き
|
||||
new_data.forEach(plugin => {
|
||||
if (saved_map.has(plugin.plugin_id)) {
|
||||
plugin.is_enabled = saved_map.get(plugin.plugin_id).is_enabled;
|
||||
}
|
||||
});
|
||||
// ・prev.data には存在せず、保存済み情報にのみある場合は追加
|
||||
for (const [id, saved] of saved_map.entries()) {
|
||||
if (!new_data.some(item => item.plugin_id === id)) {
|
||||
new_data.push({ plugin_id: saved.plugin_id, is_enabled: saved.is_enabled });
|
||||
}
|
||||
}
|
||||
|
||||
return new_data;
|
||||
});
|
||||
};
|
||||
|
||||
mergePluginData();
|
||||
}, [currentFetchedPluginsInfo.data, currentLoadedPlugins.data, currentSavedPluginsStatus]);
|
||||
|
||||
|
||||
|
||||
// --- 自動アップデート(ダウンロード処理)---
|
||||
// ※downloadAndExtractPlugin の重複実行を防ぐため、実行中の plugin_id を useRef で管理
|
||||
const downloadingRef = useRef(new Set());
|
||||
|
||||
useEffect(() => {
|
||||
if (!currentPluginsData.data.length) return;
|
||||
// マージ結果の currentPluginsData.data を元にダウンロード処理をチェック
|
||||
currentPluginsData.data.forEach(plugin => {
|
||||
if (plugin.is_downloaded &&
|
||||
plugin.is_enabled &&
|
||||
!plugin.downloaded_plugin_info.is_plugin_supported &&
|
||||
!plugin.is_latest_version_already &&
|
||||
plugin.is_latest_version_available
|
||||
) {
|
||||
if (!downloadingRef.current.has(plugin.plugin_id)) {
|
||||
showNotification_Success(t("plugin_notifications.updating"));
|
||||
downloadingRef.current.add(plugin.plugin_id);
|
||||
const target_plugin_id = plugin.plugin_id;
|
||||
downloadAndExtractPlugin(plugin)
|
||||
.then(() => {
|
||||
console.log(`Plugin ${target_plugin_id} updated successfully`);
|
||||
downloadingRef.current.delete(target_plugin_id);
|
||||
showNotification_Success(t("plugin_notifications.updated_success"));
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(`Plugin ${target_plugin_id} update failed`, error);
|
||||
downloadingRef.current.delete(target_plugin_id);
|
||||
showNotification_Error(t("plugin_notifications.updated_error"));
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}, [currentPluginsData.data]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
// ダウンロード済みかつ有効なプラグインで、サポート対象でない場合は無効化
|
||||
if (store.is_initialized_fetched_plugin_info) {
|
||||
updatePluginsData(prev => {
|
||||
prev.data.forEach(plugin => {
|
||||
if (plugin.is_downloaded && plugin.is_enabled) {
|
||||
if (
|
||||
!plugin.downloaded_plugin_info.is_plugin_supported &&
|
||||
plugin.latest_plugin_info &&
|
||||
!plugin.latest_plugin_info?.is_plugin_supported
|
||||
) {
|
||||
showNotification_Error(t("plugin_notifications.disabled_out_of_support"));
|
||||
plugin.is_enabled = false;
|
||||
setTargetSavedPluginsStatus_Init(plugin.plugin_id, false);
|
||||
}
|
||||
|
||||
if (
|
||||
!plugin.downloaded_plugin_info.is_plugin_supported &&
|
||||
plugin.is_outdated
|
||||
) {
|
||||
showNotification_Error(t("plugin_notifications.disabled_out_of_support"));
|
||||
plugin.is_enabled = false;
|
||||
setTargetSavedPluginsStatus_Init(plugin.plugin_id, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
return prev.data;
|
||||
});
|
||||
}
|
||||
}, [store.is_initialized_fetched_plugin_info]);
|
||||
|
||||
return null;
|
||||
};
|
||||
Reference in New Issue
Block a user