Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 111 additions & 21 deletions Pengu Loader/plugins/ROSE-CustomWheel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
let selectedMapId = null;
let selectedFontId = null;
let selectedAnnouncerId = null;
let hideEmptyCategories = false;
let lastMapsMods = null;
let lastFontsMods = null;
let lastAnnouncersMods = null;
// Per-category multi-selection (UI / Voiceover / Loading Screen / VFX / SFX / Others).
// These are first-class categories in the UI; they just share the same list rendering logic.
let selectedCategoryIds = Object.create(null);
Expand Down Expand Up @@ -133,6 +137,67 @@
return SUMMARY_TABS.find((t) => t.id === tabId)?.label || String(tabId || "");
}

function tabHasInstalledMods(tabId) {
if (tabId === "skins") return true;
if (tabId === "maps") return Array.isArray(lastMapsMods) && lastMapsMods.length > 0;
if (tabId === "fonts") return Array.isArray(lastFontsMods) && lastFontsMods.length > 0;
if (tabId === "announcers") return Array.isArray(lastAnnouncersMods) && lastAnnouncersMods.length > 0;

if (OTHER_CATEGORY_TABS.some((t) => t.id === tabId)) {
if (!Object.prototype.hasOwnProperty.call(lastCategoryModsById, tabId)) return false;
const mods = lastCategoryModsById[tabId];
return Array.isArray(mods) && mods.length > 0;
}

return true;
}

function getVisibleSummaryTabs() {
if (!hideEmptyCategories) return SUMMARY_TABS;
return SUMMARY_TABS.filter((tab) => tab.id === "skins" || tabHasInstalledMods(tab.id));
}

function isSummaryTabVisible(tabId) {
return getVisibleSummaryTabs().some((tab) => tab.id === tabId);
}

function ensureActiveTabVisible() {
if (!isSummaryTabVisible(activeTab)) {
activeTab = "skins";
}
}

function syncActiveTabContent() {
if (!panel) return;
panel.querySelectorAll(".tab-content").forEach((content) => {
if (content && content.dataset && content.dataset.tab === activeTab) {
content.classList.add("active");
} else if (content) {
content.classList.remove("active");
}
});
}

function syncSummaryRowVisibility() {
if (!panel || !panel._summaryRowsByTab) return;
const visibleIds = new Set(getVisibleSummaryTabs().map((tab) => tab.id));
for (const tab of SUMMARY_TABS) {
const row = panel._summaryRowsByTab[tab.id];
if (row) {
row.style.display = visibleIds.has(tab.id) ? "" : "none";
}
}
}

function applyVisibleCategoryState() {
syncSummaryRowVisibility();
if (rightPaneMode === "picker" && !isSummaryTabVisible(activeTab)) {
ensureActiveTabVisible();
syncActiveTabContent();
setRightPaneMode("picker");
}
}

function refreshSummaryValues() {
if (!panel || !panel._summaryValuesByTab) return;
for (const tab of SUMMARY_TABS) {
Expand All @@ -151,11 +216,17 @@
}
}
}
syncSummaryRowVisibility();
// Keep the button badge in sync even when the panel is closed.
refreshButtonBadgeFromSelections();
}

function setRightPaneMode(mode) {
if (mode === "picker") {
ensureActiveTabVisible();
syncActiveTabContent();
}

rightPaneMode = mode;
if (!panel) return;

Expand Down Expand Up @@ -767,22 +838,12 @@
const isOtherCategoryTab = (tabName) => OTHER_CATEGORY_TABS.some((t) => t.id === tabName);

const switchTab = (tabName) => {
if (!isSummaryTabVisible(tabName)) {
tabName = "skins";
}
activeTab = tabName;
// Update tab content
const allContents = [
panel._modsContent,
panel._mapsContent,
panel._fontsContent,
panel._announcersContent,
...OTHER_CATEGORY_TABS.map((t) => panel[`_${t.id}Content`]).filter(Boolean),
];
allContents.forEach((content) => {
if (content && content.dataset && content.dataset.tab === tabName) {
content.classList.add("active");
} else if (content) {
content.classList.remove("active");
}
});
syncActiveTabContent();
// Request data for the active tab (always request fresh data)
if (tabName === "skins") {
requestModsForCurrentSkin();
Expand Down Expand Up @@ -1033,6 +1094,7 @@
panel._summaryRowsByTab[tab.id] = row;
summaryView.appendChild(row);
});
syncSummaryRowVisibility();

// Picker view (reuses existing scrollable with tab contents)
const pickerView = document.createElement("div");
Expand Down Expand Up @@ -2034,6 +2096,9 @@
return;
}

