Commit 2aa85dc2 authored by Dimitris Kardarakos's avatar Dimitris Kardarakos

Merge branch 'calendar-events'

parents bb918b91 9a696c7f
......@@ -40,6 +40,7 @@ MonthView {
currentMonthName: plasmaCalendar.displayedDateMonthName
selectedDayTodosCount: todosCount(selectedDate)
selectedDayEventsCount: eventsCount(selectedDate)
daysModel: plasmaCalendar.daysModel
showHeader: true
showMonthName: true
......
/*
* Copyright 2018 Dimitris Kardarakos <dimkard@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import QtQuick 2.0
import QtQuick.Controls 2.4 as Controls2
import QtQuick.Layouts 1.11
import org.kde.kirigami 2.4 as Kirigami
import org.kde.phone.calindori 0.1 as Calindori
Kirigami.Page {
id: root
property date startdt
property string uid
property alias summary: summary.text
property alias description: description.text
property alias startHour: startTimeSelector.startHour
property alias startMinute: startTimeSelector.startMinutes
property alias startPm: startTimeSelector.startPm
property alias allDay: allDaySelector.checked
property alias location: location.text
property var calendar
property var eventData
property date enddt
property alias endHour: endTimeSelector.endHour
property alias endMinute: endTimeSelector.endMinutes
property alias endPm: endTimeSelector.endPm
signal editcompleted
title: qsTr("Event")
ColumnLayout {
anchors.centerIn: parent
Controls2.Label {
visible: root.startdt != undefined && !isNaN(root.startdt)
Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter
font.pointSize: Kirigami.Units.fontMetrics.font.pointSize * 1.2
text: eventData && !isNaN(eventData.dtstart) ? eventData.dtstart.toLocaleDateString(Qt.locale()) : (!isNaN(root.startdt) ? root.startdt.toLocaleDateString(Qt.locale()) : "")
}
Kirigami.FormLayout {
id: eventCard
enabled: !root.completed
Kirigami.Separator {
Kirigami.FormData.isSection: true
}
Controls2.Label {
id: calendarName
Kirigami.FormData.label: qsTr("Calendar:")
Layout.fillWidth: true
text: root.calendar.name
}
Kirigami.Separator {
Kirigami.FormData.isSection: true
}
Controls2.TextField {
id: summary
Layout.fillWidth: true
Kirigami.FormData.label: qsTr("Summary:")
text: eventData ? eventData.summary : ""
}
RowLayout {
Kirigami.FormData.label: qsTr("Start time:")
enabled: root.startdt != undefined && !isNaN(root.startdt)
Controls2.ToolButton {
id: startTimeSelector
property int startHour: root.eventData ? root.eventData.dtstart.toLocaleTimeString(Qt.locale(), "hh") % 12 : 0
property int startMinutes: root.eventData ? root.eventData.dtstart.toLocaleTimeString(Qt.locale(), "mm") : 0
property bool startPm : (root.eventData && root.eventData.dtstart.toLocaleTimeString(Qt.locale("en_US"), "AP") == "PM") ? true : false
text: !isNaN(startdt) ? (new Date(startdt.getFullYear(), startdt.getMonth() , startdt.getDate(), startHour + (startPm ? 12 : 0), startMinutes)).toLocaleTimeString(Qt.locale(), "hh:mm AP"): "00:00"
enabled: !allDaySelector.checked
onClicked: {
startTimePickerSheet.hours = startTimeSelector.startHour
startTimePickerSheet.minutes = startTimeSelector.startMinutes
startTimePickerSheet.pm = startTimeSelector.startPm
startTimePickerSheet.open()
}
Connections {
target: startTimePickerSheet
onDatePicked: {
startTimeSelector.startHour = startTimePickerSheet.hours
startTimeSelector.startMinutes = startTimePickerSheet.minutes
startTimeSelector.startPm = startTimePickerSheet.pm
}
}
}
}
RowLayout {
Kirigami.FormData.label: qsTr("End time:")
enabled: root.enddt != undefined && !isNaN(root.enddt)
Controls2.ToolButton {
id: endTimeSelector
property int endHour: root.eventData ? root.eventData.dtend.toLocaleTimeString(Qt.locale(), "hh") % 12 : 0
property int endMinutes: root.eventData ? root.eventData.dtend.toLocaleTimeString(Qt.locale(), "mm") : 0
property bool endPm : (root.eventData && root.eventData.dtend.toLocaleTimeString(Qt.locale("en_US"), "AP") == "PM") ? true : false
text: !isNaN(enddt) ? (new Date(enddt.getFullYear(), enddt.getMonth() , enddt.getDate(), endHour + (endPm ? 12 : 0), endMinutes)).toLocaleTimeString(Qt.locale(), "hh:mm AP"): "00:00"
enabled: !allDaySelector.checked
onClicked: {
endTimePickerSheet.hours = endTimeSelector.endHour
endTimePickerSheet.minutes = endTimeSelector.endMinutes
endTimePickerSheet.pm = endTimeSelector.endPm
endTimePickerSheet.open()
}
Connections {
target: endTimePickerSheet
onDatePicked: {
var endDtTime = root.enddt;
endDtTime.setHours(endTimePickerSheet.hours + (endTimePickerSheet.pm ? 12 : 0));
endDtTime.setMinutes( endTimePickerSheet.minutes);
var startDtTime = root.startdt;
startDtTime.setHours(root.startHour + (root.startPm ? 12 : 0));
startDtTime.setMinutes(root.startMinute);
if(endDtTime >= startDtTime) {
endTimeSelector.endHour = endTimePickerSheet.hours
endTimeSelector.endMinutes = endTimePickerSheet.minutes
endTimeSelector.endPm = endTimePickerSheet.pm
}
else
{
showPassiveNotification("End date time should be after start date time");
}
}
}
}
}
Controls2.CheckBox {
id: allDaySelector
enabled: !isNaN(root.startdt)
checked: eventData ? eventData.allday: false
text: qsTr("All day")
}
Kirigami.Separator {
Kirigami.FormData.isSection: true
}
Controls2.TextField {
id: location
Layout.fillWidth: true
Kirigami.FormData.label: qsTr("Location:")
text: eventData ? eventData.location : ""
}
}
Kirigami.Separator {
Layout.fillWidth: true
}
Controls2.TextArea {
id: description
Layout.fillWidth: true
Layout.minimumWidth: Kirigami.Units.gridUnit * 4
Layout.minimumHeight: Kirigami.Units.gridUnit * 4
wrapMode: Controls2.TextArea.WordWrap
text: eventData ? eventData.description : ""
placeholderText: qsTr("Description")
}
}
actions {
left: Kirigami.Action {
id: cancelAction
text: qsTr("Cancel")
icon.name : "dialog-cancel"
onTriggered: {
editcompleted();
}
}
main: Kirigami.Action {
id: info
text: qsTr("Info")
icon.name : "documentinfo"
onTriggered: {
showPassiveNotification("Please save or cancel this event");
}
}
right: Kirigami.Action {
id: saveAction
text: qsTr("Save")
icon.name : "dialog-ok"
onTriggered: {
if(summary.text) {
console.log("Saving event, root.startdt:" + startdt);
var controller = eventController.createObject(parent, {calendar: root.calendar});
controller.vevent = { "uid" : root.uid, "startDate": root.startdt, "summary": root.summary, "description": root.description, "startHour": root.startHour + (root.startPm ? 12 : 0), "startMinute": root.startMinute, "allDay": root.allDay, "location": root.location, "endDate": root.enddt, "endHour": root.endHour + (root.endPm ? 12 : 0), "endMinute": root.endMinute };
controller.addEdit();
editcompleted();
}
else {
showPassiveNotification("Summary should not be empty");
}
}
}
}
TimePickerSheet {
id: startTimePickerSheet
}
TimePickerSheet {
id: endTimePickerSheet
}
Component {
id: eventController
Calindori.EventController {
}
}
}
/*
* Copyright 2018 Dimitris Kardarakos <dimkard@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import QtQuick 2.0
import QtQuick.Controls 2.4 as Controls2
import QtQuick.Layouts 1.11
import org.kde.kirigami 2.4 as Kirigami
import org.kde.phone.calindori 0.1 as Calindori
Kirigami.Page {
id: root
property date eventStartDt
property var calendar
signal editEvent(var modelData)
signal eventsUpdated
function reload()
{
cardsListview.model.loadEvents();
}
title: qsTr("Events")
actions.main: Kirigami.Action {
icon.name: "resource-calendar-insert"
text: qsTr("Add event")
onTriggered: pageStack.push(eventEditor, {startdt: eventStartDt, enddt: eventStartDt})
}
Component {
id: eventEditor
EventEditor {
calendar: localCalendar
onEditcompleted: {
eventsUpdated();
pageStack.pop(eventEditor);
}
}
}
Kirigami.CardsListView {
id: cardsListview
anchors.fill: parent
model: Calindori.EventModel {
filterdt: root.eventStartDt
memorycalendar: root.calendar.memorycalendar
}
delegate: Kirigami.Card {
banner.title: model.summary
banner.titleLevel: 3
actions: [
Kirigami.Action {
text: qsTr("Delete")
icon.name: "delete"
onTriggered: {
var controller = eventController.createObject(parent, { calendar: root.calendar });
controller.vevent = { uid: model.uid } ;
controller.remove();
eventsUpdated();
}
},
Kirigami.Action {
text: qsTr("Edit")
icon.name: "editor"
onTriggered: root.editEvent(model)
}
]
contentItem: Column {
Controls2.Label {
property bool sameEndStart : model.dtstart && !isNaN(model.dtstart) && model.dtend && !isNaN(model.dtend) && model.dtstart.toLocaleString(Qt.locale(), "dd.MM.yyyy") == model.dtend.toLocaleString(Qt.locale(), "dd.MM.yyyy")
wrapMode: Text.WordWrap
text: ((model.dtstart && !isNaN(model.dtstart)) ? model.dtstart.toLocaleString(Qt.locale(), "ddd d MMM yyyy hh:mm" ) : "") +
(model.dtend && !isNaN(model.dtend) ? " - " +
model.dtend.toLocaleString(Qt.locale(), sameEndStart ? "hh:mm" : "ddd d MMM yyyy hh:mm" ) : "")
}
Controls2.Label {
wrapMode: Text.WordWrap
text: model.description
}
Controls2.Label {
visible: model.location != ""
wrapMode: Text.WordWrap
text: model.location
}
}
}
}
Component {
id: eventController
Calindori.EventController {
}
}
}
......@@ -156,22 +156,16 @@ Kirigami.ApplicationWindow {
contextualActions: [
Kirigami.Action {
iconName: "view-calendar-tasks"
text: "Show tasks"
onTriggered: {
if(localCalendar.todosCount(calendarMonthView.selectedDate) > 0) {
root.pageStack.push(todosView, { todoDt: calendarMonthView.selectedDate });
}
else {
showPassiveNotification (i18n("There is no task for the day selected"));
}
}
text: "Tasks"
onTriggered: root.pageStack.push(todosView, { todoDt: calendarMonthView.selectedDate })
},
Kirigami.Action {
iconName: "resource-calendar-insert"
text: "Add task"
iconName: "view-calendar-events"
text: "Events"
onTriggered: root.pageStack.push(todoPage, { startdt: calendarMonthView.selectedDate} )
onTriggered: root.pageStack.push(eventsView, { eventStartDt: calendarMonthView.selectedDate })
}
]
}
......@@ -185,6 +179,10 @@ Kirigami.ApplicationWindow {
return localCalendar.todosCount(todosDate);
}
eventsCount: function (eventsDate) {
return localCalendar.eventsCount(eventsDate);
}
onSelectedDateChanged: {
if (root.pageStack.depth > 1) {
root.pageStack.pop(null);
......@@ -218,6 +216,24 @@ Kirigami.ApplicationWindow {
}
}
Component {
id: eventsView
EventsView {
calendar: localCalendar
onEditEvent: root.pageStack.push(eventEditor, { startdt: modelData.dtstart, enddt: modelData.dtend, uid: modelData.uid, eventData: modelData })
onEventsUpdated: root.refreshNeeded()
Connections {
target: root
onRefreshNeeded: reload()
}
}
}
Component {
id: todoPage
......@@ -230,6 +246,18 @@ Kirigami.ApplicationWindow {
}
}
Component {
id: eventEditor
EventEditor {
calendar: localCalendar
onEditcompleted: {
root.refreshNeeded();
root.pageStack.pop(eventEditor);
}
}
}
Component {
id: calendarInputPage
......
/*
* Copyright 2019 Dimitris Kardarakos
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import QtQuick 2.0
import QtQuick.Controls 2.4 as Controls2
import QtQuick.Layouts 1.11
import org.kde.kirigami 2.4 as Kirigami
import org.kde.phone.calindori 0.1 as Calindori
Kirigami.OverlaySheet {
id: timePickerSheet
property int hours
property int minutes
property bool pm
signal datePicked
rightPadding: 0
leftPadding: 0
contentItem: TimePicker {
id: timePicker
hours: timePickerSheet.hours
minutes: timePickerSheet.minutes
pm: timePickerSheet.pm
}
footer: RowLayout {
Item {
Layout.fillWidth: true
}
Controls2.ToolButton {
text: qsTr("OK")
onClicked: {
timePickerSheet.hours = timePicker.hours
timePickerSheet.minutes = timePicker.minutes
timePickerSheet.pm = timePicker.pm
timePickerSheet.datePicked()
timePickerSheet.close()
}
}
Controls2.ToolButton {
text: qsTr("Cancel")
onClicked: {
timePicker.hours = timePickerSheet.hours
timePicker.minutes = timePickerSheet.minutes
timePicker.pm = timePickerSheet.pm
timePickerSheet.close()
}
}
}
}
......@@ -27,6 +27,7 @@ ColumnLayout {
property date headerDate
property int headerTodosCount
property int headerEventsCount
RowLayout {
id: selectedDayHeading
......@@ -55,8 +56,10 @@ ColumnLayout {
}
Controls2.Label {
text: (root.headerTodosCount > 0) ? i18np("%1 task for today", "%1 tasks for today",root.headerTodosCount) : ""
text: ((root.headerTodosCount > 0) ? i18np("%1 task", "%1 tasks",root.headerTodosCount) : "") +
((root.headerTodosCount > 0 && root.headerEventsCount > 0) ? " and " : "") +
((root.headerEventsCount > 0) ? i18np("%1 event", "%1 events",root.headerEventsCount) : "")
opacity: 0.6
}
}
......@@ -40,7 +40,7 @@ Rectangle {
property int delegateWidth
property date selectedDate
property bool highlight: (model.yearNumber == selectedDate.getFullYear()) && (model.monthNumber == selectedDate.getMonth() + 1) && (model.dayNumber == root.selectedDate.getDate())
property int todosCount
property int incidentsCount
signal dayClicked
......@@ -56,7 +56,7 @@ Rectangle {
/**
* Display a tiny indicator in case that
* todos exist for the day of the model
* todos or events exist for the day of the model
*/
Rectangle {
anchors {
......@@ -71,7 +71,7 @@ Rectangle {
height: width
radius: 50
color: Kirigami.Theme.selectionFocusColor
visible: todosCount > 0
visible: incidentsCount > 0
}
Controls2.ToolButton {
......
......@@ -39,6 +39,7 @@ Item {
property int dayRectWidth: Kirigami.Units.gridUnit*2.5
property date selectedDate: new Date()
property int selectedDayTodosCount: 0
property int selectedDayEventsCount: 0
property string currentMonthName
/**
* A model that provides:
......@@ -58,11 +59,23 @@ Item {
property var todosCount: function (todosDate) {
return 0;
}
/**
* Function that returns the amount of events of each day
*
* If implemented, a small indicator will be displayed
* into the cell of each day. Default implementation returns 0,
* so no indicator is displayed.
*/
property var eventsCount: function (eventsDate) {
return 0;
}
property bool showHeader: false
property bool showMonthName: true
function reloadSelectedDate() {
root.selectedDayTodosCount = root.todosCount(root.selectedDate)
root.selectedDayEventsCount = root.eventsCount(root.selectedDate)
}
onSelectedDateChanged: reloadSelectedDate()
......@@ -83,6 +96,7 @@ Item {
Layout.bottomMargin: Kirigami.Units.gridUnit / 2
headerDate: root.selectedDate
headerTodosCount: root.selectedDayTodosCount
headerEventsCount: root.selectedDayEventsCount
visible: root.showHeader
}
......@@ -133,7 +147,8 @@ Item {
currentDate: root.currentDate
delegateWidth: root.dayRectWidth
selectedDate: root.selectedDate
todosCount: root.todosCount(new Date(model.yearNumber, model.monthNumber -1, model.dayNumber))
incidentsCount: root.todosCount(new Date(model.yearNumber, model.monthNumber -1, model.dayNumber))
+ root.eventsCount(new Date(model.yearNumber, model.monthNumber -1, model.dayNumber))
onDayClicked: root.selectedDate = new Date(model.yearNumber, model.monthNumber -1, model.dayNumber)
}
......
......@@ -3,6 +3,8 @@ set(qmlplugin_SRCS
calindoriconfig.cpp
todosmodel.cpp
localcalendar.cpp
eventmodel.cpp
eventcontroller.cpp
)
add_library (calindoriqmlplugin SHARED ${qmlplugin_SRCS})
......
/*
* Copyright (C) 2019 Dimitris Kardarakos
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 3 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "eventcontroller.h"
#include "localcalendar.h"
#include <QDebug>
EventController::EventController(QObject* parent) : QObject(parent) {}
EventController::~EventController() = default;
QObject* EventController::calendar() const
{
return m_calendar;
}
void EventController::setCalendar(QObject * const calendarPtr)
{
if(calendarPtr != m_calendar)
{
m_calendar = calendarPtr;
}
emit calendarChanged();
}
QVariantMap EventController::vevent() const
{
return m_event;
}
void EventController::setVevent(const QVariantMap& event)
{
m_event = event;
}