Skip to content
Merged
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
194 changes: 108 additions & 86 deletions qml/CalendarGrid.qml
Original file line number Diff line number Diff line change
Expand Up @@ -4,64 +4,127 @@ import QtQuick.Controls 2.15
import "qrc:/qml/"

// CalendarGrid.qml
GridLayout {
id: calendarGrid
columns: 7
rowSpacing: 0
columnSpacing: 0
ColumnLayout {
id: calendarGridRoot
Layout.fillWidth: true
Layout.fillHeight: true
Layout.margins: 20
Layout.topMargin: 10

// Properties
property alias calendarModel: repeater.model
property alias eventListModel: eventLabel.eventModel
property var theme

// Signals
signal dayClicked(var panchanga)

Repeater {
id: repeater
delegate: Item {
Layout.fillWidth: true
Layout.fillHeight: modelData.type === "day" || modelData.type === "empty"
Layout.preferredHeight: modelData.type === "header" ? 35 : -1
// Components

Loader {
id: delegateLoader
anchors.fill: parent
// Calendar grid layout
GridLayout {
id: calendarGrid
columns: 7
rowSpacing: 0
columnSpacing: 0
Layout.fillWidth: true
Layout.preferredHeight: parent.width
Layout.margins: 10
Layout.topMargin: 10

Repeater {
id: repeater
delegate: Item {
Layout.fillWidth: true
Layout.fillHeight: modelData.type === "day" || modelData.type === "empty"
Layout.preferredHeight: modelData.type === "header" ? 35 : -1

Loader {
id: delegateLoader
anchors.fill: parent

sourceComponent: {
if (modelData.type === "header") {
return headerComponent;
} else if (modelData.type === "day") {
return dayComponent;
} else {
return emptyComponent;
}
}

onLoaded: {
if (modelData.type === "day") {
item.bsDay = modelData.bsDay;
item.adDay = modelData.adDay;
item.tithi = modelData.tithi;
item.isToday = modelData.isToday;
item.isSaturday = modelData.isSaturday;
item.hasEvent = modelData.hasEvent;
item.theme = calendarGridRoot.theme;

var isHoliday = false;
if (modelData.panchanga && modelData.panchanga.events) {
for (var i = 0; i < modelData.panchanga.events.length; i++) {
if (modelData.panchanga.events[i].holiday) {
isHoliday = true;
break;
}
}
}
item.isHoliday = isHoliday;

sourceComponent: {
if (modelData.type === "header") {
return headerComponent;
} else if (modelData.type === "day") {
return dayComponent;
} else { // for "empty" type
return emptyComponent;
item.clicked.connect(function() {
calendarGridRoot.dayClicked(modelData.panchanga)
});
} else if (modelData.type === "header") {
item.text = modelData.text;
item.theme = calendarGridRoot.theme;
item.cellIndex = index;
}
}
}
}
}
}

// Event List Footer
Rectangle {
id: eventFooter
Layout.fillWidth: true
implicitHeight: eventLabel.paintedHeight + 20
color: theme.secondaryBg
radius: 6
visible: eventLabel.eventModel && eventLabel.eventModel.length > 0

Label {
id: eventLabel
anchors.fill: parent
anchors.margins: 10

property var eventModel: [] // Model reference

onLoaded: {
if (modelData.type === "day") {
item.bsDay = modelData.bsDay;
item.adDay = modelData.adDay;
item.tithi = modelData.tithi;
item.isToday = modelData.isToday;
item.isSaturday = modelData.isSaturday;
item.theme = calendarGrid.theme;
item.clicked.connect(function() {
calendarGrid.dayClicked(modelData.panchanga)
});
} else if (modelData.type === "header") {
item.text = modelData.text;
item.theme = calendarGrid.theme;
item.cellIndex = index;
text: {
var str = "";
if (eventModel) {
for (var i = 0; i < eventModel.length; i++) {
var item = eventModel[i];
str += item.bsDay + " :\u00A0" + item.eventName;
if (i < eventModel.length - 1) {
str += "  •  ";
}
}
}
return str;
}

font.pixelSize: 12
color: theme ? theme.secondaryText : "black"
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}


// Component Definitions
Component {
id: headerComponent
Item {
Expand All @@ -78,56 +141,15 @@ GridLayout {
border.color: theme.borderColor
}

Rectangle {
visible: cellIndex === 0
width: headerBackground.radius
height: headerBackground.radius
color: headerBackground.color
anchors.top: parent.top
anchors.right: parent.right
}
Rectangle {
visible: cellIndex === 0
width: headerBackground.radius
height: headerBackground.radius
color: headerBackground.color
anchors.bottom: parent.bottom
anchors.left: parent.left
}
Rectangle {
visible: cellIndex === 6
width: headerBackground.radius
height: headerBackground.radius
color: headerBackground.color
anchors.top: parent.top
anchors.left: parent.left
}
Rectangle {
visible: cellIndex === 6
width: headerBackground.radius
height: headerBackground.radius
color: headerBackground.color
anchors.bottom: parent.bottom
anchors.left: parent.left
}
Rectangle {
visible: cellIndex === 0 || cellIndex === 6
width: headerBackground.radius
height: headerBackground.radius
color: headerBackground.color
anchors.bottom: parent.bottom
anchors.right: parent.right
}
Rectangle { visible: cellIndex === 0; width: headerBackground.radius; height: headerBackground.radius; color: headerBackground.color; anchors.top: parent.top; anchors.right: parent.right }
Rectangle { visible: cellIndex === 0; width: headerBackground.radius; height: headerBackground.radius; color: headerBackground.color; anchors.bottom: parent.bottom; anchors.left: parent.left }
Rectangle { visible: cellIndex === 6; width: headerBackground.radius; height: headerBackground.radius; color: headerBackground.color; anchors.top: parent.top; anchors.left: parent.left }
Rectangle { visible: cellIndex === 6; width: headerBackground.radius; height: headerBackground.radius; color: headerBackground.color; anchors.bottom: parent.bottom; anchors.left: parent.left }
Rectangle { visible: cellIndex === 0 || cellIndex === 6; width: headerBackground.radius; height: headerBackground.radius; color: headerBackground.color; anchors.bottom: parent.bottom; anchors.right: parent.right }

Label {
text: headerItemContainer.text
color: {
if (cellIndex === 6) {
return "#E4080A"
} else {
return theme.accentText;
}
}
color: (cellIndex === 6) ? "#E4080A" : theme.accentText
font.bold: true
font.pixelSize: 14
anchors.centerIn: parent
Expand Down
52 changes: 39 additions & 13 deletions qml/CalendarLogic.qml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ QtObject {
property int currentBsYear: 2081
property int currentBsMonthIndex: 1
property var calendarModel: []
property var currentMonthEvents: [] // Holds events for the current month
property string currentBsLabelStr: ""
property string currentAdLabelStr: ""
property string prevMonthName: ""
Expand Down Expand Up @@ -59,7 +60,9 @@ QtObject {
}

function renderCalendarByBs(year, monthIndex, preserveAdState = false) {
calendarModel = [];
var newCalendarModel = [];
var eventsByDay = {}; // Use an object to group events by day

currentBsYear = year;
currentBsMonthIndex = monthIndex;
var info = Panchanga.getBikramMonthInfo(year, monthIndex);
Expand All @@ -69,23 +72,18 @@ QtObject {
}

if (!preserveAdState) {
// LOGIC to determine the representative AD month
var bsMonthStartDate = Panchanga.fromBikramSambat(year, monthIndex, 1);
var startAdYear = bsMonthStartDate.getUTCFullYear();
var startAdMonth = bsMonthStartDate.getUTCMonth();

var nextAdMonth = (startAdMonth + 1) % 12;
var nextAdYear = (startAdMonth === 11) ? startAdYear + 1 : startAdYear;
var firstOfNextAdMonth = new Date(Date.UTC(nextAdYear, nextAdMonth, 1));

var bsMonthEndDate = Panchanga.fromBikramSambat(year, monthIndex, info.totalDays);

if (firstOfNextAdMonth <= bsMonthEndDate) {
// Prefer the later AD month if its first day is in the BS month.
currentAdYear = nextAdYear;
currentAdMonth = nextAdMonth;
} else {
// Otherwise, use the starting AD month.
currentAdYear = startAdYear;
currentAdMonth = startAdMonth;
}
Expand All @@ -98,13 +96,12 @@ QtObject {

var daysInMonth = info.totalDays;
var startDay = info.startDayOfWeek;
var model = [];
var weekdaysNe = ["आइतबार", "सोमबार", "मङ्गलबार", "बुधबार", "बिहीबार", "शुक्रबार", "शनिबार"];
for (var i = 0; i < 7; ++i) {
model.push({ type: "header", text: weekdaysNe[i] });
newCalendarModel.push({ type: "header", text: weekdaysNe[i] });
}
for (i = 0; i < startDay; ++i) {
model.push({ type: "empty" });
newCalendarModel.push({ type: "empty" });
}
for (var day = 1; day <= daysInMonth; ++day) {
var adDate = Panchanga.fromBikramSambat(year, monthIndex, day);
Expand All @@ -114,14 +111,45 @@ QtObject {
}
var isToday = adDate.toDateString() === new Date().toDateString();
var isSaturday = (startDay + day - 1) % 7 === 6;
var hasEventForDay = result.events && result.events.length > 0;

if (hasEventForDay) {
var devanagariDay = toDevanagari(day);
if (!eventsByDay[devanagariDay]) {
eventsByDay[devanagariDay] = []; // Initialize array if it doesn't exist
}
for (var j = 0; j < result.events.length; j++) {
eventsByDay[devanagariDay].push(result.events[j].name);
}
}

result.monthName = info.monthName;
model.push({
newCalendarModel.push({
type: "day", bsDay: day, adDay: adDate.getDate(),
tithi: result.tithi, isToday: isToday, isSaturday: isSaturday,
hasEvent: hasEventForDay,
gregorianDate: result.gregorianDate, panchanga: result
});
}
calendarModel = model;

// Process the grouped events
var newMonthEvents = [];
// Sort the days to ensure events are listed in chronological order
var sortedDays = Object.keys(eventsByDay).sort(function(a, b) {
return parseInt(fromDevanagari(a)) - parseInt(fromDevanagari(b));
});

for (i = 0; i < sortedDays.length; i++) {
var bsDay = sortedDays[i];
newMonthEvents.push({
bsDay: bsDay,
eventName: eventsByDay[bsDay].join(", ")
});
}

calendarModel = newCalendarModel;
currentMonthEvents = newMonthEvents;

currentBsLabelStr = toDevanagari(year) + " " + info.monthName;
currentAdLabelStr = getGregorianRange(year, monthIndex);
var prevMonthIndex = monthIndex - 1;
Expand All @@ -143,10 +171,8 @@ QtObject {
function renderCalendarByAd(year, monthIndex) {
currentAdYear = year;
currentAdMonth = monthIndex;

var date = new Date(Date.UTC(year, monthIndex, 1));
var bsInfo = Panchanga.calculate(date);

renderCalendarByBs(bsInfo.bsYear, bsInfo.bsMonthIndex, true);
}

Expand Down
Loading
Loading