Advertisement
Mashtii

script.js

Jun 28th, 2025 (edited)
90
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // Plik: script.js
  2.  
  3. document.addEventListener('DOMContentLoaded', () => {
  4.     const ICON_BASE_URL = 'IconChamp/';
  5.     const champions = [
  6.         { name: "[Event] Polowanie na Lempo", minTime: 0, maxTime: 0, category: 'event', iconPath: "Lempo.png" },
  7.         { name: "[Event] Obrona Mostu", minTime: 240, maxTime: 241, category: 'event', iconPath: "Hvar.png" },
  8.         { name: "[Event] Sana", minTime: 120, maxTime: 121, category: 'event', iconPath: "Sana.png" },
  9.         { name: "[Event] Orki", minTime: 480, maxTime: 481, category: 'event', iconPath: "Orki.png" },
  10.         { name: "[BOSS] Bibliotekarz", minTime: 17, maxTime: 29, iconPath: "Bibliotekarz.png", category: 'boss' },
  11.         { name: "[BOSS] Wendigo", minTime: 120, maxTime: 150, iconPath: "Wendigo.png", category: 'boss' },
  12.         { name: "[BOSS] Jastrzębior", minTime: 300, maxTime: 420, iconPath: "Jastrzębior.png", category: 'boss' },
  13.         { name: "Kosior", minTime: 25, maxTime: 30, iconPath: "Kosior.png", category: 'champion' },
  14.         { name: "Kruczy", minTime: 25, maxTime: 30, iconPath: "Kruczy.png", category: 'champion' },
  15.         { name: "Ogruch", minTime: 20, maxTime: 30, iconPath: "Ogruch.png", category: 'champion' },
  16.         { name: "Treven", minTime: 60, maxTime: 80, iconPath: "Treven.png", category: 'champion' },
  17.         { name: "Cybulski", minTime: 35, maxTime: 50, iconPath: "Cybulski.png", category: 'champion' },
  18.         { name: "Nielichy", minTime: 20, maxTime: 28, iconPath: "Nielichy.png", category: 'champion' },
  19.         { name: "Popiel", minTime: 30, maxTime: 40, iconPath: "Popiel.png", category: 'champion' },
  20.         { name: "Acerodon", minTime: 60, maxTime: 70, iconPath: "Acerodon.png", category: 'champion' },
  21.         { name: "Harilar", minTime: 60, maxTime: 75, iconPath: "Harilar.png", category: 'champion' },
  22.         { name: "Król Szczurów", minTime: 90, maxTime: 120, iconPath: "Król_Szczurów.png", category: 'champion' },
  23.         { name: "Orthal", minTime: 40, maxTime: 60, iconPath: "Orthal.png", category: 'champion' },
  24.         { name: "Wilhelm Tell", minTime: 45, maxTime: 65, iconPath: "Wilhelm_Tell.png", category: 'champion' },
  25.         { name: "Wilczur", minTime: 60, maxTime: 70, iconPath: "Wilczur.png", category: 'champion' },
  26.         { name: "Przybysz", minTime: 90, maxTime: 120, iconPath: "Przybysz.png", category: 'champion' },
  27.         { name: "Zębacz", minTime: 40, maxTime: 48, iconPath: "Zębacz.png", category: 'champion' },
  28.         { name: "Brachyura", minTime: 30, maxTime: 45, iconPath: "Brachyura.png", category: 'champion' },
  29.         { name: "Tilsal Wędrowny", minTime: 60, maxTime: 70, iconPath: "Tilsai_wędrowny.png", category: 'champion' },
  30.         { name: "Karol Kold", minTime: 45, maxTime: 57, iconPath: "Karol_kold.png", category: 'champion' },
  31.         { name: "Psychopata", minTime: 50, maxTime: 65, iconPath: "Psychopata.png", category: 'champion' },
  32.         { name: "Krwiopijca", minTime: 90, maxTime: 100, iconPath: "Krwiopijca.png", category: 'champion' },
  33.         { name: "Zaklinacz Kruków", minTime: 25, maxTime: 33, iconPath: "Zaklinacz_Kruków.png", category: 'champion' },
  34.         { name: "Wściekły Grizzly", minTime: 35, maxTime: 55, iconPath: "Wściekły_Grizzly.png", category: 'champion' },
  35.         { name: "Telek", minTime: 60, maxTime: 66, iconPath: "Telek.png", category: 'champion' },
  36.         { name: "Rizurul", minTime: 40, maxTime: 45, iconPath: "Rizurul.png", category: 'champion' },
  37.         { name: "Żaimm", minTime: 20, maxTime: 24, iconPath: "Zaimm.png", category: 'champion' },
  38.         { name: "Wściekły Burkan", minTime: 20, maxTime: 30, iconPath: "Wściekły_Burkan.png", category: 'champion' },
  39.         { name: "Jesienica", minTime: 35, maxTime: 47, iconPath: "Jesienica.png", category: 'champion' },
  40.         { name: "Dritan Żarliwy", minTime: 90, maxTime: 110, iconPath: "Dritan_Żarliwy.png", category: 'champion' },
  41.         { name: "Zimowy Szaman", minTime: 60, maxTime: 70, iconPath: "Zimowy_Szaman.png", category: 'champion' },
  42.         { name: "Tygrys Górski", minTime: 25, maxTime: 40, iconPath: "Tygrys_Górski.png", category: 'champion' },
  43.         { name: "Obłąkana Harpia", minTime: 35, maxTime: 47, iconPath: "Obłąkana_harpia.png", category: 'champion' },
  44.         { name: "Zawieja", minTime: 45, maxTime: 65, iconPath: "Zawieja.png", category: 'champion' },
  45.         { name: "Ragak Maruder", minTime: 120, maxTime: 150, iconPath: "Ragak_Maruder.png", category: 'champion' },
  46.         { name: "Yoko", minTime: 15, maxTime: 19, iconPath: "Yoko.png", category: 'champion' },
  47.         { name: "Kapłan Śmierci", minTime: 0, maxTime: 0, iconPath: "Kapłan_Śmierci.png", category: 'champion' },
  48.         { name: "Halmengir", minTime: 60, maxTime: 75, iconPath: "Halmengir.png", category: 'champion' },
  49.         { name: "Olm", minTime: 120, maxTime: 140, iconPath: "Olm.png", category: 'champion' },
  50.         { name: "Troll Zimowy 1", minTime: 30, maxTime: 40, iconPath: "Troll_Zimowy_1.png", category: 'champion' },
  51.         { name: "Troll Zimowy 2", minTime: 30, maxTime: 40, iconPath: "Troll_Zimowy_2.png", category: 'champion' },
  52.         { name: "Podróżnik", minTime: 20, maxTime: 25, iconPath: "Podróżnik.png", category: 'champion' },
  53.         { name: "Koszmar", minTime: 60, maxTime: 75, iconPath: "Koszmar.png", category: 'champion' },
  54.         { name: "Pacynkarz", minTime: 30, maxTime: 40, iconPath: "Pacynkarz.png", category: 'champion' },
  55.         { name: "Wykwit 1", minTime: 25, maxTime: 35, iconPath: "Wykwit.png", category: 'champion' },
  56.         { name: "Wykwit 2", minTime: 25, maxTime: 35, iconPath: "Wykwit.png", category: 'champion' },
  57.         { name: "Grobnica", minTime: 45, maxTime: 60, iconPath: "Grobnica.png", category: 'champion' },
  58.         { name: "Krwiopij", minTime: 60, maxTime: 100, iconPath: "Krwiopij.png", category: 'champion' },
  59.         { name: "Wisp", minTime: 120, maxTime: 180, iconPath: "Wisp.png", category: 'champion' },
  60.         { name: "Żywiciel Jak", minTime: 60, maxTime: 105, iconPath: "Żywiciel_jak.png", category: 'champion' },
  61.         { name: "Żerca", minTime: 45, maxTime: 75, iconPath: "Żerca.png", category: 'champion' },
  62.         { name: "Żywiciel Jeti", minTime: 60, maxTime: 105, iconPath: "Żywiciel_jeti.png", category: 'champion' },
  63.         { name: "Gnawk", minTime: 120, maxTime: 180, iconPath: "Gnawk.png", category: 'champion' },
  64.         { name: "Mamut", minTime: 120, maxTime: 180, iconPath: "Mamut.png", category: 'champion' },
  65.         { name: "Astronom", minTime: 360, maxTime: 420, iconPath: "Astronom.png", category: 'champion' },
  66.         { name: "Kowal Lugas", minTime: 331, maxTime: 331, iconPath: "Kowal_Lugas.png", category: 'champion' },
  67.         { name: "Straż Lugas", minTime: 331, maxTime: 331, iconPath: "Straż_Lugas.png", category: 'champion' }
  68.     ];
  69.  
  70.     let timers = []; // Globalna tablica aktywnych timerów (lokalnych lub z grupy)
  71.     const timerListUI = document.getElementById("timerList");
  72.     const championSelect = document.getElementById("championSelect");
  73.     const addButton = document.getElementById("addButton");
  74.     const useCustomTimeCheckbox = document.getElementById("useCustomTime");
  75.     const customTimeInput = document.getElementById("customTime");
  76.     const resetButton = document.getElementById("resetButton");
  77.     window.respawnSound = document.getElementById("respawnSound"); // Udostępnienie globalne dla firebase.js
  78.  
  79.     // --- FUNKCJE ZARZĄDZANIA TIMERAMI ---
  80.     window.saveCurrentTimers = function() {
  81.         if (window.currentUser && window.activeGroupId) {
  82.             const groupTimersRef = db.collection("groups").doc(window.activeGroupId);
  83.             const timersToSaveForGroup = timers.map(t => ({
  84.                 name: t.name,
  85.                 minRespawnTime: new Date(t.minRespawnTime).toISOString(),
  86.                 maxRespawnTime: new Date(t.maxRespawnTime).toISOString(),
  87.                 alertPlayed: t.alertPlayed,
  88.                 addedBy: window.currentUser.uid,
  89.                 addedByName: window.currentUser.email.split('@')[0]
  90.             }));
  91.             groupTimersRef.update({ activeTimers: timersToSaveForGroup })
  92.                 .catch(error => console.error("Błąd zapisu timerów grupy:", error));
  93.         } else {
  94.             const timersToSaveLocal = timers.map(t => ({
  95.                 name: t.name,
  96.                 minRespawnTime: new Date(t.minRespawnTime).toISOString(),
  97.                 maxRespawnTime: new Date(t.maxRespawnTime).toISOString(),
  98.                 alertPlayed: t.alertPlayed
  99.             }));
  100.             localStorage.setItem("timers", JSON.stringify(timersToSaveLocal));
  101.         }
  102.     }
  103.    
  104.     window.loadTimers = function() { // Ładuje z localStorage
  105.         const stored = localStorage.getItem("timers");
  106.         timers = [];
  107.         if (stored) {
  108.             const parsed = JSON.parse(stored);
  109.             parsed.forEach(t => {
  110.                 timers.push({
  111.                     name: t.name,
  112.                     minRespawnTime: new Date(t.minRespawnTime),
  113.                     maxRespawnTime: new Date(t.maxRespawnTime),
  114.                     alertPlayed: t.alertPlayed,
  115.                     element: null,
  116.                     timeSpan: null
  117.                 });
  118.             });
  119.         }
  120.         renderFullTimerList();
  121.     }
  122.  
  123. window.loadTimersFromArray = function(timersData) { // Ładuje z danych ( z Firebase)
  124.     timers = [];
  125.     if (timersData && timersData.length > 0) {
  126.         timersData.forEach(t => {
  127.             timers.push({
  128.                 name: t.name,
  129.                 minRespawnTime: new Date(t.minRespawnTime),
  130.                 maxRespawnTime: new Date(t.maxRespawnTime),
  131.                 alertPlayed: t.alertPlayed,
  132.                 element: null,
  133.                 timeSpan: null
  134.             });
  135.         });
  136.     }
  137.     renderFullTimerList();
  138. }
  139.    
  140.     window.clearLocalTimers = function() {
  141.         timers = [];
  142.         renderFullTimerList();
  143.     }
  144.    
  145. function renderFullTimerList() {
  146.     if (!timerListUI) return;
  147.     timerListUI.innerHTML = "";
  148.  
  149.     timers.sort((a, b) => new Date(a.minRespawnTime) - new Date(b.minRespawnTime));
  150.  
  151.     if (timers.length === 0) {
  152.         timerListUI.innerHTML = "<p>Brak aktywnych timerów.</p>";
  153.     } else {
  154.         timers.forEach(timerData => {
  155.             createAndAppendTimerElement(timerData);
  156.         });
  157.     }
  158.     updateTimersTimeDisplayOnly();
  159. }
  160.  
  161.     function createAndAppendTimerElement(timerData) {
  162.         const champion = champions.find(c => c.name === timerData.name);
  163.         if (!champion) return;
  164.  
  165.         const iconUrl = champion.iconPath ? ICON_BASE_URL + champion.iconPath : "";
  166.  
  167.         const timerElement = document.createElement("div");
  168.         timerElement.className = "timer-item";
  169.         timerElement.dataset.timerName = timerData.name;
  170.         if (iconUrl) timerElement.classList.add("with-icon");
  171.  
  172.         const timerContentDiv = document.createElement("div");
  173.         timerContentDiv.className = "timer-item-content";
  174.  
  175.         if (iconUrl) {
  176.             const icon = document.createElement("img");
  177.             icon.src = iconUrl;
  178.             icon.alt = name;
  179.             icon.className = "timer-icon";
  180.             icon.onerror = function() { this.style.display = 'none'; };
  181.             timerElement.appendChild(icon);
  182.         }
  183.  
  184.         const nameSpan = document.createElement("strong");
  185.         nameSpan.textContent = timerData.name;
  186.         timerContentDiv.appendChild(nameSpan);
  187.         timerContentDiv.appendChild(document.createElement("br"));
  188.  
  189.         const timeSpan = document.createElement("span");
  190.         timerContentDiv.appendChild(timeSpan);
  191.         timerElement.appendChild(timerContentDiv);
  192.  
  193.         const deleteButton = document.createElement("button");
  194.         deleteButton.textContent = "Usuń";
  195.         deleteButton.className = "delete-btn";
  196.         deleteButton.onclick = (e) => {
  197.             e.stopPropagation();
  198.             const indexToRemove = timers.findIndex(t => t.name === timerData.name);
  199.             if (indexToRemove > -1) {
  200.                 timers.splice(indexToRemove, 1); // Usuń z tablicy
  201.             }
  202.             timerElement.remove(); // Usuń z DOM
  203.             if (timers.length === 0 && timerListUI) {
  204.                 timerListUI.innerHTML = "<p>Brak aktywnych timerów.</p>";
  205.             }
  206.             window.saveCurrentTimers(); // Zapisz zmiany
  207.         };
  208.         timerElement.appendChild(deleteButton);
  209.  
  210.         timerData.element = timerElement;
  211.         timerData.timeSpan = timeSpan;
  212.  
  213.         timerListUI.appendChild(timerElement);
  214.     }
  215.    
  216.     function addTimerInternal(name, respawnTimes, alertPlayed = false) {
  217.         if (timers.some(t => t.name === name)) return; // Już istnieje, nie dodawaj
  218.  
  219.         const newTimerData = {
  220.             name: name,
  221.             minRespawnTime: respawnTimes.min,
  222.             maxRespawnTime: respawnTimes.max,
  223.             alertPlayed: alertPlayed,
  224.             element: null,
  225.             timeSpan: null
  226.         };
  227.         timers.push(newTimerData);
  228.        
  229.         if (timerListUI && timerListUI.querySelector('p')) { // Usuń "Brak timerów" jeśli było
  230.             timerListUI.innerHTML = "";
  231.         }
  232.         createAndAppendTimerElement(newTimerData); // Stwórz i dodaj do DOM
  233.        
  234.         // Utrzymaj posortowaną listę w DOM
  235.         sortAndReorderDOMList();
  236.         updateTimersTimeDisplayOnly(); // Tylko aktualizuj czasy
  237.     }
  238.  
  239.     function sortAndReorderDOMList() {
  240.         if (!timerListUI || timers.length === 0) return;
  241.        
  242.         timers.sort((a, b) => new Date(a.minRespawnTime) - new Date(b.minRespawnTime));
  243.        
  244.        
  245.         const fragment = document.createDocumentFragment();
  246.         timers.forEach(timer => {
  247.             if (timer.element) { // Upewnij się, że element istnieje
  248.                 fragment.appendChild(timer.element);
  249.             }
  250.         });
  251.         timerListUI.innerHTML = ''; // Wyczyść kontener przed dodaniem posortowanych
  252.         timerListUI.appendChild(fragment);
  253.     }
  254.    
  255.     function addTimerFromUI() {
  256.         const selectedChampionName = championSelect.value;
  257.         if (!selectedChampionName) return alert("Proszę wybrać championa.");
  258.         if (timers.some(t => t.name === selectedChampionName)) return alert("Ten champion jest już na liście!");
  259.        
  260.         const champion = champions.find(c => c.name === selectedChampionName);
  261.         if (!champion) return;
  262.  
  263.         let startTime = new Date();
  264.         if (useCustomTimeCheckbox.checked && customTimeInput.value) {
  265.             const [hours, minutes] = customTimeInput.value.split(":").map(Number);
  266.             if (isNaN(hours) || isNaN(minutes) || hours < 0 || hours > 23 || minutes < 0 || minutes > 59) {
  267.                 return alert("Niepoprawny format własnej godziny. Użyj HH:MM (00:00 - 23:59).");
  268.             }
  269.             startTime.setHours(hours, minutes, 0, 0);
  270.         }
  271.  
  272.         let minRespawnDate, maxRespawnDate;
  273.         if (champion.name === 'Kapłan Śmierci') {
  274.             minRespawnDate = new Date(startTime.getFullYear(), startTime.getMonth(), startTime.getDate(), 16, 0, 0);
  275.             maxRespawnDate = new Date(startTime.getFullYear(), startTime.getMonth(), startTime.getDate(), 22, 0, 0);
  276.             if (startTime > maxRespawnDate) {
  277.                 minRespawnDate.setDate(minRespawnDate.getDate() + 1);
  278.                 maxRespawnDate.setDate(maxRespawnDate.getDate() + 1);
  279.             }
  280.         } else {
  281.             minRespawnDate = new Date(startTime.getTime() + champion.minTime * 60000);
  282.             maxRespawnDate = new Date(startTime.getTime() + champion.maxTime * 60000);
  283.         }
  284.        
  285.         addTimerInternal(champion.name, { min: minRespawnDate, max: maxRespawnDate });
  286.         window.saveCurrentTimers(); // Zapisz stan po dodaniu
  287.     }
  288.  
  289.     function updateTimersTimeDisplayOnly() {
  290.         let stateChanged = false;
  291.  
  292.         timers.forEach(timer => {
  293.             if (!timer.element || !timer.timeSpan) return;
  294.  
  295.             const now = new Date();
  296.             const minRespawn = new Date(timer.minRespawnTime);
  297.             const maxRespawn = new Date(timer.maxRespawnTime);
  298.  
  299.             const timeLeftMin = Math.floor((minRespawn - now) / 1000);
  300.             const timeLeftMax = Math.floor((maxRespawn - now) / 1000);
  301.            
  302.             let previousAlertState = timer.alertPlayed;
  303.             timer.element.classList.remove('window-open');
  304.             let contentHTML;
  305.  
  306.             if (timeLeftMin > 0) {
  307.                 contentHTML = `Okno za: <strong>${Math.floor(timeLeftMin / 60)}:${(timeLeftMin % 60).toString().padStart(2, "0")}</strong>`;
  308.             } else if (timeLeftMax > 0) {
  309.                 contentHTML = `<strong style="color: #6eff7a;">OKNO OTWARTE</strong><br>Koniec za: ${Math.floor(timeLeftMax / 60)}:${(timeLeftMax % 60).toString().padStart(2, "0")}`;
  310.                 timer.element.classList.add('window-open');
  311.                 if (!timer.alertPlayed && window.respawnSound && window.respawnSound.src && window.respawnSound.readyState >= 2) {
  312.                     timer.alertPlayed = true;
  313.                     window.respawnSound.play().catch(err => console.warn("Audio play error:", err));
  314.                 }
  315.             } else {
  316.                 contentHTML = `<span style="color: #ff8c8c;">Okno minęło!</span>`;
  317.             }
  318.      
  319.             if (timer.timeSpan.innerHTML !== contentHTML) {
  320.                 timer.timeSpan.innerHTML = contentHTML;
  321.             }
  322.  
  323.             if (timer.alertPlayed !== previousAlertState) {
  324.                 stateChanged = true;
  325.             }
  326.         });
  327.  
  328.      
  329.         const initialLength = timers.length;
  330.         timers = timers.filter(timer => {
  331.             const isOutdated = (new Date(timer.maxRespawnTime) - new Date()) / 1000 < -180; // 3 minuty po końcu okna
  332.             if (isOutdated && timer.element) {
  333.                 timer.element.remove();
  334.             }
  335.             return !isOutdated;
  336.         });
  337.  
  338.         if (timers.length !== initialLength) { // Jeśli jakieś timery zostały usunięte
  339.             stateChanged = true;
  340.             if (timers.length === 0 && timerListUI && !timerListUI.querySelector('p')) {
  341.                 timerListUI.innerHTML = "<p>Brak aktywnych timerów.</p>";
  342.             }
  343.         }
  344.        
  345.         if (stateChanged) {
  346.             window.saveCurrentTimers(); // Zapisz tylko jeśli stan alertu lub liczba timerów się zmieniła
  347.         }
  348.     }
  349.  
  350.     function populateChampionSelect() {
  351.         if(!championSelect) return;
  352.         championSelect.innerHTML = '<option value="">-- Wybierz Championa --</option>';
  353.         const categories = {
  354.             'event': '--- Eventy Cykliczne ---',
  355.             'boss': '--- Bosy Lotne ---',
  356.             'champion': '--- Chempioni ---'
  357.         };
  358.         for (const category in categories) {
  359.             const optgroup = document.createElement('optgroup');
  360.             optgroup.label = categories[category];
  361.             champions.filter(c => c.category === category)
  362.            
  363.                 .forEach(c => {
  364.                     const option = document.createElement('option');
  365.                     option.value = c.name;
  366.                     option.textContent = `${c.name} ${formatWindowText(c)}`;
  367.                     optgroup.appendChild(option);
  368.                 });
  369.             championSelect.appendChild(optgroup);
  370.         }
  371.     }
  372.  
  373.     function formatWindowText(champ) {
  374.         if (champ.name === 'Kapłan Śmierci') return '(16:00-22:00)';
  375.         if (champ.name === '[Event] Polowanie na Lempo') return '(Aktywny)';
  376.         if (champ.minTime === 0 && champ.maxTime === 0) return '(Brak Timera)';
  377.         if (champ.minTime === champ.maxTime && champ.minTime !==0) return `(${champ.minTime}m)`;
  378.         return `(${champ.minTime}-${champ.maxTime}m)`;
  379.     }
  380.  
  381.     // --- OBSŁUGA USTAWIEŃ DŹWIĘKU ---
  382.     const soundSettingsBtn = document.getElementById("soundSettingsBtn");
  383.     const soundModal = document.getElementById("soundModal");
  384.     const soundSelect = document.getElementById("soundSelect");
  385.     const customSoundContainer = document.getElementById("customSoundContainer");
  386.     const customSoundInput = document.getElementById("customSoundInput");
  387.     const saveSoundBtn = document.getElementById("saveSound");
  388.     const cancelSoundBtn = document.getElementById("cancelSound");
  389.  
  390.     if(soundSettingsBtn && soundModal) soundSettingsBtn.addEventListener("click", () => soundModal.style.display = "block");
  391.     if(cancelSoundBtn && soundModal) cancelSoundBtn.addEventListener("click", () => soundModal.style.display = "none");
  392.     if(soundSelect && customSoundContainer) soundSelect.addEventListener("change", () => {
  393.         customSoundContainer.style.display = (soundSelect.value === "custom") ? "block" : "none";
  394.     });
  395.     if(saveSoundBtn && soundModal && soundSelect && customSoundInput && window.respawnSound) saveSoundBtn.addEventListener("click", () => {
  396.         let soundToSave;
  397.         if (soundSelect.value === "custom" && customSoundInput.files[0]) {
  398.             const file = customSoundInput.files[0];
  399.             if (file.size > 500000) {
  400.                 alert("Plik dźwiękowy jest za duży (max 0.5MB)."); return;
  401.             }
  402.             const reader = new FileReader();
  403.             reader.onload = function(event) {
  404.                 soundToSave = event.target.result;
  405.                 window.respawnSound.src = soundToSave;
  406.                 if (typeof saveUserSetting === 'function' && window.currentUser) saveUserSetting('sound', soundToSave);
  407.                 else localStorage.setItem("notificationSound", soundToSave);
  408.             };
  409.             reader.readAsDataURL(file);
  410.         } else if (soundSelect.value !== "custom") {
  411.             soundToSave = soundSelect.value;
  412.             window.respawnSound.src = soundToSave;
  413.             if (typeof saveUserSetting === 'function' && window.currentUser) saveUserSetting('sound', soundToSave);
  414.             else localStorage.setItem("notificationSound", soundToSave);
  415.         }
  416.         soundModal.style.display = "none";
  417.     });
  418.    
  419.     window.loadNotificationSound = function() {
  420.         const defaultSound = "/Sound/ding-36029.mp3";
  421.         if (!window.currentUser) {
  422.             const savedSound = localStorage.getItem("notificationSound") || defaultSound;
  423.             if (window.respawnSound) window.respawnSound.src = savedSound;
  424.             if (soundSelect) {
  425.                  soundSelect.value = savedSound.startsWith('data:') ? 'custom' : savedSound;
  426.                  if (soundSelect.value === 'custom' && customSoundContainer) customSoundContainer.style.display = 'block';
  427.             }
  428.         }
  429.     }
  430.  
  431.     // --- OBSŁUGA USTAWIEŃ TŁA ---
  432.     const backgroundSettingsBtn = document.getElementById('backgroundSettingsBtn');
  433.     const backgroundModal = document.getElementById('backgroundModal');
  434.     const backgroundOptionsContainer = document.getElementById('background-options-container');
  435.     const saveBackgroundBtn = document.getElementById('saveBackground');
  436.     const cancelBackgroundBtn = document.getElementById('cancelBackground');
  437.     let UIAselectedBackgroundPath = '';
  438.  
  439.     const backgrounds = {
  440.         'Zgliszcza Taernu': 'Grafiki/tlo666.png',
  441.         'Mglista Przełęcz': 'Grafiki/tlo2.png',
  442.         'Deszczowy Rynek': 'Grafiki/tlo3.png',
  443.         'Wejście do Ruin': 'Grafiki/tlo4.png'
  444.     };
  445.     const defaultBackground = backgrounds['Zgliszcza Taernu'];
  446.  
  447.     window.applyBackground = function(path) {
  448.         document.body.style.backgroundImage = `url('${path}')`;
  449.     }
  450.  
  451.     function populateBackgroundOptions() {
  452.         if(!backgroundOptionsContainer) return;
  453.         backgroundOptionsContainer.innerHTML = '';
  454.         let currentEffectiveBackground = defaultBackground;
  455.         if(window.currentUser) {
  456.             const bodyBg = document.body.style.backgroundImage;
  457.             if (bodyBg && bodyBg.includes('url("')) {
  458.                 currentEffectiveBackground = bodyBg.split('url("')[1].split('")')[0];
  459.             }
  460.         } else {
  461.             currentEffectiveBackground = localStorage.getItem('appBackground') || defaultBackground;
  462.         }
  463.         UIAselectedBackgroundPath = currentEffectiveBackground;
  464.  
  465.         for (const name in backgrounds) {
  466.             const path = backgrounds[name];
  467.             const thumb = document.createElement('div');
  468.             thumb.className = 'background-thumbnail';
  469.             thumb.style.backgroundImage = `url('${path}')`;
  470.             thumb.dataset.path = path;
  471.             thumb.title = name;
  472.             if (path === currentEffectiveBackground) thumb.classList.add('selected');
  473.            
  474.             thumb.addEventListener('click', () => {
  475.                 backgroundOptionsContainer.querySelectorAll('.background-thumbnail.selected').forEach(s => s.classList.remove('selected'));
  476.                 thumb.classList.add('selected');
  477.                 UIAselectedBackgroundPath = path;
  478.             });
  479.             backgroundOptionsContainer.appendChild(thumb);
  480.         }
  481.     }
  482.    
  483.     if(backgroundSettingsBtn && backgroundModal) backgroundSettingsBtn.addEventListener('click', () => {
  484.         populateBackgroundOptions();
  485.         backgroundModal.style.display = 'block';
  486.     });
  487.     if(cancelBackgroundBtn && backgroundModal) cancelBackgroundBtn.addEventListener('click', () => backgroundModal.style.display = 'none');
  488.     if(saveBackgroundBtn && backgroundModal) saveBackgroundBtn.addEventListener('click', () => {
  489.         if (UIAselectedBackgroundPath) {
  490.             applyBackground(UIAselectedBackgroundPath);
  491.             if (typeof saveUserSetting === 'function' && window.currentUser) saveUserSetting('background', UIAselectedBackgroundPath);
  492.             else localStorage.setItem('appBackground', UIAselectedBackgroundPath);
  493.         }
  494.         backgroundModal.style.display = 'none';
  495.     });
  496.  
  497.     window.loadSavedBackground = function() {
  498.         if (!window.currentUser) {
  499.             const savedPath = localStorage.getItem('appBackground') || defaultBackground;
  500.             applyBackground(savedPath);
  501.         }
  502.     }
  503.  
  504.     // --- LISTENERY I INICJALIZACJA ---
  505.     if(addButton) addButton.addEventListener("click", addTimerFromUI);
  506.     if(resetButton) resetButton.addEventListener("click", () => {
  507.         if (confirm("Czy na pewno chcesz zresetować WSZYSTKIE timery dla obecnego kontekstu (" + (document.getElementById('currentTimerContext')?.textContent || 'Lokalne') + ")?")) {
  508.             timers = [];
  509.             renderFullTimerList(); // Wyrenderuje pustą listę i wywoła save
  510.         }
  511.     });
  512.     if(useCustomTimeCheckbox && customTimeInput) useCustomTimeCheckbox.addEventListener("change", () => {
  513.         customTimeInput.disabled = !useCustomTimeCheckbox.checked;
  514.         if (!useCustomTimeCheckbox.checked) customTimeInput.value = "";
  515.     });
  516.  
  517.     populateChampionSelect();
  518.    
  519.     // Główna pętla aktualizacji TYLKO CZASU w timerach
  520.     setInterval(updateTimersTimeDisplayOnly, 1000);
  521. });
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement