Build the Prism calendar Daybook
This commit is contained in:
@@ -0,0 +1,298 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.config
|
||||
import qs.services
|
||||
import qs.modules.quicksettings
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
signal requestNotifications
|
||||
|
||||
readonly property bool isToday: CalendarAgenda.selectedDateKey === CalendarAgenda.dateKey(clock.date)
|
||||
readonly property var upNext: CalendarAgenda.nextEventForSelectedDate
|
||||
readonly property var listedEvents: CalendarAgenda.selectedEvents.filter(event => !root.upNext || event.id !== root.upNext.id)
|
||||
readonly property string selectedLabel: root.isToday
|
||||
? "Today"
|
||||
: Qt.formatDate(CalendarAgenda.selectedDate, "dddd, MMMM d")
|
||||
|
||||
implicitHeight: content.implicitHeight
|
||||
|
||||
SystemClock {
|
||||
id: clock
|
||||
precision: SystemClock.Minutes
|
||||
}
|
||||
|
||||
Column {
|
||||
id: content
|
||||
width: parent.width
|
||||
spacing: 12
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: 3
|
||||
visible: CalendarAgenda.phase === "loading"
|
||||
|
||||
Text {
|
||||
text: "CALENDAR"
|
||||
color: Theme.fgMuted
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.DemiBold
|
||||
font.letterSpacing: 1.1
|
||||
}
|
||||
Text {
|
||||
text: "Loading calendars…"
|
||||
color: Theme.fgDim
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.DemiBold
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: 10
|
||||
visible: CalendarAgenda.phase === "unavailable"
|
||||
|
||||
Text {
|
||||
text: "Calendar data is unavailable"
|
||||
color: Theme.fg
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.DemiBold
|
||||
}
|
||||
Text {
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
text: "Notifications, weather, and the month grid are still available. GNOME Calendar may have more detail."
|
||||
color: Theme.fgDim
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSize
|
||||
}
|
||||
ActionPill {
|
||||
text: "Open Calendar"
|
||||
onClicked: CalendarAgenda.openCalendar(CalendarAgenda.selectedDate)
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: nextCard
|
||||
width: parent.width
|
||||
height: visible ? 88 : 0
|
||||
visible: CalendarAgenda.available && root.isToday && root.upNext !== null
|
||||
radius: Theme.cardRadius
|
||||
border.width: 1
|
||||
border.color: Theme.alpha(Theme.accent, 0.18)
|
||||
color: Theme.alpha(Theme.accent, 0.105)
|
||||
clip: true
|
||||
|
||||
Rectangle {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: -24
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: -34
|
||||
width: 110
|
||||
height: 110
|
||||
radius: 55
|
||||
border.width: 0
|
||||
color: Theme.alpha(Theme.accentSecondary, 0.08)
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 14
|
||||
anchors.right: nextJoin.visible ? nextJoin.left : parent.right
|
||||
anchors.rightMargin: nextJoin.visible ? 10 : 14
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 5
|
||||
|
||||
Text {
|
||||
text: "UP NEXT · " + root.relativeStart(root.upNext)
|
||||
color: Theme.accent
|
||||
font.family: Theme.fontFamily
|
||||
font.features: Theme.tabularFigures
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Bold
|
||||
font.letterSpacing: 0.8
|
||||
}
|
||||
Text {
|
||||
width: parent.width
|
||||
text: root.upNext?.summary ?? ""
|
||||
color: Theme.fg
|
||||
elide: Text.ElideRight
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.DemiBold
|
||||
}
|
||||
Text {
|
||||
width: parent.width
|
||||
text: root.eventDetail(root.upNext)
|
||||
color: Theme.fgDim
|
||||
elide: Text.ElideRight
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
}
|
||||
}
|
||||
|
||||
ActionPill {
|
||||
id: nextJoin
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 12
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 12
|
||||
visible: String(root.upNext?.joinUrl ?? "").startsWith("https://")
|
||||
text: "Join"
|
||||
accent: true
|
||||
onClicked: CalendarAgenda.join(root.upNext)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
z: -1
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: CalendarAgenda.openEvent(root.upNext)
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: 34
|
||||
visible: CalendarAgenda.available
|
||||
|
||||
Column {
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 2
|
||||
|
||||
Text {
|
||||
text: root.selectedLabel.toUpperCase()
|
||||
color: Theme.fgMuted
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.DemiBold
|
||||
font.letterSpacing: 0.9
|
||||
}
|
||||
Text {
|
||||
text: "Your schedule"
|
||||
color: Theme.fg
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.DemiBold
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
text: CalendarAgenda.selectedEvents.length + (CalendarAgenda.selectedEvents.length === 1 ? " event" : " events")
|
||||
color: Theme.fgDim
|
||||
font.family: Theme.fontFamily
|
||||
font.features: Theme.tabularFigures
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: visible ? 92 : 0
|
||||
visible: CalendarAgenda.available && CalendarAgenda.selectedEvents.length === 0
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: 8
|
||||
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: "Nothing scheduled"
|
||||
color: Theme.fgDim
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSize
|
||||
}
|
||||
ActionPill {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: "Open Calendar"
|
||||
onClicked: CalendarAgenda.openCalendar(CalendarAgenda.selectedDate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScrollColumn {
|
||||
width: parent.width
|
||||
maxHeight: 286
|
||||
spacing: 0
|
||||
visible: CalendarAgenda.available && root.listedEvents.length > 0
|
||||
|
||||
Repeater {
|
||||
model: root.listedEvents
|
||||
|
||||
AgendaEvent {
|
||||
required property var modelData
|
||||
|
||||
width: parent.width
|
||||
eventData: modelData
|
||||
past: Number(modelData.end) <= CalendarAgenda.nowEpoch
|
||||
onActivated: CalendarAgenda.openEvent(modelData)
|
||||
onJoinRequested: CalendarAgenda.join(modelData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NotificationSummary {
|
||||
width: parent.width
|
||||
onActivated: root.requestNotifications()
|
||||
}
|
||||
}
|
||||
|
||||
function relativeStart(event: var): string {
|
||||
if (!event)
|
||||
return "";
|
||||
const seconds = Number(event.start) - CalendarAgenda.nowEpoch;
|
||||
if (seconds <= 0)
|
||||
return "NOW";
|
||||
if (seconds < 3600)
|
||||
return "IN " + Math.ceil(seconds / 60) + " MINUTES";
|
||||
return Qt.formatTime(new Date(Number(event.start) * 1000), Settings.use24Hour ? "HH:mm" : "h:mm AP");
|
||||
}
|
||||
|
||||
function eventDetail(event: var): string {
|
||||
if (!event)
|
||||
return "";
|
||||
const source = CalendarAgenda.sourceForId(event.sourceId)?.name ?? "Calendar";
|
||||
const location = String(event.location ?? "").trim();
|
||||
return location === "" ? source : source + " · " + location;
|
||||
}
|
||||
|
||||
component ActionPill: Rectangle {
|
||||
id: action
|
||||
|
||||
required property string text
|
||||
property bool accent: false
|
||||
signal clicked
|
||||
|
||||
width: actionLabel.implicitWidth + 20
|
||||
height: 28
|
||||
radius: Theme.pillRadius
|
||||
border.width: 0
|
||||
color: actionMouse.containsMouse
|
||||
? Theme.alpha(action.accent ? Theme.accent : Theme.fg, 0.24)
|
||||
: Theme.alpha(action.accent ? Theme.accent : Theme.fg, action.accent ? 0.14 : 0.07)
|
||||
|
||||
Text {
|
||||
id: actionLabel
|
||||
anchors.centerIn: parent
|
||||
text: action.text
|
||||
color: action.accent ? Theme.accent : Theme.fg
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.DemiBold
|
||||
}
|
||||
MouseArea {
|
||||
id: actionMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: action.clicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user