Commit 19c59c5a authored by Claudio Cambra's avatar Claudio Cambra
Browse files

Change incidence info drawer into popup on desktop



Signed-off-by: Claudio Cambra's avatarClaudio Cambra <claudio.cambra@gmail.com>
parent 00f8b55b
This diff is collapsed.
// SPDX-FileCopyrightText: 2022 Claudio Cambra <claudio.cambra@gmail.com>
// SPDX-License-Identifier: LGPL-2.0-or-later
import QtQuick 2.15
import org.kde.kirigami 2.14 as Kirigami
import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import QtLocation 5.15
import "labelutils.js" as LabelUtils
import org.kde.kalendar 1.0
QQC2.Popup {
id: root
signal tagClicked(string tagName)
property var incidenceData
property var activeTags : []
property alias scrollView: incidenceInfoContents.scrollView
contentWidth: availableWidth
topPadding: 0
leftPadding: 0
rightPadding: 0
bottomPadding: 0
Kirigami.Theme.colorSet: Kirigami.Theme.Window
contentItem: IncidenceInfoContents {
id: incidenceInfoContents
anchors.fill: parent
incidenceData: root.incidenceData
activeTags: root.activeTags
onTagClicked: root.tagClicked(tagName)
}
}
......@@ -8,11 +8,29 @@ import QtQuick.Controls 2.15 as QQC2
MouseArea {
acceptedButtons: Qt.BackButton | Qt.ForwardButton
propagateComposedEvents: true
function repositionIncidencePopup() {
if(incidenceInfoPopup && incidenceInfoPopup.visible) {
incidenceInfoPopup.reposition();
}
}
onClicked: {
if (mouse.button === Qt.BackButton) {
moveViewBackwardsAction.trigger();
} else if (mouse.button === Qt.ForwardButton) {
moveViewForwardsAction.trigger();
}
mouse.accepted = false;
}
onWheel: {
repositionIncidencePopup();
wheel.accepted = false;
}
onPressAndHold: {
repositionIncidencePopup();
mouse.accepted = false;
}
}
......@@ -187,7 +187,7 @@ Item {
drag.target: !Kirigami.Settings.isMobile && !modelData.isReadOnly && incidenceDelegate.dragDropEnabled ? parent : undefined
onReleased: parent.Drag.drop()
onViewClicked: KalendarUiUtils.setUpView(modelData)
onViewClicked: KalendarUiUtils.setUpView(modelData, incidenceDelegate)
onEditClicked: KalendarUiUtils.setUpEdit(modelData.incidencePtr)
onDeleteClicked: KalendarUiUtils.setUpDelete(modelData.incidencePtr, deleteDate)
onTodoCompletedClicked: KalendarUiUtils.completeTodo(incidencePtr)
......
......@@ -11,6 +11,7 @@ import org.kde.kalendar 1.0
import org.kde.kalendar.utils 1.0
Item {
id: root
property var incidenceWrapper: modelData
property var collectionData: CalendarManager.getCollectionDetails(incidenceWrapper.collectionId)
......@@ -26,7 +27,7 @@ Item {
//drag.target: !Kirigami.Settings.isMobile && !modelData.isReadOnly && incidenceDelegate.dragDropEnabled ? parent : undefined
//onReleased: parent.Drag.drop()
onViewClicked: KalendarUiUtils.setUpView(incidenceData)
onViewClicked: KalendarUiUtils.setUpView(incidenceData, root)
onEditClicked: KalendarUiUtils.setUpEdit(incidencePtr)
onDeleteClicked: KalendarUiUtils.setUpDelete(incidencePtr, deleteDate)
onTodoCompletedClicked: KalendarUiUtils.completeTodo(incidencePtr)
......
......@@ -110,9 +110,22 @@ QtObject {
editorToUse.incidenceWrapper.incidenceEnd = parentWrapper.incidenceEnd;
}
function setUpView(modelData) {
appMain.incidenceInfoDrawer.incidenceData = modelData;
appMain.incidenceInfoDrawer.open();
function setUpView(modelData, incidenceItem = null) {
// Choose between opening the incidence information in the drawer or the popup
const usingDrawer = Kirigami.Settings.isMobile || !incidenceItem;
appMain.incidenceInfoDrawerEnabled = usingDrawer;
appMain.incidenceInfoPopupEnabled = !usingDrawer;
const incidenceInfoComponent = usingDrawer ? appMain.incidenceInfoDrawer : appMain.incidenceInfoPopup;
incidenceInfoComponent.incidenceData = modelData;
if (!usingDrawer) {
incidenceInfoComponent.openingIncidenceItem = incidenceItem;
}
incidenceInfoComponent.open();
}
function fakeModelDataFromIncidenceWrapper(incidenceWrapper) {
......
......@@ -1076,7 +1076,7 @@ Kirigami.Page {
drag.target: !Kirigami.Settings.isMobile && !modelData.isReadOnly && root.dragDropEnabled ? parent : undefined
onReleased: parent.Drag.drop()
onViewClicked: KalendarUiUtils.setUpView(modelData)
onViewClicked: KalendarUiUtils.setUpView(modelData, hourlyIncidenceDelegateBackgroundBackground)
onEditClicked: KalendarUiUtils.setUpEdit(incidencePtr)
onDeleteClicked: KalendarUiUtils.setUpDelete(incidencePtr, deleteDate)
onTodoCompletedClicked: KalendarUiUtils.completeTodo(incidencePtr)
......
......@@ -20,9 +20,9 @@ Kirigami.Page {
KalendarUiUtils.setUpAdd(type, addDate);
}
function viewIncidence(modelData) {
function viewIncidence(modelData, incidenceItem) {
pathView.currentItem.item.savedYScrollPos = pathView.currentItem.item.QQC2.ScrollBar.vertical.visualPosition;
KalendarUiUtils.setUpView(modelData);
KalendarUiUtils.setUpView(modelData, incidenceItem);
}
function editIncidence(incidencePtr) {
......@@ -606,7 +606,7 @@ Kirigami.Page {
drag.target: !Kirigami.Settings.isMobile && !modelData.isReadOnly && root.dragDropEnabled ? incidenceCard : undefined
onReleased: incidenceCard.Drag.drop()
onViewClicked: root.viewIncidence(modelData)
onViewClicked: root.viewIncidence(modelData, incidenceCard)
onEditClicked: root.editIncidence(incidencePtr)
onDeleteClicked: root.deleteIncidence(incidencePtr, deleteDate)
onTodoCompletedClicked: root.completeTodo(incidencePtr)
......
......@@ -17,7 +17,7 @@ TreeListView {
id: root
// We need to store a copy of opened incidence data or we will lose it as we scroll the listviews.
function viewAndRetainTodoData(todoData) {
function viewAndRetainTodoData(todoData, incidenceItem) {
retainedTodoData = {
incidencePtr: todoData.incidencePtr,
incidenceId: todoData.incidenceId,
......@@ -27,7 +27,7 @@ TreeListView {
endTime: todoData.endTime,
durationString: todoData.durationString
};
KalendarUiUtils.setUpView(retainedTodoData);
KalendarUiUtils.setUpView(retainedTodoData, incidenceItem);
}
property var retainedTodoData: ({})
......@@ -198,7 +198,7 @@ TreeListView {
}
]
onClicked: root.viewAndRetainTodoData(model)
onClicked: root.viewAndRetainTodoData(model, listItem)
contentItem: IncidenceMouseArea {
id: mouseArea
......
......@@ -149,7 +149,8 @@ Kirigami.ApplicationWindow {
shortcut: "Delete"
onTriggered: {
if(root.openOccurrence) {
KalendarUiUtils.setUpDelete(incidenceInfoDrawer.incidenceData.incidencePtr, incidenceInfoDrawer.incidenceData.startTime);
KalendarUiUtils.setUpDelete(root.openOccurrence.incidencePtr,
root.openOccurrence.startTime);
}
}
}
......@@ -497,80 +498,148 @@ Kirigami.ApplicationWindow {
}
}
property alias incidenceInfoDrawer: incidenceInfoDrawer
contextDrawer: IncidenceInfoDrawer {
id: incidenceInfoDrawer
contextDrawer: if(incidenceInfoDrawerEnabled) incidenceInfoDrawer
width: if(!Kirigami.Settings.isMobile) actualWidth
height: if(Kirigami.Settings.isMobile) applicationWindow().height * 0.6
bottomPadding: menuLoader.active ? menuLoader.height : 0
readonly property bool incidenceInfoViewer: incidenceInfoDrawerEnabled ? incidenceInfoDrawer :
incidenceInfoPopupEnabled ? incidenceInfoPopup :
null
modal: !root.wideScreen || !enabled
onEnabledChanged: drawerOpen = enabled && !modal
onModalChanged: drawerOpen = !modal
enabled: incidenceData != undefined && pageStack.currentItem.mode !== KalendarApplication.Contact
handleVisible: enabled
interactive: Kirigami.Settings.isMobile // Otherwise get weird bug where drawer gets dragged around despite no click
onIncidenceDataChanged: root.openOccurrence = incidenceData;
onVisibleChanged: {
if(visible) {
root.openOccurrence = incidenceData;
} else {
root.openOccurrence = null;
property bool incidenceInfoDrawerEnabled: Kirigami.Settings.isMobile
readonly property alias incidenceInfoDrawer: incidenceInfoDrawerLoader.item
Loader {
id: incidenceInfoDrawerLoader
active: root.incidenceInfoDrawerEnabled
sourceComponent: IncidenceInfoDrawer {
id: incidenceInfoDrawer
width: if(!Kirigami.Settings.isMobile) actualWidth
height: if(Kirigami.Settings.isMobile) applicationWindow().height * 0.6
bottomPadding: menuLoader.active ? menuLoader.height : 0
modal: !root.wideScreen || !enabled
onEnabledChanged: drawerOpen = enabled && !modal
onModalChanged: drawerOpen = !modal
enabled: incidenceData != undefined && pageStack.currentItem.mode !== KalendarApplication.Contact
handleVisible: enabled
interactive: Kirigami.Settings.isMobile // Otherwise get weird bug where drawer gets dragged around despite no click
onIncidenceDataChanged: root.openOccurrence = incidenceData;
onVisibleChanged: visible ?
root.openOccurrence = incidenceData : root.openOccurrence = null
readonly property int minWidth: Kirigami.Units.gridUnit * 15
readonly property int maxWidth: Kirigami.Units.gridUnit * 25
readonly property int defaultWidth: Kirigami.Units.gridUnit * 20
property int actualWidth: {
if (Config.incidenceInfoDrawerDrawerWidth === -1) {
return defaultWidth;
} else {
return Config.incidenceInfoDrawerDrawerWidth;
}
}
}
onAddSubTodo: {
KalendarUiUtils.setUpAddSubTodo(parentWrapper);
if (modal) { incidenceInfoDrawer.close() }
}
onEditIncidence: {
KalendarUiUtils.setUpEdit(incidencePtr);
if (modal) { incidenceInfoDrawer.close() }
}
onDeleteIncidence: {
KalendarUiUtils.setUpDelete(incidencePtr, deleteDate)
if (modal) { incidenceInfoDrawer.close() }
}
ResizerSeparator {
anchors.left: if(Qt.application.layoutDirection !== Qt.RightToLeft) parent.left
anchors.leftMargin: if(Qt.application.layoutDirection !== Qt.RightToLeft) -1 // Cover up the natural separator on the drawer
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: if(Qt.application.layoutDirection === Qt.RightToLeft) parent.right
anchors.rightMargin: if(Qt.application.layoutDirection === Qt.RightToLeft) -1
width: 1
oversizeMouseAreaHorizontal: 5
z: 500
function savePos() {
Config.incidenceInfoDrawerDrawerWidth = incidenceInfoDrawer.actualWidth;
Config.save();
}
readonly property int minWidth: Kirigami.Units.gridUnit * 15
readonly property int maxWidth: Kirigami.Units.gridUnit * 25
readonly property int defaultWidth: Kirigami.Units.gridUnit * 20
property int actualWidth: {
if (Config.incidenceInfoDrawerDrawerWidth === -1) {
return defaultWidth;
} else {
return Config.incidenceInfoDrawerDrawerWidth;
onDragBegin: savePos()
onDragReleased: savePos()
onDragPositionChanged: {
if (Qt.application.layoutDirection === Qt.RightToLeft) {
incidenceInfoDrawer.actualWidth = Math.min(incidenceInfoDrawer.maxWidth, Math.max(incidenceInfoDrawer.minWidth, Config.incidenceInfoDrawerDrawerWidth + changeX));
} else {
incidenceInfoDrawer.actualWidth = Math.min(incidenceInfoDrawer.maxWidth, Math.max(incidenceInfoDrawer.minWidth, Config.incidenceInfoDrawerDrawerWidth - changeX));
}
}
}
}
}
ResizerSeparator {
anchors.left: if(Qt.application.layoutDirection !== Qt.RightToLeft) parent.left
anchors.leftMargin: if(Qt.application.layoutDirection !== Qt.RightToLeft) -1 // Cover up the natural separator on the drawer
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: if(Qt.application.layoutDirection === Qt.RightToLeft) parent.right
anchors.rightMargin: if(Qt.application.layoutDirection === Qt.RightToLeft) -1
width: 1
oversizeMouseAreaHorizontal: 5
z: 500
function savePos() {
Config.incidenceInfoDrawerDrawerWidth = incidenceInfoDrawer.actualWidth;
Config.save();
property bool incidenceInfoPopupEnabled: !Kirigami.Settings.isMobile
readonly property alias incidenceInfoPopup: incidenceInfoPopupLoader.item
Loader {
id: incidenceInfoPopupLoader
active: incidenceInfoPopupEnabled
sourceComponent: IncidenceInfoPopup {
id: incidenceInfoPopup
// HACK: This is called on mouse events by the KBMNavigationMouseArea in root
// so that we can react to scrolling in the different views, as there is no
// way to track the assigned incidence item delegate in a global sense.
// Remember that when a delegate is scrolled within a scroll view, the
// delegate's own relative x and y values do not change
function reposition() {
calculatePositionTimer.start();
}
onDragBegin: savePos()
onDragReleased: savePos()
onDragPositionChanged: {
if (Qt.application.layoutDirection === Qt.RightToLeft) {
incidenceInfoDrawer.actualWidth = Math.min(incidenceInfoDrawer.maxWidth, Math.max(incidenceInfoDrawer.minWidth, Config.incidenceInfoDrawerDrawerWidth + changeX));
} else {
incidenceInfoDrawer.actualWidth = Math.min(incidenceInfoDrawer.maxWidth, Math.max(incidenceInfoDrawer.minWidth, Config.incidenceInfoDrawerDrawerWidth - changeX));
function calculateIncidenceItemPosition() {
if (!openingIncidenceItem) {
console.log("Can't calculate incidence item position for popup, no opening incidence item is set");
return;
}
// We need to compensate for the x and y local adjustments used, for instance,
// in the day grid view to position the incidence item delegates
incidenceItemPosition = openingIncidenceItem.mapToItem(root.pageStack.currentItem,
openingIncidenceItem.x,
openingIncidenceItem.y);
incidenceItemPosition.x -= openingIncidenceItem.x;
incidenceItemPosition.y -= openingIncidenceItem.y;
}
property Item openingIncidenceItem: null
onOpeningIncidenceItemChanged: reposition()
property point incidenceItemPosition
property bool positionBelowIncidenceItem: incidenceItemPosition &&
incidenceItemPosition.y < root.pageStack.currentItem.height / 2;
property int maxXPosition: root.pageStack.currentItem.width - width
// HACK:
// If we reposition immediately we often end up updating the position of the popup
// before the assigned delegate has finished changing position itself. Even with
// this tiny interval, we avoid the problem and 2ms is not enough to be noticeable
Timer {
id: calculatePositionTimer
interval: 2
onTriggered: incidenceInfoPopup.calculateIncidenceItemPosition()
}
Connections {
target: incidenceInfoPopup.openingIncidenceItem
function onXChanged() { incidenceInfoPopup.reposition(); }
function onYChanged() { incidenceInfoPopup.reposition(); }
function onWidthChanged() { incidenceInfoPopup.reposition(); }
function onHeightChanged() { incidenceInfoPopup.reposition(); }
}
x: Math.min(incidenceItemPosition.x, maxXPosition)
y: positionBelowIncidenceItem ? incidenceItemPosition.y + openingIncidenceItem.height : incidenceItemPosition.y - height;
width: Kirigami.Units.gridUnit * 30
height: Math.min(Kirigami.Units.gridUnit * 50, scrollView.contentHeight)
activeTags: root.filter && root.filter.tags ? root.filter.tags : []
onIncidenceDataChanged: root.openOccurrence = incidenceData
onVisibleChanged: {
reposition();
visible ? root.openOccurrence = incidenceData : root.openOccurrence = null;
}
onTagClicked: root.toggleFilterTag(tagName)
}
}
......@@ -813,13 +882,22 @@ Kirigami.ApplicationWindow {
DeleteIncidencePage {
id: deleteIncidencePage
onAddException: {
if(incidenceInfoDrawer.incidenceWrapper && incidenceInfoDrawer.incidenceWrapper.uid === deleteIncidencePage.incidenceWrapper.uid &&
DateUtils.sameDay(incidenceInfoDrawer.incidenceData.startTime, exceptionDate)) {
function closeOpenIncidenceIfSame() {
const deletingIncidenceIsOpen = incidenceWrapper &&
root.incidenceInfoViewer &&
root.incidenceInfoViewer.incidenceWrapper &&
root.incidenceInfoViewer.incidenceWrapper.uid === incidenceWrapper.uid;
incidenceInfoDrawer.incidenceData = undefined;
if (deletingIncidenceIsOpen) {
root.incidenceInfoViewer.incidenceData = undefined;
root.openOccurrence = undefined;
}
}
onAddException: {
if (root.openOccurrence && DateUtils.sameDay(root.openOccurrence.incidenceData.startTime, exceptionDate)) {
closeOpenIncidenceIfSame()
}
incidenceWrapper.recurrenceExceptionsModel.addExceptionDateTime(exceptionDate);
CalendarManager.editIncidence(incidenceWrapper);
......@@ -827,34 +905,23 @@ Kirigami.ApplicationWindow {
}
onAddRecurrenceEndDate: {
// If occurrence is past the new recurrence end date, it has ben deleted so kill instance in incidence info
if(incidenceInfoDrawer.incidenceWrapper && incidenceInfoDrawer.incidenceWrapper.uid === deleteIncidencePage.incidenceWrapper.uid &&
incidenceInfoDrawer.incidenceData.startTime >= endDate) {
incidenceInfoDrawer.incidenceData = undefined;
root.openOccurrence = undefined;
if (root.openOccurrence && root.openOccurrence.startTime >= endDate) {
closeOpenIncidenceIfSame();
}
incidenceWrapper.setRecurrenceDataItem("endDateTime", endDate);
CalendarManager.editIncidence(incidenceWrapper);
closeDialog();
}
onDeleteIncidence: {
// Deleting an incidence also means deleting all of its occurrences
if(incidenceInfoDrawer.incidenceWrapper && incidenceInfoDrawer.incidenceWrapper.uid === deleteIncidencePage.incidenceWrapper.uid) {
incidenceInfoDrawer.incidenceData = undefined;
root.openOccurrence = undefined;
}
closeOpenIncidenceIfSame()
CalendarManager.deleteIncidence(incidencePtr);
closeDialog();
}
onDeleteIncidenceWithChildren: {
// TODO: Check if parent deleted too
if(incidenceInfoDrawer.incidenceWrapper && incidenceInfoDrawer.incidenceWrapper.uid == deleteIncidencePage.incidenceWrapper.uid) {
incidenceInfoDrawer.incidenceData = undefined;
root.openOccurrence = undefined;
}
closeOpenIncidenceIfSame();
CalendarManager.deleteIncidence(incidencePtr, true);
closeDialog();
}
......
......@@ -54,6 +54,8 @@ SPDX-License-Identifier: CC0-1.0
<file alias="ResizerSeparator.qml">contents/ui/Controls/ResizerSeparator.qml</file>
<file alias="CalendarItemTapHandler.qml">contents/ui/Controls/CalendarItemTapHandler.qml</file>
<file alias="TodoCheckBox.qml">contents/ui/Controls/TodoCheckBox.qml</file>
<file alias="IncidenceInfoContents.qml">contents/ui/Controls/IncidenceInfoContents.qml</file>
<file alias="IncidenceInfoPopup.qml">contents/ui/Controls/IncidenceInfoPopup.qml</file>
<file alias="LocationMap.qml">contents/ui/Location/LocationMap.qml</file>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment