TimerHooker Android MD3 Version

Speeds up countdown timers with a fully movable UI designed for Android screens.

Ekde 2025/04/03. Vidu La ĝisdata versio.

// ==UserScript==
// @name            TimerHooker Android MD3 Version
// @version         2.3.0
// @description     Speeds up countdown timers with a fully movable UI designed for Android screens.
// @include         *
// @author          Govindarajulu
// @match           http://*/*
// @run-at          document-start
// @grant           none
// @license         GPL-3.0-or-later
// @namespace https://greasyfork.org/users/1356925
// ==/UserScript==

(function (global) {
    let isSpeedActive = false;
    const speedMultiplier = 50;
    let autoHideTimeout;

    function overrideTimers(factor) {
        ["setTimeout", "setInterval"].forEach((method) => {
            window[method] = ((original) => (fn, time) => original(fn, time / factor))(window[method]);
        });
    }

    const TimerHooker = {
        toggleSpeed: function () {
            isSpeedActive = !isSpeedActive;
            overrideTimers(isSpeedActive ? speedMultiplier : 1);

            const btn = document.getElementById("toggleSpeedBtn");
            if (btn) btn.textContent = isSpeedActive ? "Stop" : "Speed";

            console.log(`[TimerHooker] Countdown timers accelerated: x${isSpeedActive ? speedMultiplier : 1}`);
            TimerHooker.resetAutoHide(); // Reset hide timer when toggled
        },

        createUI: function () {
            if (document.getElementById("timerHookerUI")) return;

            const speedControl = document.createElement("div");
            speedControl.id = "timerHookerUI";
            speedControl.style = `
                position: fixed; top: 50%; left: -35px; z-index: 99999;
                background: rgba(0,0,0,0.3); color: white; padding: 6px 12px; border-radius: 40px;
                font-size: 12px; font-weight: 500; text-align: center; cursor: grab;
                backdrop-filter: blur(8px); box-shadow: 0px 3px 8px rgba(0,0,0,0.2);
                user-select: none; transition: left 0.3s ease, top 0.1s ease, background 0.3s ease, color 0.3s ease;
                touch-action: none;
            `;

            speedControl.textContent = "Speed";
            speedControl.id = "toggleSpeedBtn";
            speedControl.addEventListener("click", () => {
                speedControl.style.left = "10px"; // Bring button fully into view
                TimerHooker.toggleSpeed();
            });

            // Enable **touch-based dragging** across Android screens
            let startX, startY, isDragging = false;

            speedControl.addEventListener("touchstart", (e) => {
                isDragging = true;
                clearTimeout(autoHideTimeout); // Stop auto-hide when dragged
                const touch = e.touches[0];
                startX = touch.clientX - speedControl.getBoundingClientRect().left;
                startY = touch.clientY - speedControl.getBoundingClientRect().top;
                speedControl.style.cursor = "grabbing";
            });

            document.addEventListener("touchmove", (e) => {
                if (!isDragging) return;
                const touch = e.touches[0];

                speedControl.style.left = `${Math.min(window.innerWidth - speedControl.offsetWidth, Math.max(0, touch.clientX - startX))}px`;
                speedControl.style.top = `${Math.min(window.innerHeight - speedControl.offsetHeight, Math.max(0, touch.clientY - startY))}px`;
            });

            document.addEventListener("touchend", () => {
                isDragging = false;
                speedControl.style.cursor = "grab";
                TimerHooker.resetAutoHide(); // Start hiding after movement stops
            });

            document.body.appendChild(speedControl);
            TimerHooker.resetAutoHide();
            console.log("[TimerHooker] UI optimized for Android successfully.");
        },

        resetAutoHide: function () {
            clearTimeout(autoHideTimeout);
            autoHideTimeout = setTimeout(() => {
                const speedControl = document.getElementById("timerHookerUI");
                if (!isDragging) speedControl.style.left = "-35px"; // Move button back to sideline
            }, 3000);
        },

        handleFullscreen: function () {
            document.addEventListener("fullscreenchange", () => {
                const speedControl = document.getElementById("timerHookerUI");
                if (document.fullscreenElement) {
                    speedControl.style.display = "none"; // Hide in fullscreen mode
                } else {
                    speedControl.style.display = "block"; // Show when fullscreen exits
                }
            });
        },

        init: function () {
            console.log("[TimerHooker] Android MD3 version activated");
            this.createUI();
            this.handleFullscreen();
        }
    };

    if (document.readyState === "complete") {
        TimerHooker.init();
    } else {
        window.addEventListener("load", () => TimerHooker.init());
    }
})(window);