Commit 78efabab authored by Claudio Cambra's avatar Claudio Cambra
Browse files

Add single-day and three-day views to Kalendar

parent c4a70bb3
Pipeline #105489 passed with stage
in 4 minutes and 48 seconds
......@@ -15,8 +15,12 @@ Kirigami.NavigationTabBar {
property string name: "monthView"
},
KActionFromAction {
kalendarAction: "open_week_view"
property string name: "weekView"
kalendarAction: "open_threeday_view"
property string name: "threeDayView"
},
KActionFromAction {
kalendarAction: "open_day_view"
property string name: "dayView"
},
KActionFromAction {
kalendarAction: "open_schedule_view"
......
......@@ -52,6 +52,14 @@ Labs.MenuBar {
kalendarAction: 'open_week_view'
}
NativeMenuItemFromAction {
kalendarAction: "open_threeday_view"
}
NativeMenuItemFromAction {
kalendarAction: "open_day_view"
}
NativeMenuItemFromAction {
kalendarAction: 'open_schedule_view'
}
......
......@@ -23,6 +23,7 @@ Kirigami.Page {
signal deselect()
signal moveIncidence(int startOffset, date occurrenceDate, var incidenceWrapper, Item caughtDelegate)
signal resizeIncidence(int endOffset, date occurrenceDate, var incidenceWrapper, Item caughtDelegate)
signal openDayView(date selectedDate)
property var openOccurrence: {}
property var model
......@@ -48,7 +49,7 @@ Kirigami.Page {
readonly property real gridLineWidth: 1.0
readonly property real hourLabelWidth: hourLabelMetrics.boundingRect(new Date(0,0,0,0,0,0,0).toLocaleTimeString(Qt.locale(), Locale.NarrowFormat)).width +
Kirigami.Units.largeSpacing * 2.5
readonly property real periodHeight: Kirigami.Units.gridUnit / 2
readonly property real periodHeight: Kirigami.Units.gridUnit
Kirigami.Theme.inherit: false
Kirigami.Theme.colorSet: Kirigami.Theme.View
......@@ -65,13 +66,16 @@ Kirigami.Page {
function setToDate(date, isInitialWeek = false) {
root.initialWeek = isInitialWeek;
date = DateUtils.getFirstDayOfWeek(date);
const weekDiff = Math.round((date - pathView.currentItem.startDate) / (root.daysToShow * 24 * 60 * 60 * 1000));
if(root.daysToShow % 7 === 0) {
date = DateUtils.getFirstDayOfWeek(date);
}
const weekDiff = Math.round((date.getTime() - pathView.currentItem.startDate.getTime()) / (root.daysToShow * 24 * 60 * 60 * 1000));
let newIndex = pathView.currentIndex + weekDiff;
let firstItemDate = pathView.model.data(pathView.model.index(1,0), Kalendar.InfiniteCalendarViewModel.StartDateRole);
let lastItemDate = pathView.model.data(pathView.model.index(pathView.model.rowCount() - 1,0), Kalendar.InfiniteCalendarViewModel.StartDateRole);
while(firstItemDate >= date) {
pathView.model.addDates(false)
firstItemDate = pathView.model.data(pathView.model.index(1,0), Kalendar.InfiniteCalendarViewModel.StartDateRole);
......@@ -149,7 +153,7 @@ Kirigami.Page {
property date dateToUse
property int startIndex
Component.onCompleted: {
startIndex = count / 2;
startIndex = root.model.rowCount() / 2;
currentIndex = startIndex;
}
onCurrentIndexChanged: {
......@@ -213,35 +217,55 @@ Kirigami.Page {
Repeater {
id: dayHeadings
model: weekViewModel.rowCount()
delegate: Kirigami.Heading {
id: dayHeading
property date headingDate: DateUtils.addDaysToDate(viewLoader.startDate, index)
property bool isToday: headingDate.getDate() === root.currentDay &&
headingDate.getMonth() === root.currentMonth &&
headingDate.getFullYear() === root.currentYear
model: switch(root.daysToShow) {
case 1:
return dayViewModel.rowCount();
case 3:
return threeDayViewModel.rowCount();
case 7:
default:
return weekViewModel.rowCount();
}
delegate: Rectangle {
width: root.dayWidth
horizontalAlignment: Text.AlignRight
padding: Kirigami.Units.smallSpacing
level: 2
color: isToday ? Kirigami.Theme.highlightColor : Kirigami.Theme.textColor
text: {
const longText = headingDate.toLocaleDateString(Qt.locale(), "dddd <b>d</b>");
const mediumText = headingDate.toLocaleDateString(Qt.locale(), "ddd <b>d</b>");
const shortText = mediumText.slice(0,1) + " " + headingDate.toLocaleDateString(Qt.locale(), "<b>d</b>");
if(fontMetrics.boundingRect(longText).width < width) {
return longText;
} else if(fontMetrics.boundingRect(mediumText).width < width) {
return mediumText;
} else {
return shortText;
implicitHeight: dayHeading.implicitHeight
color: Kirigami.Theme.backgroundColor
Kirigami.Heading { // Heading is out of the button so the color isn't disabled when the button is
id: dayHeading
property date headingDate: DateUtils.addDaysToDate(viewLoader.startDate, index)
property bool isToday: headingDate.getDate() === root.currentDay &&
headingDate.getMonth() === root.currentMonth &&
headingDate.getFullYear() === root.currentYear
width: parent.width
horizontalAlignment: Text.AlignRight
padding: Kirigami.Units.smallSpacing
level: 2
color: isToday ? Kirigami.Theme.highlightColor : Kirigami.Theme.textColor
text: {
const longText = headingDate.toLocaleDateString(Qt.locale(), "dddd <b>d</b>");
const mediumText = headingDate.toLocaleDateString(Qt.locale(), "ddd <b>d</b>");
const shortText = mediumText.slice(0,1) + " " + headingDate.toLocaleDateString(Qt.locale(), "<b>d</b>");
if(fontMetrics.boundingRect(longText).width < width) {
return longText;
} else if(fontMetrics.boundingRect(mediumText).width < width) {
return mediumText;
} else {
return shortText;
}
}
}
background: Rectangle {
color: dayHeading.isToday ? Kirigami.Theme.activeBackgroundColor : Kirigami.Theme.backgroundColor
QQC2.Button {
implicitHeight: dayHeading.implicitHeight
width: parent.width
flat: true
enabled: root.daysToShow > 1
onClicked: root.openDayView(dayHeading.headingDate)
}
}
}
......@@ -360,14 +384,30 @@ Kirigami.Page {
id: allDayViewLoader
anchors.fill: parent
anchors.leftMargin: root.hourLabelWidth
active: weekViewMultiDayViewModel.incidenceCount > 0
active: switch(root.daysToShow) {
case 1:
return dayViewMultiDayViewModel.incidenceCount > 0;
case 3:
return threeDayViewMultiDayViewModel.incidenceCount > 0;
case 7:
default:
return weekViewMultiDayViewModel.incidenceCount > 0;
}
sourceComponent: Item {
id: allDayViewItem
implicitHeight: allDayHeader.actualHeight
clip: true
Repeater {
model: weekViewMultiDayViewModel // from root.model
model: switch(root.daysToShow) {
case 1:
return dayViewMultiDayViewModel;
case 3:
return threeDayViewMultiDayViewModel;
case 7:
default:
return weekViewMultiDayViewModel;
} // from root.model
Layout.topMargin: Kirigami.Units.largeSpacing
//One row => one week
Item {
......@@ -551,8 +591,17 @@ Kirigami.Page {
z: -2
QQC2.ScrollBar.horizontal.policy: QQC2.ScrollBar.AlwaysOff
readonly property real periodsPerHour: 60 / weekViewModel.periodLength
readonly property real daySections: (60 * 24) / weekViewModel.periodLength
readonly property int periodLength: switch(root.daysToShow) {
case 1:
return dayViewModel.periodLength;
case 3:
return threeDayViewModel.periodLength;
case 7:
default:
return weekViewModel.periodLength;
}
readonly property real periodsPerHour: 60 / periodLength
readonly property real daySections: (60 * 24) / periodLength
readonly property real dayHeight: (daySections * root.periodHeight) + (root.gridLineWidth * 23)
readonly property real hourHeight: periodsPerHour * root.periodHeight
readonly property real minuteHeight: hourHeight / 60
......@@ -627,7 +676,7 @@ Kirigami.Page {
}
Repeater {
model: pathView.model.weekViewLocalisedHourLabels // Not a model role but instead one of the model object's properties
model: pathView.model.hourlyViewLocalisedHourLabels // Not a model role but instead one of the model object's properties
delegate: QQC2.Label {
property real textYTop: y
......@@ -671,7 +720,15 @@ Kirigami.Page {
Repeater {
id: dayColumnRepeater
model: weekViewModel // From root.model
model: switch(root.daysToShow) {
case 1:
return dayViewModel;
case 3:
return threeDayViewModel;
case 7:
default:
return weekViewModel;
} // From root.model
delegate: Item {
id: dayColumn
......
......@@ -22,6 +22,7 @@ Kirigami.Page {
signal addSubTodo(var parentWrapper)
signal deselect()
signal moveIncidence(int startOffset, date occurrenceDate, var incidenceWrapper, Item caughtDelegate)
signal openDayView(date selectedDate)
property var openOccurrence
property var model
......@@ -219,6 +220,7 @@ Kirigami.Page {
onAddSubTodo: monthPage.addSubTodo(parentWrapper)
onDeselect: monthPage.deselect()
onMoveIncidence: monthPage.moveIncidence(startOffset, occurrenceDate, incidenceWrapper, caughtDelegate)
onOpenDayView: monthPage.openDayView(selectedDate)
}
}
}
......
......@@ -23,6 +23,7 @@ Item {
signal addSubTodo(var parentWrapper)
signal deselect()
signal moveIncidence(int startOffset, date occurrenceDate, var incidenceWrapper, Item caughtDelegate)
signal openDayView(date selectedDate)
property var openOccurrence
property var model
......@@ -181,31 +182,42 @@ Item {
}
// Day number
RowLayout {
visible: root.showDayIndicator
QQC2.Button {
anchors.top: parent.top
anchors.right: parent.right
anchors.left: parent.left
implicitHeight: dayNumberLayout.implicitHeight
QQC2.Label {
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
padding: Kirigami.Units.smallSpacing
text: i18n("<b>Today</b>")
renderType: Text.QtRendering
color: Kirigami.Theme.highlightColor
visible: gridItem.isToday && gridItem.width > Kirigami.Units.gridUnit * 5
}
QQC2.Label {
Layout.alignment: Qt.AlignRight | Qt.AlignTop
text: gridItem.date.toLocaleDateString(Qt.locale(), gridItem.day == 1 ?
"d MMM" : "d")
renderType: Text.QtRendering
padding: Kirigami.Units.smallSpacing
flat: true
visible: root.showDayIndicator
enabled: root.daysToShow > 1
onClicked: root.openDayView(gridItem.date)
contentItem: RowLayout {
id: dayNumberLayout
visible: root.showDayIndicator
color: gridItem.isToday ?
Kirigami.Theme.highlightColor :
(!gridItem.isCurrentMonth ? Kirigami.Theme.disabledTextColor : Kirigami.Theme.textColor)
font.bold: gridItem.isToday
QQC2.Label {
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
padding: Kirigami.Units.smallSpacing
text: i18n("<b>Today</b>")
renderType: Text.QtRendering
color: Kirigami.Theme.highlightColor
visible: gridItem.isToday && gridItem.width > Kirigami.Units.gridUnit * 5
}
QQC2.Label {
Layout.alignment: Qt.AlignRight | Qt.AlignTop
text: gridItem.date.toLocaleDateString(Qt.locale(), gridItem.day == 1 ?
"d MMM" : "d")
renderType: Text.QtRendering
padding: Kirigami.Units.smallSpacing
visible: root.showDayIndicator
color: gridItem.isToday ?
Kirigami.Theme.highlightColor :
(!gridItem.isCurrentMonth ? Kirigami.Theme.disabledTextColor : Kirigami.Theme.textColor)
font.bold: gridItem.isToday
}
}
}
}
......
......@@ -22,6 +22,7 @@ Kirigami.Page {
signal addSubTodo(var parentWrapper)
signal deselect()
signal moveIncidence(int startOffset, date occurrenceDate, var incidenceWrapper, Item caughtDelegate)
signal openDayView(date selectedDate)
onAddIncidence: pathView.currentItem.item.savedYScrollPos = pathView.currentItem.item.QQC2.ScrollBar.vertical.visualPosition
onViewIncidence: pathView.currentItem.item.savedYScrollPos = pathView.currentItem.item.QQC2.ScrollBar.vertical.visualPosition
......@@ -313,19 +314,48 @@ Kirigami.Page {
property real dayLabelWidth: Kirigami.Units.gridUnit * 4
property bool isToday: new Date(periodStartDate).setHours(0,0,0,0) === new Date().setHours(0,0,0,0)
QQC2.Label {
id: smallDayLabel
Layout.alignment: Qt.AlignVCenter
QQC2.Button {
id: dayButton
Layout.fillHeight: true
Layout.maximumWidth: dayGrid.dayLabelWidth
Layout.minimumWidth: dayGrid.dayLabelWidth
padding: Kirigami.Units.smallSpacing
rightPadding: Kirigami.Units.largeSpacing
horizontalAlignment: Text.AlignRight
visible: !cardsColumn.visible
text: periodStartDate.toLocaleDateString(Qt.locale(), "ddd <b>dd</b>")
color: Kirigami.Theme.disabledTextColor
flat: true
onClicked: root.openDayView(periodStartDate)
property Item smallDayLabel: QQC2.Label {
id: smallDayLabel
Layout.alignment: Qt.AlignVCenter
width: dayButton.width
horizontalAlignment: Text.AlignRight
visible: !cardsColumn.visible
wrapMode: Text.Wrap
text: periodStartDate.toLocaleDateString(Qt.locale(), "ddd <b>dd</b>")
color: Kirigami.Theme.disabledTextColor
}
property Item largeDayLabel: Kirigami.Heading {
id: largeDayLabel
width: dayButton.width
Layout.alignment: Qt.AlignTop
horizontalAlignment: Text.AlignRight
verticalAlignment: Text.AlignTop
level: dayGrid.isToday ? 1 : 3
textFormat: Text.StyledText
wrapMode: Text.Wrap
color: dayGrid.isToday ? Kirigami.Theme.highlightColor : Kirigami.Theme.textColor
text: periodStartDate.toLocaleDateString(Qt.locale(), "ddd<br><b>dd</b>")
}
contentItem: incidences.length || dayGrid.isToday ? largeDayLabel : smallDayLabel
}
QQC2.Label {
......@@ -337,26 +367,6 @@ Kirigami.Page {
color: Kirigami.Theme.disabledTextColor
}
Kirigami.Heading {
id: largeDayLabel
Layout.alignment: Qt.AlignTop
Layout.maximumWidth: dayGrid.dayLabelWidth
Layout.minimumWidth: dayGrid.dayLabelWidth
Layout.fillHeight: true
padding: Kirigami.Units.smallSpacing
rightPadding: Kirigami.Units.largeSpacing
horizontalAlignment: Text.AlignRight
verticalAlignment: Text.AlignTop
level: dayGrid.isToday ? 1 : 3
textFormat: Text.StyledText
wrapMode: Text.Wrap
color: dayGrid.isToday ? Kirigami.Theme.highlightColor : Kirigami.Theme.textColor
text: periodStartDate.toLocaleDateString(Qt.locale(), "ddd<br><b>dd</b>")
visible: incidences.length || dayGrid.isToday
}
ColumnLayout {
id: cardsColumn
......
......@@ -131,6 +131,13 @@ QQC2.MenuBar {
KActionFromAction {
kalendarAction: "open_week_view"
}
KActionFromAction {
kalendarAction: "open_threeday_view"
}
KActionFromAction {
kalendarAction: "open_day_view"
}
KActionFromAction {
kalendarAction: "open_schedule_view"
}
......
......@@ -43,6 +43,8 @@ Kirigami.ApplicationWindow {
readonly property var monthViewAction: KalendarApplication.action("open_month_view")
readonly property var weekViewAction: KalendarApplication.action("open_week_view")
readonly property var threeDayViewAction: KalendarApplication.action("open_threeday_view")
readonly property var dayViewAction: KalendarApplication.action("open_day_view")
readonly property var scheduleViewAction: KalendarApplication.action("open_schedule_view")
readonly property var todoViewAction: KalendarApplication.action("open_todo_view")
readonly property var moveViewForwardsAction: KalendarApplication.action("move_view_forwards")
......@@ -104,6 +106,12 @@ Kirigami.ApplicationWindow {
case Config.WeekView:
weekViewAction.trigger();
break;
case Config.ThreeDayView:
threeDayViewAction.trigger();
break;
case Config.DayView:
dayViewAction.trigger();
break;
case Config.ScheduleView:
scheduleViewAction.trigger();
break;
......@@ -142,7 +150,7 @@ Kirigami.ApplicationWindow {
}
}
function switchView(newViewComponent) {
function switchView(newViewComponent, viewSettings) {
if(pageStack.layers.depth > 1) {
pageStack.layers.pop(pageStack.layers.initialItem);
}
......@@ -151,6 +159,16 @@ Kirigami.ApplicationWindow {
if(filterHeader.active) {
pageStack.currentItem.header = filterHeader.item;
}
if(viewSettings) {
for(const [key, value] of Object.entries(viewSettings)) {
pageStack.currentItem[key] = value;
}
}
if(pageStack.currentItem.objectName !== "todoView") {
pageStack.currentItem.setToDate(root.selectedDate, true);
}
}
Connections {
......@@ -165,7 +183,21 @@ Kirigami.ApplicationWindow {
function onOpenWeekView() {
if(pageStack.currentItem.objectName !== "weekView" || root.ignoreCurrentPage) {
weekScaleModelLoader.active = true;
root.switchView(weekViewComponent);
root.switchView(hourlyViewComponent);
}
}
function onOpenThreeDayView() {
if(pageStack.currentItem.objectName !== "threeDayView" || root.ignoreCurrentPage) {
threeDayScaleModelLoader.active = true;
root.switchView(hourlyViewComponent, { daysToShow: 3 });
}
}
function onOpenDayView() {
if(pageStack.currentItem.objectName !== "dayView" || root.ignoreCurrentPage) {
dayScaleModelLoader.active = true;
root.switchView(hourlyViewComponent, { daysToShow: 1 });
}
}
......@@ -386,6 +418,12 @@ Kirigami.ApplicationWindow {
case "weekView":
return i18n("Week View");
break;
case "threeDayView":
return i18n("3 Day View");
break;
case "dayView":
return i18n("Day View");
break;
case "scheduleView":
return i18n("Schedule View");
break;
......@@ -478,8 +516,8 @@ Kirigami.ApplicationWindow {
modal: !root.wideScreen || !enabled
onEnabledChanged: drawerOpen = enabled && !modal
onModalChanged: drawerOpen = !modal
enabled: incidenceData != undefined && pageStack.layers.depth < 2 && pageStack.depth < 3
handleVisible: enabled && pageStack.layers.depth < 2 && pageStack.depth < 3
enabled: incidenceData != undefined
handleVisible: enabled
interactive: Kirigami.Settings.isMobile // Otherwise get weird bug where drawer gets dragged around despite no click
activeTags: root.filter && root.filter.tags ?
......@@ -949,6 +987,27 @@ Kirigami.ApplicationWindow {
function onUpdateIncidenceDatesCompleted() { root.reenableDragOnCurrentView(); }
}
function openDayLayer(selectedDate) {
if(!isNaN(selectedDate.getTime())) {
dayScaleModelLoader.active = true;
root.selectedDate = selectedDate;
if(Kirigami.Settings.isMobile) {
dayViewAction.trigger();
} else {
pageStack.layers.push(hourlyViewComponent);
pageStack.layers.currentItem.daysToShow = 1;
if(filterHeader.active) {
pageStack.layers.currentItem.header = filterHeader.item;
}
pageStack.layers.currentItem.setToDate(root.selectedDate, true);
}
}
}
Component {
id: deleteIncidenceSheetComponent
DeleteIncidenceSheet {
......@@ -1063,6 +1122,28 @@ Kirigami.ApplicationWindow {
}
}
Loader {
id: threeDayScaleModelLoader
active: Config.lastOpenedView === Config.ThreeDayView
onStatusChanged: if(status === Loader.Ready) asynchronous = true
sourceComponent: InfiniteCalendarViewModel {
scale: InfiniteCalendarViewModel.ThreeDayScale
calendar: CalendarManager.calendar
filter: root.filter
}
}
Loader {
id: dayScaleModelLoader
active: Config.lastOpenedView === Config.DayView
onStatusChanged: if(status === Loader.Ready) asynchronous = true
sourceComponent: InfiniteCalendarViewModel {
scale: InfiniteCalendarViewModel.DayScale
calendar: CalendarManager.calendar
filter: root.filter
}
}
Component {
id: monthViewComponent
......@@ -1086,12 +1167,11 @@ Kirigami.ApplicationWindow {
onAddSubTodo: root.setUpAddSubTodo(parentWrapper)
onDeselect: incidenceInfo.close()
onMoveIncidence: root.setUpIncidenceDateChange(incidenceWrapper, startOffset, startOffset, occurrenceDate, caughtDelegate)
onOpenDayView: root.openDayLayer(selectedDate)
onMonthChanged: if(month !== root.selectedDate.getMonth() && !initialMonth) root.selectedDate = new Date (year, month, 1)
onYearChanged: if(year !== root.selectedDate.getFullYear() && !initialMonth) root.selectedDate = new Date (year, month, 1)
Component.onCompleted: setToDate(root.selectedDate, true)
actions.contextualActions: createAction
}
}
......@@ -1115,8 +1195,6 @@ Kirigami.ApplicationWindow {
onMonthChanged: if(month !== root.selectedDate.getMonth() && !initialMonth) root.selectedDate = new Date (year, month, day)
onYearChanged: if(year !== root.selectedDate.getFullYear() && !initialMonth) root.selectedDate = new Date (year, month, day)
Component.onCompleted: setToDate(root.selectedDate, true)
onAddIncidence: root.setUpAdd(type, addDate)
onViewIncidence: root.setUpView(modelData)