Luigit
repositories / dotfiles

dotfiles

bugabingas dorkfiles

owned by admin

quickshell/nuguland/Time.qml

Raw
import QtQuick

Item {
    id: root

    property date now: new Date()
    property string compact: formatClock(now).display
    readonly property var weekdays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
    readonly property var monthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]

    function pad(value) {
        return value < 10 ? `0${value}` : `${value}`;
    }

    function parsed(iso) {
        return new Date(String(iso));
    }

    function formatClock(value) {
        const hour = value.getHours();
        const minute = value.getMinutes();
        const second = value.getSeconds();
        return {
            "hour": hour,
            "minute": minute,
            "second": second,
            "display": `${pad(hour)}:${pad(minute)}`,
            "statusDisplay": `${pad(hour)}:${pad(minute)}:${pad(second)}`
        };
    }

    function odometerClock(value) {
        const display = formatClock(value).display;
        const cells = [];
        const chars = display.split("");
        for (let i = 0; i < chars.length; i++) {
            const ch = chars[i];
            const digit = ch >= "0" && ch <= "9";
            cells.push(digit ? {
                "kind": "digit",
                "value": Number(ch),
                "motion": "vertical-digit-roll"
            } : {
                "kind": "separator",
                "value": ch,
                "hard": true
            });
        }
        return {
            "source": "Nuguland Clock.qml ClockNumber.qml",
            "ownedBy": "Bar.qml",
            "display": display,
            "motion": "vertical-digit-roll",
            "font": "IBM Plex Mono",
            "hardSeparators": [":"],
            "noGlow": true,
            "settingsBacked": false,
            "cells": cells
        };
    }

    function formatDate(value) {
        const year = value.getFullYear();
        const month = value.getMonth() + 1;
        const day = value.getDate();
        const weekday = weekdays[value.getDay()];
        const monthName = monthNames[month - 1];
        return {
            "year": year,
            "month": month,
            "day": day,
            "weekday": weekday,
            "monthName": monthName,
            "isoDay": isoDay(value),
            "line": `${weekday} ${day} ${monthName}`
        };
    }

    function isoDay(value) {
        return `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}`;
    }

    function relativeText(fromDate, toDate) {
        const seconds = Math.max(0, Math.floor((toDate.getTime() - fromDate.getTime()) / 1000));
        if (seconds < 10)
            return "now";

        if (seconds < 60)
            return `${seconds}s ago`;

        const minutes = Math.floor(seconds / 60);
        if (minutes < 60)
            return `${minutes}m ago`;

        const hours = Math.floor(minutes / 60);
        if (hours < 24)
            return `${hours}h ago`;

        return `${Math.floor(hours / 24)}d ago`;
    }

    function personalAgenda(value) {
        return [
            {
                "id": "nuguland-focus",
                "title": "Nuguland focus",
                "time": `${formatClock(value).display}`,
                "source": "personal-constant",
                "role": "ui.accent"
            }
        ];
    }

    function stateObject(value) {
        return {
            "backend": "Time.qml",
            "source": "shared-service-timer",
            "widgetProcesses": "forbidden",
            "helperProcesses": [],
            "font": "IBM Plex Mono",
            "timezone": "local",
            "iso": value.toISOString(),
            "clock": formatClock(value),
            "odometerClock": odometerClock(value),
            "date": formatDate(value),
            "relativeSamples": {
                "minute": relativeText(new Date(value.getTime() - 60000), value),
                "hour": relativeText(new Date(value.getTime() - 3.6e+06), value)
            },
            "agenda": personalAgenda(value)
        };
    }

    function stateJson() {
        return JSON.stringify(stateObject(now));
    }

    function stateAt(iso) {
        return JSON.stringify(stateObject(parsed(iso)));
    }

    function relative(fromIso, toIso) {
        const fromDate = parsed(fromIso);
        const toDate = parsed(toIso);
        return JSON.stringify({
            "backend": "Time.qml",
            "from": fromDate.toISOString(),
            "to": toDate.toISOString(),
            "text": relativeText(fromDate, toDate)
        });
    }

    function calendar(year, month, selectedDay) {
        const first = new Date(year, month - 1, 1);
        const mondayOffset = (first.getDay() + 6) % 7;
        const cursor = new Date(first.getFullYear(), first.getMonth(), first.getDate() - mondayOffset);
        const todayIso = `${year}-${pad(month)}-${pad(selectedDay)}`;
        const weeks = [];
        for (let week = 0; week < 6; week++) {
            const days = [];
            for (let day = 0; day < 7; day++) {
                const current = new Date(cursor.getTime());
                const inMonth = current.getMonth() === month - 1;
                const currentDay = current.getDate();
                const currentIso = isoDay(current);
                days.push({
                    "iso": currentIso,
                    "day": currentDay,
                    "inMonth": inMonth,
                    "selected": inMonth && currentDay === selectedDay,
                    "today": currentIso === todayIso
                });
                cursor.setDate(cursor.getDate() + 1);
            }
            weeks.push(days);
        }
        return JSON.stringify({
            "backend": "Time.qml",
            "year": year,
            "month": month,
            "selectedDay": selectedDay,
            "weekStartsOn": "Mon",
            "weeks": weeks
        });
    }

    Timer {
        interval: 1000
        running: true
        repeat: true
        onTriggered: root.now = new Date()
    }
}