// Settings changes are intentionally applied on the next wheel open.
requestSettings();

// Create panel if it doesn't exist
if (!panel.parentNode) {
document.body.appendChild(panel);
Expand All @@ -2049,19 +2114,14 @@
activeTab = "skins";
isFirstOpenInSession = false;
}
ensureActiveTabVisible();

// Always start in summary view when opening the panel
setRightPaneMode("summary");
refreshSummaryValues();

// Update tab content based on activeTab (generic)
panel.querySelectorAll(".tab-content").forEach((content) => {
if (content && content.dataset && content.dataset.tab === activeTab) {
content.classList.add("active");
} else if (content) {
content.classList.remove("active");
}
});
syncActiveTabContent();

// Request data for the active tab
if (activeTab === "skins") {
Expand Down Expand Up @@ -2291,12 +2351,30 @@
updateButtonBadge(getSelectedModsCount());
}

function requestSettings() {
if (bridge) bridge.send({ type: "settings-request" });
}

function handleSettingsData(event) {
const detail = event?.detail;
if (!detail || detail.type !== "settings-data") {
return;
}

hideEmptyCategories = Boolean(detail.hideEmptyCategories);
applyVisibleCategoryState();
refreshSummaryValues();
}

function handleModsResponse(event) {
const detail = event?.detail;
if (!detail || detail.type !== "skin-mods-response") {
return;
}

hideEmptyCategories = Boolean(detail.hideEmptyCategories);
applyVisibleCategoryState();

const championId = Number(detail?.championId);
const skinId = Number(detail?.skinId);
if (!championId || !skinId) {
Expand Down Expand Up @@ -2389,6 +2467,7 @@
}

const mapsList = Array.isArray(detail.maps) ? detail.maps : [];
lastMapsMods = mapsList;

// Check for historic mod and auto-select it
const historicMod = detail.historicMod;
Expand All @@ -2411,6 +2490,7 @@

refreshSummaryValues();
refreshButtonBadgeFromSelections();
applyVisibleCategoryState();

if (isOpen && rightPaneMode === "picker" && activeTab === "maps") {
updateMapsEntries(mapsList);
Expand Down Expand Up @@ -2443,6 +2523,7 @@
}

const fontsList = Array.isArray(detail.fonts) ? detail.fonts : [];
lastFontsMods = fontsList;

// Check for historic mod and auto-select it
const historicMod = detail.historicMod;
Expand All @@ -2462,6 +2543,7 @@

refreshSummaryValues();
refreshButtonBadgeFromSelections();
applyVisibleCategoryState();

if (isOpen && rightPaneMode === "picker" && activeTab === "fonts") {
updateFontsEntries(fontsList);
Expand Down Expand Up @@ -2494,6 +2576,7 @@
}

const announcersList = Array.isArray(detail.announcers) ? detail.announcers : [];
lastAnnouncersMods = announcersList;

// Check for historic mod and auto-select it
const historicMod = detail.historicMod;
Expand All @@ -2513,6 +2596,7 @@

refreshSummaryValues();
refreshButtonBadgeFromSelections();
applyVisibleCategoryState();

if (isOpen && rightPaneMode === "picker" && activeTab === "announcers") {
updateAnnouncersEntries(announcersList);
Expand Down Expand Up @@ -2578,6 +2662,7 @@

refreshSummaryValues();
refreshButtonBadgeFromSelections();
applyVisibleCategoryState();

if (!isOpen || rightPaneMode !== "picker" || !OTHER_CATEGORY_TABS.some((t) => t.id === activeTab)) {
return;
Expand Down Expand Up @@ -2650,6 +2735,7 @@

refreshSummaryValues();
refreshButtonBadgeFromSelections();
applyVisibleCategoryState();

if (!isOpen || rightPaneMode !== "picker" || activeTab !== category) {
return;
Expand Down Expand Up @@ -2734,6 +2820,7 @@

// Subscribe to bridge messages instead of window CustomEvents
if (bridge) {
bridge.subscribe("settings-data", (data) => handleSettingsData({ detail: data }));
bridge.subscribe("skin-mods-response", (data) => handleModsResponse({ detail: data }));
bridge.subscribe("maps-response", (data) => handleMapsResponse({ detail: data }));
bridge.subscribe("fonts-response", (data) => handleFontsResponse({ detail: data }));
Expand All @@ -2758,8 +2845,11 @@
}
});

requestSettings();

// Request initial data on every (re)connect
bridge.onReady(() => {
requestSettings();
requestMaps();
requestFonts();
requestAnnouncers();
Expand Down
37 changes: 36 additions & 1 deletion Pengu Loader/plugins/ROSE-SettingsPanel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
threshold: 0.5,
monitorAutoResumeTimeout: 60,
autostart: false,
hideEmptyCategories: false,
gamePath: "",
gamePathValid: false,
version: "",
Expand Down Expand Up @@ -952,6 +953,7 @@
threshold: payload.threshold || 0.5,
monitorAutoResumeTimeout: payload.monitorAutoResumeTimeout || 60,
autostart: payload.autostart || false,
hideEmptyCategories: payload.hideEmptyCategories || false,
gamePath: payload.gamePath || "",
gamePathValid: payload.gamePathValid || false,
version: payload.version || "",
Expand Down Expand Up @@ -1798,6 +1800,30 @@
autostartSection.appendChild(autostartWrapper);
form.appendChild(autostartSection);

// Custom mods wheel section
const customWheelSection = document.createElement("div");
customWheelSection.className = "settings-section";

const customWheelLabel = document.createElement("label");
customWheelLabel.className = "settings-label";
customWheelLabel.textContent = "Custom mods wheel:";
customWheelSection.appendChild(customWheelLabel);

const hideEmptyCategoriesWrapper = document.createElement("div");
hideEmptyCategoriesWrapper.className = "settings-checkbox-wrapper";

const hideEmptyCategoriesCheckbox = document.createElement("input");
hideEmptyCategoriesCheckbox.type = "checkbox";
hideEmptyCategoriesCheckbox.className = "settings-checkbox";
hideEmptyCategoriesCheckbox.id = "hide-empty-categories-checkbox";
hideEmptyCategoriesWrapper.appendChild(hideEmptyCategoriesCheckbox);

const hideEmptyCategoriesText = document.createElement("span");
hideEmptyCategoriesText.textContent = "Hide empty mod categories";
hideEmptyCategoriesWrapper.appendChild(hideEmptyCategoriesText);
customWheelSection.appendChild(hideEmptyCategoriesWrapper);
form.appendChild(customWheelSection);

// Game path section
const pathSection = document.createElement("div");
pathSection.className = "settings-section";
Expand Down Expand Up @@ -2386,6 +2412,7 @@
const timeoutButton = timeoutSlider?.closest('.lol-settings-slider')?.querySelector('.lol-uikit-slider-button');
const timeoutFill = timeoutSlider?.closest('.lol-settings-slider')?.querySelector('.lol-uikit-slider-fill');
const autostartCheckbox = document.getElementById("autostart-checkbox");
const hideEmptyCategoriesCheckbox = document.getElementById("hide-empty-categories-checkbox");
const pathInput = document.getElementById("game-path-input");

if (thresholdSlider && thresholdValue && thresholdButton && thresholdFill) {
Expand Down Expand Up @@ -2417,6 +2444,10 @@
autostartCheckbox.checked = currentSettings.autostart;
}

if (hideEmptyCategoriesCheckbox) {
hideEmptyCategoriesCheckbox.checked = currentSettings.hideEmptyCategories;
}

if (pathInput) {
pathInput.value = currentSettings.gamePath || "";
// Update status based on validation result from settings data
Expand Down Expand Up @@ -2490,6 +2521,7 @@
const thresholdSlider = document.getElementById("threshold-slider");
const timeoutSlider = document.getElementById("timeout-slider");
const autostartCheckbox = document.getElementById("autostart-checkbox");
const hideEmptyCategoriesCheckbox = document.getElementById("hide-empty-categories-checkbox");
const pathInput = document.getElementById("game-path-input");

const threshold = thresholdSlider
Expand All @@ -2499,6 +2531,7 @@
? parseInt(timeoutSlider.value)
: 60;
const autostart = autostartCheckbox ? autostartCheckbox.checked : false;
const hideEmptyCategories = hideEmptyCategoriesCheckbox ? hideEmptyCategoriesCheckbox.checked : false;
const gamePath = pathInput ? pathInput.value.trim() : "";

// Clamp threshold between 0.30 and 2.0
Expand All @@ -2514,13 +2547,15 @@
threshold: clampedThreshold,
monitorAutoResumeTimeout: clampedTimeout,
autostart: autostart,
hideEmptyCategories: hideEmptyCategories,
gamePath: gamePath,
});

log("info", "Settings save requested", {
threshold: clampedThreshold,
monitorAutoResumeTimeout: clampedTimeout,
autostart,
hideEmptyCategories,
gamePath,
});
}
Expand Down Expand Up @@ -3658,4 +3693,4 @@
log("error", "Init failed:", err);
});
}
})();
})();
Loading