WeekView.qml 42.5 KB
Newer Older
Claudio Cambra's avatar
Claudio Cambra committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// SPDX-FileCopyrightText: 2021 Claudio Cambra <claudio.cambra@gmail.com>
// SPDX-License-Identifier: GPL-2.0-or-later

import QtQuick 2.15
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.15 as QQC2
import org.kde.kirigami 2.14 as Kirigami
import QtGraphicalEffects 1.12

import org.kde.kalendar 1.0 as Kalendar
import "dateutils.js" as DateUtils
import "labelutils.js" as LabelUtils

Kirigami.Page {
    id: root

    signal addIncidence(int type, date addDate, bool includeTime)
    signal viewIncidence(var modelData, var collectionData)
    signal editIncidence(var incidencePtr, var collectionId)
    signal deleteIncidence(var incidencePtr, date deleteDate)
    signal completeTodo(var incidencePtr)
    signal addSubTodo(var parentWrapper)
23
    signal deselect()
Claudio Cambra's avatar
Claudio Cambra committed
24
25

    property var openOccurrence: {}
26
27
    property var model

Claudio Cambra's avatar
Claudio Cambra committed
28
29
30
31
32
33
34
35
36
37
38
    property date selectedDate: new Date()
    property date startDate: DateUtils.getFirstDayOfMonth(selectedDate)
    property date currentDate: new Date() // Needs to get updated for marker to move, done from main.qml
    readonly property int currentDay: currentDate ? currentDate.getDate() : null
    readonly property int currentMonth: currentDate ? currentDate.getMonth() : null
    readonly property int currentYear: currentDate ? currentDate.getFullYear() : null
    property int day: selectedDate.getDate()
    property int month: selectedDate.getMonth()
    property int year: selectedDate.getFullYear()
    property bool initialWeek: true
    property int daysToShow: 7
39
    readonly property int minutesFromStartOfDay: (root.currentDate.getHours() * 60) + root.currentDate.getMinutes()
Claudio Cambra's avatar
Claudio Cambra committed
40
41
42
43
44
45
46
    readonly property bool isDark: LabelUtils.isDarkColor(Kirigami.Theme.backgroundColor)

    property real scrollbarWidth: 0
    readonly property real dayWidth: ((root.width - hourLabelWidth - leftPadding - scrollbarWidth) / daysToShow) - gridLineWidth
    readonly property real incidenceSpacing: Kirigami.Units.smallSpacing / 2
    readonly property real gridLineWidth: 1.0
    readonly property real hourLabelWidth: Kirigami.Units.gridUnit * 3.5
47
    readonly property real periodHeight: Kirigami.Units.gridUnit / 2
Claudio Cambra's avatar
Claudio Cambra committed
48
49
50
51
52
53
54
55
56
57

    Kirigami.Theme.inherit: false
    Kirigami.Theme.colorSet: Kirigami.Theme.View

    background: Rectangle {
        color: Kirigami.Theme.backgroundColor
    }

    function setToDate(date, isInitialWeek = false) {
        root.initialWeek = isInitialWeek;
58

Claudio Cambra's avatar
Claudio Cambra committed
59
60
61
62
        date = DateUtils.getFirstDayOfWeek(date);
        const weekDiff = Math.round((date - pathView.currentItem.startDate) / (root.daysToShow * 24 * 60 * 60 * 1000));

        let newIndex = pathView.currentIndex + weekDiff;
63
64
        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);
Claudio Cambra's avatar
Claudio Cambra committed
65
66
67

        while(firstItemDate >= date) {
            pathView.model.addDates(false)
68
            firstItemDate = pathView.model.data(pathView.model.index(1,0), Kalendar.InfiniteCalendarViewModel.StartDateRole);
Claudio Cambra's avatar
Claudio Cambra committed
69
70
71
72
73
74
75
76
            newIndex = 0;
        }
        if(firstItemDate < date && newIndex === 0) {
            newIndex = Math.round((date - firstItemDate) / (root.daysToShow * 24 * 60 * 60 * 1000)) + 1
        }

        while(lastItemDate <= date) {
            pathView.model.addDates(true)
77
            lastItemDate = pathView.model.data(pathView.model.index(pathView.model.rowCount() - 1,0), Kalendar.InfiniteCalendarViewModel.StartDateRole);
Claudio Cambra's avatar
Claudio Cambra committed
78
79
80
        }
        pathView.currentIndex = newIndex;
        selectedDate = date;
81
82
83
84

        if(isInitialWeek) {
            pathView.currentItem.item.hourScrollView.setToCurrentTime();
        }
Claudio Cambra's avatar
Claudio Cambra committed
85
    }
