|  | 
|  | 1 | +import QtQuick 2.15 | 
|  | 2 | +import "qrc:/PanchangaCalculator.js" as Panchanga | 
|  | 3 | + | 
|  | 4 | +// CalendarLogic.qml | 
|  | 5 | +QtObject { | 
|  | 6 | +    id: calendarLogic | 
|  | 7 | + | 
|  | 8 | +    // State Properties | 
|  | 9 | +    property int currentAdYear: new Date().getFullYear() | 
|  | 10 | +    property int currentAdMonth: new Date().getMonth() | 
|  | 11 | +    property string prevAdMonthName: "" | 
|  | 12 | +    property string nextAdMonthName: "" | 
|  | 13 | + | 
|  | 14 | +    property int currentBsYear: 2081 | 
|  | 15 | +    property int currentBsMonthIndex: 1 | 
|  | 16 | +    property var calendarModel: [] | 
|  | 17 | +    property string currentBsLabelStr: "" | 
|  | 18 | +    property string currentAdLabelStr: "" | 
|  | 19 | +    property string prevMonthName: "" | 
|  | 20 | +    property string nextMonthName: "" | 
|  | 21 | +    property bool isCurrentMonthComputed: false | 
|  | 22 | + | 
|  | 23 | + | 
|  | 24 | +    function toDevanagari(num) { | 
|  | 25 | +        return Panchanga.toDevanagari(String(num)) | 
|  | 26 | +    } | 
|  | 27 | + | 
|  | 28 | +    function fromDevanagari(devanagariStr) { | 
|  | 29 | +        if (typeof devanagariStr !== 'string') return ""; | 
|  | 30 | +        const digitMap = { | 
|  | 31 | +            '०': '0', '१': '1', '२': '2', '३': '3', '४': '4', | 
|  | 32 | +            '५': '5', '६': '6', '७': '7', '८': '8', '९': '9' | 
|  | 33 | +        }; | 
|  | 34 | +        return devanagariStr.replace(/[०-९]/g, (match) => digitMap[match]); | 
|  | 35 | +    } | 
|  | 36 | + | 
|  | 37 | +    function initializeApp() { | 
|  | 38 | +        var today = new Date(); | 
|  | 39 | +        var bsInfo = Panchanga.calculate(today); | 
|  | 40 | +        renderCalendarByBs(bsInfo.bsYear, bsInfo.bsMonthIndex); | 
|  | 41 | +    } | 
|  | 42 | + | 
|  | 43 | +    function getGregorianRange(bsYear, monthIndex) { | 
|  | 44 | +        var first = Panchanga.fromBikramSambat(bsYear, monthIndex, 1); | 
|  | 45 | +        var info = Panchanga.getBikramMonthInfo(bsYear, monthIndex); | 
|  | 46 | +        var last = Panchanga.fromBikramSambat(bsYear, monthIndex, info.totalDays); | 
|  | 47 | +        var firstMonth = Panchanga.nepaliGregorianMonths[first.getUTCMonth()]; | 
|  | 48 | +        var lastMonth = Panchanga.nepaliGregorianMonths[last.getUTCMonth()]; | 
|  | 49 | +        var firstYear = first.getUTCFullYear(); | 
|  | 50 | +        var lastYear = last.getUTCFullYear(); | 
|  | 51 | + | 
|  | 52 | +        if (firstYear !== lastYear) { | 
|  | 53 | +            return firstMonth + " " + firstYear + " – " + lastMonth + " " + lastYear; | 
|  | 54 | +        } else if (firstMonth !== lastMonth) { | 
|  | 55 | +            return firstMonth + " - " + lastMonth + " " + firstYear; | 
|  | 56 | +        } else { | 
|  | 57 | +            return firstMonth + " " + firstYear; | 
|  | 58 | +        } | 
|  | 59 | +    } | 
|  | 60 | + | 
|  | 61 | +    function renderCalendarByBs(year, monthIndex, preserveAdState = false) { | 
|  | 62 | +        calendarModel = []; | 
|  | 63 | +        currentBsYear = year; | 
|  | 64 | +        currentBsMonthIndex = monthIndex; | 
|  | 65 | +        var info = Panchanga.getBikramMonthInfo(year, monthIndex); | 
|  | 66 | +        if (!info) { | 
|  | 67 | +            console.error("Failed to get Bikram month info for", year, monthIndex); | 
|  | 68 | +            return; | 
|  | 69 | +        } | 
|  | 70 | + | 
|  | 71 | +        if (!preserveAdState) { | 
|  | 72 | +            // LOGIC to determine the representative AD month | 
|  | 73 | +            var bsMonthStartDate = Panchanga.fromBikramSambat(year, monthIndex, 1); | 
|  | 74 | +            var startAdYear = bsMonthStartDate.getUTCFullYear(); | 
|  | 75 | +            var startAdMonth = bsMonthStartDate.getUTCMonth(); | 
|  | 76 | + | 
|  | 77 | +            var nextAdMonth = (startAdMonth + 1) % 12; | 
|  | 78 | +            var nextAdYear = (startAdMonth === 11) ? startAdYear + 1 : startAdYear; | 
|  | 79 | +            var firstOfNextAdMonth = new Date(Date.UTC(nextAdYear, nextAdMonth, 1)); | 
|  | 80 | + | 
|  | 81 | +            var bsMonthEndDate = Panchanga.fromBikramSambat(year, monthIndex, info.totalDays); | 
|  | 82 | + | 
|  | 83 | +            if (firstOfNextAdMonth <= bsMonthEndDate) { | 
|  | 84 | +                // Prefer the later AD month if its first day is in the BS month. | 
|  | 85 | +                currentAdYear = nextAdYear; | 
|  | 86 | +                currentAdMonth = nextAdMonth; | 
|  | 87 | +            } else { | 
|  | 88 | +                // Otherwise, use the starting AD month. | 
|  | 89 | +                currentAdYear = startAdYear; | 
|  | 90 | +                currentAdMonth = startAdMonth; | 
|  | 91 | +            } | 
|  | 92 | +        } | 
|  | 93 | + | 
|  | 94 | +        var prevAdMonthIndex = (currentAdMonth - 1 + 12) % 12; | 
|  | 95 | +        var nextAdMonthIndex = (currentAdMonth + 1) % 12; | 
|  | 96 | +        prevAdMonthName = Panchanga.nepaliGregorianMonths[prevAdMonthIndex]; | 
|  | 97 | +        nextAdMonthName = Panchanga.nepaliGregorianMonths[nextAdMonthIndex]; | 
|  | 98 | + | 
|  | 99 | +        var daysInMonth = info.totalDays; | 
|  | 100 | +        var startDay = info.startDayOfWeek; | 
|  | 101 | +        var model = []; | 
|  | 102 | +        var weekdaysNe = ["आइतबार", "सोमबार", "मङ्गलबार", "बुधबार", "बिहीबार", "शुक्रबार", "शनिबार"]; | 
|  | 103 | +        for (var i = 0; i < 7; ++i) { | 
|  | 104 | +            model.push({ type: "header", text: weekdaysNe[i] }); | 
|  | 105 | +        } | 
|  | 106 | +        for (i = 0; i < startDay; ++i) { | 
|  | 107 | +            model.push({ type: "empty" }); | 
|  | 108 | +        } | 
|  | 109 | +        for (var day = 1; day <= daysInMonth; ++day) { | 
|  | 110 | +            var adDate = Panchanga.fromBikramSambat(year, monthIndex, day); | 
|  | 111 | +            var result = Panchanga.calculate(adDate); | 
|  | 112 | +            if (day === 1) { | 
|  | 113 | +                isCurrentMonthComputed = result.isComputed; | 
|  | 114 | +            } | 
|  | 115 | +            var isToday = adDate.toDateString() === new Date().toDateString(); | 
|  | 116 | +            var isSaturday = (startDay + day - 1) % 7 === 6; | 
|  | 117 | +            result.monthName = info.monthName; | 
|  | 118 | +            model.push({ | 
|  | 119 | +                type: "day", bsDay: day, adDay: adDate.getDate(), | 
|  | 120 | +                tithi: result.tithi, isToday: isToday, isSaturday: isSaturday, | 
|  | 121 | +                gregorianDate: result.gregorianDate, panchanga: result | 
|  | 122 | +            }); | 
|  | 123 | +        } | 
|  | 124 | +        calendarModel = model; | 
|  | 125 | +        currentBsLabelStr = toDevanagari(year) + " " + info.monthName; | 
|  | 126 | +        currentAdLabelStr = getGregorianRange(year, monthIndex); | 
|  | 127 | +        var prevMonthIndex = monthIndex - 1; | 
|  | 128 | +        var prevYear = year; | 
|  | 129 | +        if (prevMonthIndex < 0) { | 
|  | 130 | +            prevMonthIndex = 11; | 
|  | 131 | +            prevYear--; | 
|  | 132 | +        } | 
|  | 133 | +        prevMonthName = Panchanga.solarMonths[prevMonthIndex] || ""; | 
|  | 134 | +        var nextMonthIndex = monthIndex + 1; | 
|  | 135 | +        var nextYear = year; | 
|  | 136 | +        if (nextMonthIndex > 11) { | 
|  | 137 | +            nextMonthIndex = 0; | 
|  | 138 | +            nextYear++; | 
|  | 139 | +        } | 
|  | 140 | +        nextMonthName = Panchanga.solarMonths[nextMonthIndex] || ""; | 
|  | 141 | +    } | 
|  | 142 | + | 
|  | 143 | +    function renderCalendarByAd(year, monthIndex) { | 
|  | 144 | +        currentAdYear = year; | 
|  | 145 | +        currentAdMonth = monthIndex; | 
|  | 146 | + | 
|  | 147 | +        var date = new Date(Date.UTC(year, monthIndex, 1)); | 
|  | 148 | +        var bsInfo = Panchanga.calculate(date); | 
|  | 149 | + | 
|  | 150 | +        renderCalendarByBs(bsInfo.bsYear, bsInfo.bsMonthIndex, true); | 
|  | 151 | +    } | 
|  | 152 | + | 
|  | 153 | +    function navigateBsMonth(direction) { | 
|  | 154 | +        var newMonth = currentBsMonthIndex + direction; | 
|  | 155 | +        var newYear = currentBsYear; | 
|  | 156 | +        if (newMonth > 11) { | 
|  | 157 | +            newMonth = 0; | 
|  | 158 | +            newYear++; | 
|  | 159 | +        } else if (newMonth < 0) { | 
|  | 160 | +            newMonth = 11; | 
|  | 161 | +            newYear--; | 
|  | 162 | +        } | 
|  | 163 | +        renderCalendarByBs(newYear, newMonth); | 
|  | 164 | +    } | 
|  | 165 | + | 
|  | 166 | +    function navigateAdMonth(direction) { | 
|  | 167 | +        var newAdMonth = currentAdMonth + direction; | 
|  | 168 | +        var newAdYear = currentAdYear; | 
|  | 169 | +        if (newAdMonth > 11) { | 
|  | 170 | +            newAdMonth = 0; | 
|  | 171 | +            newAdYear++; | 
|  | 172 | +        } else if (newAdMonth < 0) { | 
|  | 173 | +            newAdMonth = 11; | 
|  | 174 | +            newAdYear--; | 
|  | 175 | +        } | 
|  | 176 | +        renderCalendarByAd(newAdYear, newAdMonth); | 
|  | 177 | +    } | 
|  | 178 | +} | 
0 commit comments