230 lines
8.9 KiB
QML
230 lines
8.9 KiB
QML
// The day in numbers — the same payload the Telegram message is built from.
|
|
import QtQuick
|
|
import QtQuick.Controls
|
|
import QtQuick.Layouts
|
|
|
|
import "."
|
|
import "components"
|
|
|
|
ScrollView {
|
|
id: page
|
|
contentWidth: availableWidth
|
|
clip: true
|
|
|
|
readonly property var payload: controller.report.report ? controller.report.report : null
|
|
readonly property var metrics: payload ? payload.metrics : null
|
|
|
|
ColumnLayout {
|
|
width: page.availableWidth - 56
|
|
x: 28
|
|
y: 26
|
|
spacing: 22
|
|
|
|
PageHeader {
|
|
eyebrow: controller.report.sent_at ? "sent to Telegram" : "not sent yet"
|
|
title: page.payload ? "Report · " + page.payload.date : "Report"
|
|
caption: page.payload ? page.payload.verdict : ""
|
|
|
|
GhostButton { text: "Reload"; onClicked: controller.loadReport() }
|
|
PrimaryButton { text: "Send to Telegram"; onClicked: controller.sendReport() }
|
|
}
|
|
|
|
Panel {
|
|
padding: 0
|
|
RowLayout {
|
|
Layout.fillWidth: true
|
|
spacing: 0
|
|
Repeater {
|
|
model: [
|
|
{ label: "Pomodoros",
|
|
value: page.metrics ? page.metrics.pomodoros + "/" + page.metrics.goal : "—",
|
|
caption: page.metrics && page.metrics.goal_met ? "goal met" : "goal not met yet",
|
|
accent: true },
|
|
{ label: "Focus",
|
|
value: page.metrics ? Theme.humanMinutes(page.metrics.focus_minutes) : "—",
|
|
caption: page.metrics ? Theme.humanMinutes(page.metrics.break_minutes) + " resting" : "" },
|
|
{ label: "Score",
|
|
value: page.payload ? "" + Math.round(page.payload.score) : "—",
|
|
caption: "out of 100" },
|
|
{ label: "Streak",
|
|
value: page.payload ? page.payload.streak.current + "d" : "—",
|
|
caption: page.payload ? "best " + page.payload.streak.best : "" }
|
|
]
|
|
delegate: RowLayout {
|
|
required property int index
|
|
required property var modelData
|
|
Layout.fillWidth: true
|
|
spacing: 0
|
|
Rectangle {
|
|
visible: index > 0
|
|
width: 1
|
|
Layout.preferredHeight: 84
|
|
color: Theme.rule
|
|
}
|
|
Stat {
|
|
Layout.fillWidth: true
|
|
Layout.margins: 20
|
|
label: modelData.label
|
|
value: modelData.value
|
|
caption: modelData.caption
|
|
size: 38
|
|
accent: modelData.accent ? Theme.work : Theme.ink
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
Layout.fillWidth: true
|
|
spacing: 10
|
|
SectionTitle { text: "Last 30 days"; trailing: "goal line dashed" }
|
|
Panel {
|
|
BarRow {
|
|
Layout.fillWidth: true
|
|
days: controller.stats.range ? controller.stats.range : []
|
|
goal: controller.goal
|
|
}
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
Layout.fillWidth: true
|
|
visible: page.payload && page.payload.achievements.length > 0
|
|
spacing: 10
|
|
SectionTitle { text: "Achievements" }
|
|
Flow {
|
|
Layout.fillWidth: true
|
|
spacing: 8
|
|
Repeater {
|
|
model: page.payload ? page.payload.achievements : []
|
|
delegate: Rectangle {
|
|
required property var modelData
|
|
implicitWidth: badge.implicitWidth + 24
|
|
implicitHeight: badge.implicitHeight + 18
|
|
radius: 10
|
|
color: Qt.alpha(Theme.ember, 0.08)
|
|
border.width: 1
|
|
border.color: Qt.alpha(Theme.ember, 0.22)
|
|
|
|
ColumnLayout {
|
|
id: badge
|
|
anchors.centerIn: parent
|
|
spacing: 1
|
|
Label {
|
|
text: modelData.emoji + " " + modelData.title
|
|
color: Theme.ink
|
|
font.pixelSize: 13
|
|
font.weight: Font.DemiBold
|
|
font.family: Theme.sansFamily
|
|
}
|
|
Label {
|
|
visible: modelData.detail !== ""
|
|
text: modelData.detail
|
|
color: Theme.muted
|
|
font.pixelSize: 11
|
|
font.family: Theme.sansFamily
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
Layout.fillWidth: true
|
|
visible: page.payload && page.payload.fun_facts.length > 0
|
|
spacing: 8
|
|
SectionTitle { text: "The funny part" }
|
|
Repeater {
|
|
model: page.payload ? page.payload.fun_facts : []
|
|
delegate: Label {
|
|
required property var modelData
|
|
text: modelData
|
|
color: Theme.ink
|
|
font.pixelSize: 13
|
|
font.family: Theme.sansFamily
|
|
wrapMode: Text.WordWrap
|
|
Layout.fillWidth: true
|
|
}
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
Layout.fillWidth: true
|
|
visible: page.metrics && page.metrics.tasks_completed.length > 0
|
|
spacing: 6
|
|
SectionTitle { text: "Closed today" }
|
|
Repeater {
|
|
model: page.metrics ? page.metrics.tasks_completed : []
|
|
delegate: RowLayout {
|
|
required property var modelData
|
|
Layout.fillWidth: true
|
|
spacing: 12
|
|
Label {
|
|
text: modelData.title
|
|
color: Theme.ink
|
|
font.pixelSize: 13
|
|
font.family: Theme.sansFamily
|
|
elide: Text.ElideRight
|
|
Layout.fillWidth: true
|
|
}
|
|
Label {
|
|
text: modelData.source
|
|
color: Theme.faint
|
|
font.pixelSize: 11
|
|
font.family: Theme.sansFamily
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
Layout.fillWidth: true
|
|
spacing: 10
|
|
SectionTitle { text: "All time" }
|
|
Panel {
|
|
padding: 0
|
|
RowLayout {
|
|
Layout.fillWidth: true
|
|
spacing: 0
|
|
Repeater {
|
|
model: [
|
|
{ label: "Pomodoros",
|
|
value: controller.stats.lifetime ? "" + controller.stats.lifetime.pomodoros : "—" },
|
|
{ label: "Hours focused",
|
|
value: controller.stats.lifetime ? "" + controller.stats.lifetime.focus_hours : "—" },
|
|
{ label: "Tasks closed",
|
|
value: controller.stats.lifetime ? "" + controller.stats.lifetime.tasks_completed : "—" },
|
|
{ label: "Blocked",
|
|
value: controller.stats.lifetime ? "" + controller.stats.lifetime.blocked_attempts : "—" }
|
|
]
|
|
delegate: RowLayout {
|
|
required property int index
|
|
required property var modelData
|
|
Layout.fillWidth: true
|
|
spacing: 0
|
|
Rectangle {
|
|
visible: index > 0
|
|
width: 1
|
|
Layout.preferredHeight: 64
|
|
color: Theme.rule
|
|
}
|
|
Stat {
|
|
Layout.fillWidth: true
|
|
Layout.margins: 18
|
|
label: modelData.label
|
|
value: modelData.value
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Item { Layout.preferredHeight: 10 }
|
|
}
|
|
|
|
Component.onCompleted: controller.loadReport()
|
|
}
|