86
87
88
89
90
91
92
93
94
95
96
97
98
99
    readonly property Kirigami.Action previousAction: Kirigami.Action {
        icon.name: "go-previous"
        text: i18n("Previous Week")
        shortcut: "Left"
        onTriggered: setToDate(DateUtils.addDaysToDate(pathView.currentItem.startDate, -root.daysToShow))
        displayHint: Kirigami.DisplayHint.IconOnly
    }
    readonly property Kirigami.Action nextAction: Kirigami.Action {
        icon.name: "go-next"
        text: i18n("Next Week")
        shortcut: "Right"
        onTriggered: setToDate(DateUtils.addDaysToDate(pathView.currentItem.startDate, root.daysToShow))
        displayHint: Kirigami.DisplayHint.IconOnly
    }
100
101
102
    readonly property Kirigami.Action todayAction: Kirigami.Action {
        icon.name: "go-jump-today"
        text: i18n("Today")
103
        onTriggered: setToDate(new Date(), true);
104
    }
Claudio Cambra's avatar
Claudio Cambra committed
105
106

    actions {
107
108
        left: Qt.application.layoutDirection === Qt.RightToLeft ? nextAction : previousAction
        right: Qt.application.layoutDirection === Qt.RightToLeft ? previousAction : nextAction
109
        main: todayAction
Claudio Cambra's avatar
Claudio Cambra committed
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
    }

    padding: 0

    PathView {
        id: pathView

        anchors.fill: parent
        flickDeceleration: Kirigami.Units.longDuration
        preferredHighlightBegin: 0.5
        preferredHighlightEnd: 0.5
        snapMode: PathView.SnapToItem
        focus: true
        interactive: Kirigami.Settings.tabletMode

        path: Path {
            startX: - pathView.width * pathView.count / 2 + pathView.width / 2
            startY: pathView.height / 2
            PathLine {
                x: pathView.width * pathView.count / 2 + pathView.width / 2
                y: pathView.height / 2
            }
        }

134
        model: root.model
Claudio Cambra's avatar
Claudio Cambra committed
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157

        property date dateToUse
        property int startIndex
        Component.onCompleted: {
            startIndex = count / 2;
            currentIndex = startIndex;
        }
        onCurrentIndexChanged: {
            root.startDate = currentItem.startDate;
            root.month = currentItem.month;
            root.year = currentItem.year;

            if(currentIndex >= count - 2) {
                model.addDates(true);
            } else if (currentIndex <= 1) {
                model.addDates(false);
                startIndex += model.weeksToAdd;
            }
        }

        delegate: Loader {
            id: viewLoader

158
159
160
            readonly property date startDate: model.startDate
            readonly property int month: model.selectedMonth - 1 // Convert QDateTime month to JS month
            readonly property int year: model.selectedYear
Claudio Cambra's avatar
Claudio Cambra committed
161

162
163
164
            readonly property int index: model.index
            readonly property bool isCurrentItem: PathView.isCurrentItem
            readonly property bool isNextOrCurrentItem: index >= pathView.currentIndex -1 && index <= pathView.currentIndex + 1
165
            property int multiDayLinesShown: 0
Claudio Cambra's avatar
Claudio Cambra committed
166

167
            readonly property int daysFromWeekStart: DateUtils.fullDaysBetweenDates(startDate, root.currentDate) - 1
168
            // As long as the date is even slightly larger, it will return 1; since we start from the startDate at 00:00, adjust
169

Claudio Cambra's avatar
Claudio Cambra committed
170
            active: isNextOrCurrentItem
171
172
            asynchronous: !isCurrentItem
            visible: status === Loader.Ready
173
174
            sourceComponent: Column {
                id: viewColumn
Claudio Cambra's avatar
Claudio Cambra committed
175
176
177
178
                width: pathView.width
                height: pathView.height
                spacing: 0

179
180
                readonly property alias hourScrollView: hourlyView

Claudio Cambra's avatar
Claudio Cambra committed
181
                Row {
182
183
                    id: headingRow
                    width: pathView.width
Claudio Cambra's avatar
Claudio Cambra committed
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
                    spacing: root.gridLineWidth

                    Kirigami.Heading {
                        id: weekNumberHeading

                        width: root.hourLabelWidth - root.gridLineWidth
                        horizontalAlignment: Text.AlignRight
                        padding: Kirigami.Units.smallSpacing
                        level: 2
                        text: DateUtils.getWeek(viewLoader.startDate, Qt.locale().firstDayOfWeek)
                        color: Kirigami.Theme.disabledTextColor
                        background: Rectangle {
                            color: Kirigami.Theme.backgroundColor
                        }
                    }

                    Repeater {
                        id: dayHeadings

203
                        model: weekViewModel.rowCount()
Claudio Cambra's avatar
Claudio Cambra committed
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
                        delegate: Kirigami.Heading {
                            id: dayHeading

                            FontMetrics {
                                id: dayTitleMetrics
                            }

                            property date headingDate: DateUtils.addDaysToDate(viewLoader.startDate, index)
                            property bool isToday: headingDate.getDate() === root.currentDay &&
                                                   headingDate.getMonth() === root.currentMonth &&
                                                   headingDate.getFullYear() === root.currentYear
                            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>dd</b>");
                                const mediumText = headingDate.toLocaleDateString(Qt.locale(), "ddd <b>dd</b>");
                                const shortText = mediumText.slice(0,1) + " " + headingDate.toLocaleDateString(Qt.locale(), "<b>dd</b>");


                                if(dayTitleMetrics.boundingRect(longText).width < width) {
                                    return longText;
                                } else if(dayTitleMetrics.boundingRect(mediumText).width < width) {
                                    return mediumText;
                                } else {
                                    return shortText;
                                }
                            }
                            background: Rectangle {
                                color: dayHeading.isToday ? Kirigami.Theme.activeBackgroundColor : Kirigami.Theme.backgroundColor
                            }
                        }
                    }
239
240
241
242
243
                    Rectangle { // Cover up the shadow of headerTopSeparator above the scrollbar
                        color: Kirigami.Theme.backgroundColor
                        height: parent.height
                        width: root.scrollbarWidth
                    }
Claudio Cambra's avatar
Claudio Cambra committed
244
245
246
247
                }

                Kirigami.Separator {
                    id: headerTopSeparator
248
                    width: pathView.width
Claudio Cambra's avatar
Claudio Cambra committed
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
                    height: root.gridLineWidth
                    z: -1

                    RectangularGlow {
                        anchors.fill: parent
                        z: -1
                        glowRadius: 5
                        spread: 0.3
                        color: Qt.rgba(0.0, 0.0, 0.0, 0.15)
                        visible: !allDayViewLoader.active
                    }
                }

                Item {
                    id: allDayHeader
264
265
                    width: pathView.width
                    height: actualHeight
Claudio Cambra's avatar
Claudio Cambra committed
266
                    visible: allDayViewLoader.active
267
268
269
270
271
272
273
274
275
276
277
278

                    readonly property int minHeight: Kirigami.Units.gridUnit *2
                    readonly property int maxHeight: pathView.height / 3
                    readonly property int lineHeight: viewLoader.multiDayLinesShown * (Kirigami.Units.gridUnit + Kirigami.Units.smallSpacing + root.incidenceSpacing) + Kirigami.Units.smallSpacing
                    readonly property int defaultHeight: Math.min(lineHeight, maxHeight)
                    property int actualHeight: {
                        if (Kalendar.Config.weekViewAllDayHeaderHeight === -1) {
                            return defaultHeight;
                        } else {
                            return Kalendar.Config.weekViewAllDayHeaderHeight;
                        }
                    }
Claudio Cambra's avatar
Claudio Cambra committed
279

280
281
282
283
284
285
286
287
288
289
290
291
292
293
                    NumberAnimation {
                        id: resetAnimation
                        target: allDayHeader
                        property: "height"
                        to: allDayHeader.defaultHeight
                        duration: Kirigami.Units.longDuration
                        easing.type: Easing.InOutQuad
                        onFinished: {
                            Kalendar.Config.weekViewAllDayHeaderHeight = -1;
                            Kalendar.Config.save();
                            allDayHeader.actualHeight = allDayHeader.defaultHeight;
                        }
                    }

Claudio Cambra's avatar
Claudio Cambra committed
294
295
296
297
298
299
                    Rectangle {
                        id: headerBackground
                        anchors.fill: parent
                        color: Kirigami.Theme.backgroundColor
                    }

300
301
302
303
                    Kirigami.ShadowedRectangle {
                        anchors.left: parent.left
                        anchors.top: parent.bottom
                        width: root.hourLabelWidth
304
305
306
                        height: Kalendar.Config.weekViewAllDayHeaderHeight !== -1 ?
                            resetHeaderHeightButton.height :
                            0
307
308
309
310
311
312
313
314
315
316
                        z: -1
                        corners.bottomRightRadius: Kirigami.Units.smallSpacing
                        shadow.size: Kirigami.Units.largeSpacing
                        shadow.color: Qt.rgba(0.0, 0.0, 0.0, 0.2)
                        shadow.yOffset: 2
                        shadow.xOffset: 2
                        color: Kirigami.Theme.backgroundColor
                        border.width: root.gridLineWidth
                        border.color: headerBottomSeparator.color

317
318
319
320
321
322
                        Behavior on height { NumberAnimation {
                            duration: Kirigami.Units.shortDuration
                            easing.type: Easing.InOutQuad
                        } }

                        Item {
323
                            width: root.hourLabelWidth
324
325
326
327
328
329
330
331
                            height: parent.height
                            clip: true

                            QQC2.ToolButton {
                                id: resetHeaderHeightButton
                                width: root.hourLabelWidth
                                text: i18nc("@action:button", "Reset")
                                onClicked: resetAnimation.start()
332
333
334
335
                            }
                        }
                    }

Claudio Cambra's avatar
Claudio Cambra committed
336
337
                    QQC2.Label {
                        width: root.hourLabelWidth
338
                        height: parent.height
Claudio Cambra's avatar
Claudio Cambra committed
339
340
341
342
                        padding: Kirigami.Units.smallSpacing
                        leftPadding: Kirigami.Units.largeSpacing
                        verticalAlignment: Text.AlignTop
                        horizontalAlignment: Text.AlignRight
343
                        text: i18n("All day or Multi day")
Claudio Cambra's avatar
Claudio Cambra committed
344
                        wrapMode: Text.Wrap
345
346
                        elide: Text.ElideRight
                        font: Kirigami.Theme.smallFont
Claudio Cambra's avatar
Claudio Cambra committed
347
348
349
350
351
352
353
                        color: Kirigami.Theme.disabledTextColor
                    }

                    Loader {
                        id: allDayViewLoader
                        anchors.fill: parent
                        anchors.leftMargin: root.hourLabelWidth
354
                        active: weekViewMultiDayViewModel.incidenceCount > 0
Claudio Cambra's avatar
Claudio Cambra committed
355
                        sourceComponent: Item {
356
357
                            id: allDayViewItem
                            implicitHeight: allDayHeader.actualHeight
Claudio Cambra's avatar
Claudio Cambra committed
358
359
360
                            clip: true

                            Repeater {
361
                                model: weekViewMultiDayViewModel // from root.model
Claudio Cambra's avatar
Claudio Cambra committed
362
363
364
                                Layout.topMargin: Kirigami.Units.largeSpacing
                                //One row => one week
                                Item {
365
                                    id: weekItem
Claudio Cambra's avatar
Claudio Cambra committed
366
                                    width: parent.width
367
                                    implicitHeight: allDayHeader.actualHeight
Claudio Cambra's avatar
Claudio Cambra committed
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
                                    clip: true
                                    RowLayout {
                                        width: parent.width
                                        height: parent.height
                                        spacing: root.gridLineWidth
                                        Item {
                                            id: dayDelegate
                                            Layout.fillWidth: true
                                            Layout.fillHeight: true
                                            readonly property date startDate: periodStartDate

                                            QQC2.ScrollView {
                                                id: linesListViewScrollView
                                                anchors {
                                                    fill: parent
                                                }

                                                QQC2.ScrollBar.horizontal.policy: QQC2.ScrollBar.AlwaysOff

                                                ListView {
                                                    id: linesRepeater
                                                    Layout.fillWidth: true
390
                                                    Layout.rightMargin: spacing
Claudio Cambra's avatar
Claudio Cambra committed
391
392
393
394
395
396
397
398
399
400
401
402
403

                                                    clip: true
                                                    spacing: root.incidenceSpacing

                                                    ListView {
                                                        id: allDayIncidencesBackgroundView
                                                        anchors.fill: parent
                                                        spacing: root.gridLineWidth
                                                        orientation: Qt.Horizontal
                                                        z: -1

                                                        Kirigami.Separator {
                                                            anchors.fill: parent
404
                                                            anchors.rightMargin: root.scrollbarWidth
Claudio Cambra's avatar
Claudio Cambra committed
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
                                                            z: -1
                                                        }

                                                        model: root.daysToShow
                                                        delegate: Rectangle {
                                                            id: multiDayViewBackground

                                                            readonly property date date: DateUtils.addDaysToDate(viewLoader.startDate, index)
                                                            readonly property bool isToday: date.getDate() === root.currentDay &&
                                                                date.getMonth() === root.currentMonth &&
                                                                date.getFullYear() === root.currentYear

                                                            width: root.dayWidth
                                                            height: linesListViewScrollView.height
                                                            color: isToday ? Kirigami.Theme.activeBackgroundColor : Kirigami.Theme.backgroundColor

                                                            DayMouseArea {
                                                                id: listViewMenu
                                                                anchors.fill: parent

                                                                addDate: parent.date
                                                                onAddNewIncidence: root.addIncidence(type, addDate, false)
427
                                                                onDeselect: root.deselect()
Claudio Cambra's avatar
Claudio Cambra committed
428
429
430
431
432
                                                            }
                                                        }
                                                    }

                                                    model: incidences
433
434
435
                                                    onCountChanged: {
                                                        viewLoader.multiDayLinesShown = count
                                                    }
Claudio Cambra's avatar
Claudio Cambra committed
436
437
438
439
440
441
442
443
444

                                                    delegate: Item {
                                                        id: line
                                                        height: Kirigami.Units.gridUnit + Kirigami.Units.smallSpacing

                                                        //Incidences
                                                        Repeater {
                                                            id: incidencesRepeater
                                                            model: modelData
445
446
447
448
449
450
451
                                                            MultiDayViewIncidenceDelegate {
                                                                dayWidth: root.dayWidth
                                                                parentViewSpacing: root.gridLineWidth
                                                                horizontalSpacing: linesRepeater.spacing
                                                                openOccurrenceId: root.openOccurrence ? root.openOccurrence.incidenceId : ""
                                                                isDark: root.isDark
                                                                reactToCurrentMonth: false
Claudio Cambra's avatar
Claudio Cambra committed
452
453
454
455
456
457
458
459
460
461
462
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494

                    MouseArea {
                        anchors.left: parent.left
                        anchors.bottom: parent.bottom
                        anchors.right: parent.right
                        height: 5
                        z: Infinity
                        cursorShape: !Kirigami.Settings.isMobile ? Qt.SplitVCursor : undefined
                        preventStealing: true
                        enabled: true
                        visible: true
                        onPressed: {
                            _lastY = mapToGlobal(mouseX, mouseY).y;
                            if(Kalendar.Config.weekViewAllDayHeaderHeight === -1) {
                                // Stops shrink on first drag
                                Kalendar.Config.weekViewAllDayHeaderHeight = allDayHeader.defaultHeight;
                            }
                        }
                        onReleased: {
                            Kalendar.Config.weekViewAllDayHeaderHeight = allDayHeader.actualHeight;
                            Kalendar.Config.save();
                        }
                        property real _lastY: -1

                        onPositionChanged: {
                            if (_lastY === -1) {
                                return;
                            } else {
                                allDayHeader.actualHeight = Math.min(allDayHeader.maxHeight, Math.max(allDayHeader.minHeight, Kalendar.Config.weekViewAllDayHeaderHeight - _lastY + mapToGlobal(mouseX, mouseY).y))
                            }
                        }
                    }
Claudio Cambra's avatar
Claudio Cambra committed
495
496
497
498
                }

                Kirigami.Separator {
                    id: headerBottomSeparator
499
                    width: pathView.width
Claudio Cambra's avatar
Claudio Cambra committed
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
                    height: root.gridLineWidth
                    z: -1
                    visible: allDayViewLoader.active

                    RectangularGlow {
                        anchors.fill: parent
                        z: -1
                        glowRadius: 5
                        spread: 0.3
                        color: Qt.rgba(0.0, 0.0, 0.0, 0.15)
                    }
                }

                QQC2.ScrollView {
                    id: hourlyView
515
516
                    width: viewColumn.width
                    height: viewColumn.height - headerBottomSeparator.height - allDayHeader.height - headerTopSeparator.height - headingRow.height
Claudio Cambra's avatar
Claudio Cambra committed
517
518
519
520
                    contentWidth: availableWidth
                    z: -2
                    QQC2.ScrollBar.horizontal.policy: QQC2.ScrollBar.AlwaysOff

521
522
523
524
                    readonly property real periodsPerHour: 60 / weekViewModel.periodLength
                    readonly property real daySections: (60 * 24) / weekViewModel.periodLength
                    readonly property real dayHeight: (daySections * root.periodHeight) + (root.gridLineWidth * 23)
                    readonly property real hourHeight: periodsPerHour * root.periodHeight
Claudio Cambra's avatar
Claudio Cambra committed
525
                    readonly property real minuteHeight: hourHeight / 60
526
                    readonly property Item vScrollBar: QQC2.ScrollBar.vertical
Claudio Cambra's avatar
Claudio Cambra committed
527

528
529
530
531
532
533
534
                    function setToCurrentTime() {
                        if(currentTimeMarkerLoader.active) {
                            const viewHeight = (applicationWindow().height - applicationWindow().pageStack.globalToolBar.height - headerBottomSeparator.height - allDayHeader.height - headerTopSeparator.height - headingRow.height - Kirigami.Units.gridUnit);
                            // Since we position with anchors, height is 0 -- must calc manually

                            let yPos = (currentTimeMarkerLoader.item.y / dayHeight) - ((viewHeight / 2) / dayHeight)
                            yPos = Math.max(0.0, yPos);
535
                            yPos = vScrollBar.size ? Math.min(vScrollBar.size, yPos) : Math.min(1.0, yPos);
536
537
538
539
540

                            vScrollBar.position = yPos;
                        }
                    }

Claudio Cambra's avatar
Claudio Cambra committed
541
542
543
                    Connections {
                        target: hourlyView.QQC2.ScrollBar.vertical
                        function onWidthChanged() {
544
                            if(!Kirigami.Settings.isMobile) root.scrollbarWidth = hourlyView.QQC2.ScrollBar.vertical.width;
Claudio Cambra's avatar
Claudio Cambra committed
545
546
                        }
                    }
547
                    Component.onCompleted: {
548
                        if(!Kirigami.Settings.isMobile) root.scrollbarWidth = hourlyView.QQC2.ScrollBar.vertical.width;
549
550
                        if(currentTimeMarkerLoader.active && root.initialWeek) {
                            setToCurrentTime();
551
                        }
552
                    }
Claudio Cambra's avatar
Claudio Cambra committed
553
554
555

                    Item {
                        id: hourlyViewContents
556
557
                        width: parent.width
                        implicitHeight: hourlyView.dayHeight
Claudio Cambra's avatar
Claudio Cambra committed
558
559
560

                        clip: true

561
                        Item {
Claudio Cambra's avatar
Claudio Cambra committed
562
                            id: hourLabelsColumn
563

564
565
566
567
568
569
                            property real currentTimeLabelTop: currentTimeLabelLoader.active ?
                                currentTimeLabelLoader.item.y
                                : 0
                            property real currentTimeLabelBottom: currentTimeLabelLoader.active ?
                                currentTimeLabelLoader.item.y + fontMetrics.height
                                : 0
570

Claudio Cambra's avatar
Claudio Cambra committed
571
572
573
574
575
576
577
578
579
                            anchors.left: parent.left
                            anchors.top: parent.top
                            anchors.bottom: parent.bottom
                            width: root.hourLabelWidth

                            FontMetrics {
                                id: fontMetrics
                            }

580
581
582
                            Loader {
                                id: currentTimeLabelLoader

583
                                active: currentTimeMarkerLoader.active
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
                                sourceComponent: QQC2.Label {
                                    id: currentTimeLabel

                                    width: root.hourLabelWidth
                                    color: Kirigami.Theme.highlightColor
                                    font.weight: Font.DemiBold
                                    horizontalAlignment: Text.AlignRight
                                    rightPadding: Kirigami.Units.smallSpacing
                                    y: Math.max(0, (root.currentDate.getHours() * root.gridLineWidth) + (hourlyView.minuteHeight * root.minutesFromStartOfDay) - (implicitHeight / 2)) - (root.gridLineWidth / 2)
                                    z: 100

                                    text: root.currentDate.toLocaleTimeString(Qt.locale(), Locale.NarrowFormat)

                                }
                            }

600
601
                            Repeater {
                                model: pathView.model.weekViewLocalisedHourLabels // Not a model role but instead one of the model object's properties
602

603
                                delegate: QQC2.Label {
604
605
                                    property real textYTop: y
                                    property real textYBottom: y + fontMetrics.height
606
                                    property bool overlapWithCurrentTimeLabel: currentTimeLabelLoader.active &&
607
608
609
                                        ((hourLabelsColumn.currentTimeLabelTop <= textYTop && hourLabelsColumn.currentTimeLabelBottom >= textYTop) ||
                                        (hourLabelsColumn.currentTimeLabelTop < textYBottom && hourLabelsColumn.currentTimeLabelBottom > textYBottom) ||
                                        (hourLabelsColumn.currentTimeLabelTop >= textYTop && hourLabelsColumn.currentTimeLabelBottom <= textYBottom))
610

611
                                    y: ((root.periodHeight * hourlyView.periodsPerHour) * (index + 1)) + (root.gridLineWidth * (index + 1)) -
612
613
614
615
616
617
618
                                        (fontMetrics.height / 2) - (root.gridLineWidth / 2)
                                    width: root.hourLabelWidth
                                    rightPadding: Kirigami.Units.smallSpacing
                                    verticalAlignment: Text.AlignBottom
                                    horizontalAlignment: Text.AlignRight
                                    text: modelData
                                    color: Kirigami.Theme.disabledTextColor
619
                                    visible: !overlapWithCurrentTimeLabel
620
                                }
Claudio Cambra's avatar
Claudio Cambra committed
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
                            }
                        }

                        Item {
                            id: innerWeekView
                            anchors {
                                left: hourLabelsColumn.right
                                top: parent.top
                                bottom: parent.bottom
                                right: parent.right
                            }
                            clip: true

                            Kirigami.Separator {
                                anchors.fill: parent
                            }

                            ListView {
                                anchors.fill: parent
                                spacing: root.gridLineWidth
                                orientation: Qt.Horizontal
642
                                model: weekViewModel // From root.model
Claudio Cambra's avatar
Claudio Cambra committed
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661

                                boundsBehavior: Flickable.StopAtBounds

                                delegate: Item {
                                    id: dayColumn

                                    readonly property int index: model.index
                                    readonly property date columnDate: DateUtils.addDaysToDate(viewLoader.startDate, index)
                                    readonly property bool isToday: columnDate.getDate() === root.currentDay &&
                                        columnDate.getMonth() === root.currentMonth &&
                                        columnDate.getFullYear() === root.currentYear

                                    width: root.dayWidth
                                    height: hourlyView.dayHeight
                                    clip: true

                                    ListView {
                                        anchors.fill: parent
                                        spacing: root.gridLineWidth
662
                                        boundsBehavior: Flickable.StopAtBounds
663
                                        interactive: false
Claudio Cambra's avatar
Claudio Cambra committed
664
665
666
667
668
669
670
671
672
673
674

                                        model: 24
                                        delegate: Rectangle {
                                            width: parent.width
                                            height: hourlyView.hourHeight
                                            color: dayColumn.isToday ? Kirigami.Theme.activeBackgroundColor : Kirigami.Theme.backgroundColor

                                            DayMouseArea {
                                                anchors.fill: parent
                                                addDate: new Date(DateUtils.addDaysToDate(viewLoader.startDate, dayColumn.index).setHours(index))
                                                onAddNewIncidence: addIncidence(type, addDate, true)
675
                                                onDeselect: root.deselect()
Claudio Cambra's avatar
Claudio Cambra committed
676
677
678
679
680
681
682
683
684
685
686
687
688
689
                                            }
                                        }
                                    }

                                    Repeater {
                                        id: incidencesRepeater
                                        model: incidences
                                        delegate: Rectangle {
                                            readonly property real gridLineYCompensation: (modelData.starts / hourlyView.periodsPerHour) * root.gridLineWidth
                                            readonly property real gridLineHeightCompensation: (modelData.duration / hourlyView.periodsPerHour) * root.gridLineWidth
                                            readonly property bool isOpenOccurrence: root.openOccurrence ?
                                                root.openOccurrence.incidenceId === modelData.incidenceId : false

                                            x: root.incidenceSpacing + (modelData.priorTakenWidthShare * root.dayWidth)
690
                                            y: (modelData.starts * root.periodHeight) + root.incidenceSpacing + gridLineYCompensation
Claudio Cambra's avatar
Claudio Cambra committed
691
                                            width: (root.dayWidth * modelData.widthShare) - (root.incidenceSpacing * 2)
692
                                            height: (modelData.duration * root.periodHeight) - (root.incidenceSpacing * 2) + gridLineHeightCompensation - root.gridLineWidth
693
                                            radius: Kirigami.Units.smallSpacing
Claudio Cambra's avatar
Claudio Cambra committed
694
                                            color: Qt.rgba(0,0,0,0)
695
                                            clip: true
Claudio Cambra's avatar
Claudio Cambra committed
696
697
                                            visible: !modelData.allDay

698
                                            IncidenceBackground {
Claudio Cambra's avatar
Claudio Cambra committed
699
                                                id: incidenceBackground
700
701
                                                isOpenOccurrence: parent.isOpenOccurrence
                                                isDark: root.isDark
Claudio Cambra's avatar
Claudio Cambra committed
702
703
704
705
706
707
                                            }

                                            ColumnLayout {
                                                id: incidenceContents

                                                readonly property color textColor: LabelUtils.getIncidenceLabelColor(modelData.color, root.isDark)
708
                                                readonly property bool isTinyHeight: parent.height <= Kirigami.Units.gridUnit
Claudio Cambra's avatar
Claudio Cambra committed
709
710
711
712
713

                                                anchors {
                                                    fill: parent
                                                    leftMargin: Kirigami.Units.smallSpacing
                                                    rightMargin: Kirigami.Units.smallSpacing
714
715
                                                    topMargin: !isTinyHeight ? Kirigami.Units.smallSpacing : 0
                                                    bottomMargin: !isTinyHeight ? Kirigami.Units.smallSpacing : 0
Claudio Cambra's avatar
Claudio Cambra committed
716
717
718
719
720
721
722
723
724
725
                                                }

                                                QQC2.Label {
                                                    Layout.fillWidth: true
                                                    Layout.fillHeight: true
                                                    text: modelData.text
                                                    horizontalAlignment: Text.AlignLeft
                                                    verticalAlignment: Text.AlignTop
                                                    wrapMode: Text.Wrap
                                                    elide: Text.ElideRight
726
727
                                                    font.pointSize: parent.isTinyHeight ? Kirigami.Theme.smallFont.pointSize :
                                                        Kirigami.Theme.defaultFont.pointSize
Claudio Cambra's avatar
Claudio Cambra committed
728
                                                    font.weight: Font.Medium
729
                                                    font.strikeout: modelData.todoCompleted
730
                                                    renderType: Text.QtRendering
Claudio Cambra's avatar
Claudio Cambra committed
731
                                                    color: isOpenOccurrence ? (LabelUtils.isDarkColor(modelData.color) ? "white" : "black") :
732
                                                        incidenceContents.textColor
733
                                                    Behavior on color { ColorAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.OutCubic } }
Claudio Cambra's avatar
Claudio Cambra committed
734
735
736
737
738
739
740
741
742
743
744
745
746
                                                }

                                                RowLayout {
                                                    width: parent.width
                                                    visible: parent.height > Kirigami.Units.gridUnit * 3
                                                    Kirigami.Icon {
                                                        id: incidenceIcon
                                                        implicitWidth: Kirigami.Units.iconSizes.smallMedium
                                                        implicitHeight: Kirigami.Units.iconSizes.smallMedium
                                                        source: modelData.incidenceTypeIcon
                                                        isMask: true
                                                        color: isOpenOccurrence ? (LabelUtils.isDarkColor(modelData.color) ? "white" : "black") :
                                                            incidenceContents.textColor
747
                                                        Behavior on color { ColorAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.OutCubic } }
Claudio Cambra's avatar
Claudio Cambra committed
748
749
750
751
752
753
754
755
                                                        visible: parent.width > Kirigami.Units.gridUnit * 4
                                                    }
                                                    QQC2.Label {
                                                        id: timeLabel
                                                        Layout.fillWidth: true
                                                        horizontalAlignment: Text.AlignRight
                                                        text: modelData.startTime.toLocaleTimeString(Qt.locale(), Locale.NarrowFormat) + " - " + modelData.endTime.toLocaleTimeString(Qt.locale(), Locale.NarrowFormat)
                                                        wrapMode: Text.Wrap
756
                                                        renderType: Text.QtRendering
Claudio Cambra's avatar
Claudio Cambra committed
757
758
                                                        color: isOpenOccurrence ? (LabelUtils.isDarkColor(modelData.color) ? "white" : "black") :
                                                            incidenceContents.textColor
759
                                                        Behavior on color { ColorAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.OutCubic } }
Claudio Cambra's avatar
Claudio Cambra committed
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
                                                        visible: parent.width > Kirigami.Units.gridUnit * 3
                                                    }
                                                }
                                            }

                                            IncidenceMouseArea {
                                                incidenceData: modelData
                                                collectionId: modelData.collectionId

                                                onViewClicked: viewIncidence(modelData, collectionData)
                                                onEditClicked: editIncidence(incidencePtr, collectionId)
                                                onDeleteClicked: deleteIncidence(incidencePtr, deleteDate)
                                                onTodoCompletedClicked: completeTodo(incidencePtr)
                                                onAddSubTodoClicked: root.addSubTodo(parentWrapper)
                                            }
                                        }
                                    }
                                }
                            }

780
781
                            Loader {
                                id: currentTimeMarkerLoader
Claudio Cambra's avatar
Claudio Cambra committed
782

783
784
785
786
787
788
                                active: root.currentDate >= viewLoader.startDate && viewLoader.daysFromWeekStart < root.daysToShow
                                sourceComponent: Rectangle {
                                    id: currentTimeMarker

                                    width: root.dayWidth
                                    height: root.gridLineWidth * 2
Claudio Cambra's avatar
Claudio Cambra committed
789
                                    color: Kirigami.Theme.highlightColor
790
                                    x: (viewLoader.daysFromWeekStart * root.dayWidth) + (viewLoader.daysFromWeekStart * root.gridLineWidth)
791
792
                                    y: (root.currentDate.getHours() * root.gridLineWidth) + (hourlyView.minuteHeight * root.minutesFromStartOfDay) -
                                        (height / 2) - (root.gridLineWidth / 2)
793
794
795
796
797
798
799
800
801
802
803
                                    z: 100

                                    Rectangle {
                                        anchors.left: parent.left
                                        anchors.top: parent.top
                                        anchors.topMargin: -(height / 2) + (parent.height / 2)
                                        width: height
                                        height: parent.height * 5
                                        radius: 100
                                        color: Kirigami.Theme.highlightColor
                                    }
Claudio Cambra's avatar
Claudio Cambra committed
804
805
806
807
808
809
810
811
812
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}