Warning, /utilities/francis/src/ui/main.qml is written in an unsupported language. File is not indexed.

0001 // SPDX-FileCopyrightText: 2022 Felipe Kinoshita <kinofhek@gmail.com>
0002 // SPDX-License-Identifier: GPL-3.0-or-later
0003 
0004 import QtQuick 2.15
0005 import QtQuick.Controls 2.15 as QQC2
0006 import QtQuick.Layouts 1.15
0007 import QtQuick.Shapes 1.14
0008 import QtQml 2.14
0009 
0010 import org.kde.kirigami 2.19 as Kirigami
0011 import org.kde.notification 1.0
0012 
0013 import org.kde.francis 1.0
0014 
0015 Kirigami.ApplicationWindow {
0016     id: root
0017 
0018     title: i18n("Francis")
0019 
0020     width: Kirigami.Units.gridUnit * 25
0021     height: Kirigami.Units.gridUnit * 25
0022     minimumWidth: Kirigami.Units.gridUnit * 20
0023     minimumHeight: Kirigami.Units.gridUnit * 20
0024 
0025     Timer {
0026         id: saveWindowGeometryTimer
0027         interval: 1000
0028         onTriggered: App.saveWindowGeometry(root)
0029     }
0030 
0031     Connections {
0032         id: saveWindowGeometryConnections
0033         enabled: root.visible
0034         target: root
0035 
0036         function onClosing() { App.saveWindowGeometry(root); }
0037         function onWidthChanged() { saveWindowGeometryTimer.restart(); }
0038         function onHeightChanged() { saveWindowGeometryTimer.restart(); }
0039         function onXChanged() { saveWindowGeometryTimer.restart(); }
0040         function onYChanged() { saveWindowGeometryTimer.restart(); }
0041     }
0042 
0043     Connections {
0044         target: Controller
0045 
0046         function onBreakChanged() {
0047             if (Controller.onBreak) {
0048                 intervalEndedNotification.sendEvent()
0049             } else {
0050                 breakEndedNotification.sendEvent()
0051             }
0052         }
0053     }
0054 
0055     Loader {
0056         active: !Kirigami.Settings.isMobile
0057         sourceComponent: GlobalMenu {}
0058     }
0059 
0060     Notification {
0061         id: intervalEndedNotification
0062         componentName: "plasma_workspace"
0063         eventId: "notification"
0064         urgency: Notification.LowUrgency
0065         title: i18n("Interval Ended")
0066         text: i18n("Enjoy your break, drink some water.")
0067         iconName: "appointment-reminder"
0068     }
0069 
0070     Notification {
0071         id: breakEndedNotification
0072         componentName: "plasma_workspace"
0073         eventId: "notification"
0074         urgency: Notification.LowUrgency
0075         title: i18n("Break Ended")
0076         text: i18n("Get back to work.")
0077         iconName: "appointment-reminder"
0078     }
0079 
0080     pageStack.initialPage: Kirigami.Page {
0081         id: page
0082 
0083         padding: 0
0084         titleDelegate: PageHeader {}
0085 
0086         TapHandler {
0087             onTapped: Controller.hasStarted ? Controller.toggle() : Controller.start()
0088         }
0089 
0090         ColumnLayout {
0091             anchors.centerIn: parent
0092 
0093             Item {
0094                 implicitWidth: circleArc.radiusX * 2 + 10
0095                 implicitHeight: implicitWidth
0096 
0097                 Shape {
0098                     id: circle
0099 
0100                     layer {
0101                         enabled: true
0102                         samples: 8
0103                     }
0104                     anchors.fill: parent
0105                     anchors.horizontalCenter: parent.horizontalCenter
0106                     Kirigami.Theme.colorSet: Kirigami.Theme.Button
0107 
0108                     // base circle
0109                     ShapePath {
0110                         strokeColor: Kirigami.ColorUtils.linearInterpolation(Kirigami.Theme.disabledTextColor, "transparent", 0.6);
0111                         fillColor: "transparent"
0112                         strokeWidth: 3
0113                         capStyle: ShapePath.FlatCap
0114                         PathAngleArc {
0115                             id: circleArc
0116                             centerX: circle.width / 2; centerY: circle.height / 2;
0117                             radiusX: Math.min(root.width * (Kirigami.Settings.isMobile ? 0.3 : 0.25), root.height * (Kirigami.Settings.isMobile ? 0.3 : 0.25)); radiusY: radiusX
0118                             startAngle: -180
0119                             sweepAngle: 360
0120                         }
0121                     }
0122 
0123                     // progress circle
0124                     ShapePath {
0125                         strokeColor: Controller.onBreak ? Kirigami.Theme.textColor : Kirigami.Theme.linkColor
0126                         fillColor: "transparent"
0127                         strokeWidth: 7
0128                         capStyle: ShapePath.RoundCap
0129                         PathAngleArc {
0130                             id: arc
0131                             centerX: circleArc.centerX; centerY: circleArc.centerY
0132                             radiusX: circleArc.radiusX; radiusY: circleArc.radiusY
0133                             startAngle: -90 + 360 * Controller.percentage / 100
0134                             sweepAngle: 360 * (1 - Controller.percentage/100)
0135                             Behavior on sweepAngle {
0136                                 NumberAnimation{
0137                                     duration: 1000
0138                                 }
0139                             }
0140                         }
0141                     }
0142                     ShapePath {
0143                         strokeColor: Kirigami.ColorUtils.linearInterpolation(Kirigami.Theme.backgroundColor, "transparent", 0.4);
0144                         fillColor: "transparent"
0145                         strokeWidth: 5
0146                         capStyle: ShapePath.RoundCap
0147                         PathAngleArc {
0148                             centerX: circleArc.centerX; centerY: circleArc.centerY
0149                             radiusX: circleArc.radiusX; radiusY: circleArc.radiusY
0150                             startAngle: -90 + 360 * Controller.percentage / 100
0151                             sweepAngle: 360 * (1 - Controller.percentage/100)
0152 
0153                             Behavior on sweepAngle {
0154                                 NumberAnimation{
0155 
0156                                     duration: 1000
0157                                 }
0158                             }
0159                         }
0160                     }
0161                 }
0162 
0163                 ColumnLayout {
0164                     anchors.fill: parent
0165 
0166                     Item {
0167                         Layout.fillHeight: true
0168                     }
0169 
0170                     QQC2.Label {
0171                         Layout.alignment: Qt.AlignCenter
0172 
0173                         text: {
0174                             switch (Controller.pomodoros) {
0175                                 case 1:
0176                                     return i18n("Lap 2")
0177                                 case 2:
0178                                     return i18n("Lap 3")
0179                                 case 3:
0180                                     return i18n("Lap 4")
0181                                 default:
0182                                     return i18n("Lap 1")
0183                             }
0184                         }
0185                         font.pointSize: Math.floor(Kirigami.Theme.defaultFont.pointSize * 1.5)
0186                         color: Kirigami.Theme.disabledTextColor
0187                     }
0188 
0189                     QQC2.Label {
0190                         id: timeText
0191 
0192                         Layout.alignment: Qt.AlignCenter
0193 
0194                         text: Controller.text
0195                         color: Controller.onBreak ? Kirigami.Theme.textColor : Kirigami.Theme.linkColor
0196                         font.pointSize: Kirigami.Theme.defaultFont.pointSize * 4
0197                         font.bold: true
0198                         font.family: "monospace"
0199                     }
0200 
0201                     Item {
0202                         Layout.fillHeight: true
0203                     }
0204                 }
0205             }
0206 
0207             QQC2.Label {
0208                 visible: Controller.onBreak
0209 
0210                 Layout.fillWidth: true
0211                 Layout.maximumWidth: root.width - (Kirigami.Units.gridUnit * 4)
0212                 Layout.preferredHeight: goalText.implicitHeight
0213                 Layout.alignment: Qt.AlignCenter
0214 
0215                 text: i18n("Taking a Break")
0216                 wrapMode: Text.Wrap
0217                 horizontalAlignment: Qt.AlignHCenter
0218                 font.pointSize: Math.round(Kirigami.Theme.defaultFont.pointSize * 1.5)
0219             }
0220 
0221             QQC2.TextField {
0222                 id: goalText
0223 
0224                 visible: !Controller.onBreak
0225 
0226                 Layout.fillWidth: true
0227                 Layout.maximumWidth: root.width - (Kirigami.Units.gridUnit * 4)
0228                 Layout.alignment: Qt.AlignCenter
0229 
0230                 wrapMode: Text.Wrap
0231                 horizontalAlignment: Qt.AlignHCenter
0232                 maximumLength: 78
0233                 font.pointSize: Math.round(Kirigami.Theme.defaultFont.pointSize * 1.5)
0234 
0235                 onEditingFinished: {
0236                     text = text.trim()
0237                     goalText.focus = false
0238                 }
0239 
0240                 background: Item {
0241                     QQC2.Label {
0242                         enabled: false
0243                         visible: !goalText.text && !goalText.activeFocus
0244 
0245                         anchors.centerIn: parent
0246 
0247                         Layout.alignment: Qt.AlignCenter
0248 
0249                         text: i18n("I need to focus on…")
0250                         horizontalAlignment: Qt.AlignHCenter
0251 
0252                         color: Kirigami.Theme.disabledTextColor
0253                     }
0254                 }
0255             }
0256 
0257             Item {
0258                 Layout.fillHeight: true
0259             }
0260         }
0261     }
0262 }