181 lines
7.2 KiB
QML
181 lines
7.2 KiB
QML
// Everything you owe, from every source, grouped by deadline.
|
||
import QtQuick
|
||
import QtQuick.Controls.Material
|
||
import QtQuick.Layouts
|
||
|
||
import "components"
|
||
|
||
Item {
|
||
id: page
|
||
|
||
function bucketTasks(bucket) {
|
||
var out = []
|
||
for (var i = 0; i < controller.tasks.length; i++) {
|
||
var task = controller.tasks[i]
|
||
if (!task.is_done && task.bucket === bucket) out.push(task)
|
||
}
|
||
return out
|
||
}
|
||
|
||
ColumnLayout {
|
||
anchors.fill: parent
|
||
anchors.margins: 20
|
||
spacing: 12
|
||
|
||
RowLayout {
|
||
Layout.fillWidth: true
|
||
spacing: 8
|
||
Label {
|
||
text: controller.tasks.length + " open"
|
||
font.pixelSize: 13
|
||
opacity: 0.7
|
||
}
|
||
Item { Layout.fillWidth: true }
|
||
Button { text: "+ Add"; onClicked: addDialog.open() }
|
||
PrimaryButton { text: "⟳ Refresh sources"; onClicked: controller.refreshSources() }
|
||
}
|
||
|
||
ScrollView {
|
||
Layout.fillWidth: true
|
||
Layout.fillHeight: true
|
||
contentWidth: availableWidth
|
||
clip: true
|
||
|
||
ColumnLayout {
|
||
width: parent.parent.availableWidth
|
||
spacing: 12
|
||
|
||
Repeater {
|
||
model: [
|
||
{ key: "overdue", label: "Overdue", mark: "🔴" },
|
||
{ key: "today", label: "Due today", mark: "🟡" },
|
||
{ key: "upcoming", label: "Coming up", mark: "🔵" },
|
||
{ key: "someday", label: "No deadline", mark: "⚪" }
|
||
]
|
||
delegate: Card {
|
||
required property var modelData
|
||
property var items: page.bucketTasks(modelData.key)
|
||
visible: items.length > 0
|
||
title: modelData.mark + " " + modelData.label + " (" + items.length + ")"
|
||
|
||
Repeater {
|
||
model: parent.parent.items
|
||
delegate: RowLayout {
|
||
required property var modelData
|
||
Layout.fillWidth: true
|
||
spacing: 10
|
||
|
||
CheckBox {
|
||
checked: modelData.is_done
|
||
onToggled: controller.setTaskDone(modelData.id, checked)
|
||
}
|
||
ColumnLayout {
|
||
Layout.fillWidth: true
|
||
spacing: 2
|
||
Label {
|
||
text: modelData.title
|
||
font.pixelSize: 14
|
||
elide: Text.ElideRight
|
||
Layout.fillWidth: true
|
||
}
|
||
RowLayout {
|
||
spacing: 6
|
||
Label {
|
||
text: modelData.source_label
|
||
font.pixelSize: 10
|
||
opacity: 0.65
|
||
}
|
||
Label {
|
||
visible: !!modelData.project
|
||
text: "· " + modelData.project
|
||
font.pixelSize: 10
|
||
opacity: 0.65
|
||
}
|
||
Label {
|
||
visible: modelData.days_overdue > 0
|
||
text: "· " + modelData.days_overdue + "d overdue"
|
||
font.pixelSize: 10
|
||
color: "#e34948"
|
||
}
|
||
Label {
|
||
visible: !!modelData.due_date && modelData.days_overdue === 0
|
||
text: "· " + modelData.due_date
|
||
font.pixelSize: 10
|
||
opacity: 0.65
|
||
}
|
||
Label {
|
||
visible: !!modelData.priority
|
||
text: "· " + modelData.priority
|
||
font.pixelSize: 10
|
||
opacity: 0.65
|
||
}
|
||
}
|
||
}
|
||
ToolButton {
|
||
text: "↗"
|
||
visible: !!modelData.url
|
||
onClicked: controller.openUrl(modelData.url)
|
||
ToolTip.visible: hovered
|
||
ToolTip.text: "Open in " + modelData.source_label
|
||
}
|
||
ToolButton {
|
||
text: "▶"
|
||
onClicked: { controller.attachTask(modelData.id); controller.startWork(); window.page = 0 }
|
||
ToolTip.visible: hovered
|
||
ToolTip.text: "Start a pomodoro on this"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
Card {
|
||
visible: controller.tasks.length === 0
|
||
title: "Nothing on the list"
|
||
subtitle: "Connect Jira, Todoist or Google Tasks in Settings → Sources, "
|
||
+ "or add something here yourself."
|
||
Button {
|
||
text: "Open settings"
|
||
onClicked: window.page = 4
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
Dialog {
|
||
id: addDialog
|
||
anchors.centerIn: Overlay.overlay
|
||
width: 380
|
||
modal: true
|
||
title: "New task"
|
||
standardButtons: Dialog.Cancel
|
||
|
||
ColumnLayout {
|
||
anchors.fill: parent
|
||
spacing: 10
|
||
TextField {
|
||
id: titleField
|
||
Layout.fillWidth: true
|
||
placeholderText: "What needs doing?"
|
||
}
|
||
TextField {
|
||
id: dueField
|
||
Layout.fillWidth: true
|
||
placeholderText: "Due date (YYYY-MM-DD, optional)"
|
||
inputMask: ""
|
||
}
|
||
PrimaryButton {
|
||
text: "Add"
|
||
enabled: titleField.text.trim() !== ""
|
||
Layout.alignment: Qt.AlignRight
|
||
onClicked: {
|
||
controller.createTask(titleField.text.trim(), dueField.text.trim())
|
||
titleField.text = ""; dueField.text = ""
|
||
addDialog.close()
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|