Route the interactive Panama date menu
This commit is contained in:
@@ -24,7 +24,7 @@ Pill {
|
||||
return date + time;
|
||||
}
|
||||
|
||||
onActivated: ShellState.toggle("notifications")
|
||||
onActivated: ShellState.toggleDateMenu("agenda")
|
||||
|
||||
Text {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
@@ -4,17 +4,20 @@
|
||||
// months and the panel below it never jumps. Days belonging to the neighbouring
|
||||
// months fill the edges, dimmed. Today wears the accent.
|
||||
//
|
||||
// Deliberately non-interactive apart from the header: there is no calendar
|
||||
// backend behind this, so a day cell that highlighted on hover would be
|
||||
// promising a click that does nothing.
|
||||
// Days become real navigation targets now that Evolution Data Server backs the
|
||||
// panel. Up to three source-coloured markers show whether a date has events.
|
||||
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import qs.config
|
||||
import qs.services
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
signal dateActivated(date value)
|
||||
signal visibleMonthChanged(int year, int month)
|
||||
|
||||
implicitHeight: body.implicitHeight
|
||||
|
||||
// Cells divide the available width evenly; the height is fixed so the grid
|
||||
@@ -37,6 +40,7 @@ Item {
|
||||
// panel opens, so it never comes back showing wherever you paged off to.
|
||||
property int viewYear: root.todayYear
|
||||
property int viewMonth: root.todayMonth
|
||||
property date selectedDate: CalendarAgenda.selectedDate
|
||||
|
||||
readonly property bool onCurrentMonth: root.viewYear === root.todayYear && root.viewMonth === root.todayMonth
|
||||
|
||||
@@ -53,30 +57,29 @@ Item {
|
||||
root.viewMonth = d.getMonth();
|
||||
}
|
||||
|
||||
function activateCell(model: var): void {
|
||||
if (!model.current) {
|
||||
root.viewYear = model.date.getFullYear();
|
||||
root.viewMonth = model.date.getMonth();
|
||||
}
|
||||
root.dateActivated(model.date);
|
||||
}
|
||||
|
||||
onViewYearChanged: root.visibleMonthChanged(root.viewYear, root.viewMonth)
|
||||
onViewMonthChanged: root.visibleMonthChanged(root.viewYear, root.viewMonth)
|
||||
|
||||
readonly property var cells: {
|
||||
const first = new Date(root.viewYear, root.viewMonth, 1);
|
||||
const offset = first.getDay(); // 0 = Sunday, matching the header row
|
||||
const inThisMonth = new Date(root.viewYear, root.viewMonth + 1, 0).getDate();
|
||||
const inPrevMonth = new Date(root.viewYear, root.viewMonth, 0).getDate();
|
||||
|
||||
const out = [];
|
||||
for (let i = 0; i < 42; i++) {
|
||||
const n = i - offset + 1;
|
||||
if (n < 1)
|
||||
out.push({
|
||||
day: inPrevMonth + n,
|
||||
current: false
|
||||
});
|
||||
else if (n > inThisMonth)
|
||||
out.push({
|
||||
day: n - inThisMonth,
|
||||
current: false
|
||||
});
|
||||
else
|
||||
out.push({
|
||||
day: n,
|
||||
current: true
|
||||
});
|
||||
const date = new Date(root.viewYear, root.viewMonth, i - offset + 1);
|
||||
out.push({
|
||||
date: date,
|
||||
day: date.getDate(),
|
||||
current: date.getMonth() === root.viewMonth && date.getFullYear() === root.viewYear
|
||||
});
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@@ -198,6 +201,8 @@ Item {
|
||||
required property var modelData
|
||||
|
||||
readonly property bool isToday: cell.modelData.current && cell.modelData.day === root.todayDay && root.onCurrentMonth
|
||||
readonly property bool isSelected: CalendarAgenda.dateKey(cell.modelData.date) === CalendarAgenda.dateKey(root.selectedDate)
|
||||
readonly property var markers: CalendarAgenda.markersForDate(cell.modelData.date).slice(0, 3)
|
||||
|
||||
width: root.cellWidth
|
||||
height: root.cellHeight
|
||||
@@ -208,8 +213,18 @@ Item {
|
||||
height: root.cellHeight - 4
|
||||
radius: width / 2
|
||||
border.width: 0
|
||||
visible: cell.isToday
|
||||
color: Theme.accent
|
||||
visible: cell.isToday || cell.isSelected || cellMouse.containsMouse
|
||||
color: {
|
||||
if (cell.isToday)
|
||||
return Theme.accent;
|
||||
if (cell.isSelected)
|
||||
return Theme.alpha(Theme.accent, 0.20);
|
||||
return Theme.alpha(Theme.fg, 0.08);
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.durFast }
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
@@ -223,11 +238,44 @@ Item {
|
||||
color: {
|
||||
if (cell.isToday)
|
||||
return Theme.bgDark;
|
||||
if (cell.isSelected)
|
||||
return Theme.accent;
|
||||
return cell.modelData.current ? Theme.fg : Theme.fgMuted;
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 1
|
||||
spacing: 2
|
||||
|
||||
Repeater {
|
||||
model: cell.markers
|
||||
|
||||
Rectangle {
|
||||
required property var modelData
|
||||
|
||||
width: 3
|
||||
height: 3
|
||||
radius: 2
|
||||
border.width: 0
|
||||
color: cell.isToday ? Theme.bgDark : modelData.color
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: cellMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: root.activateCell(cell.modelData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: root.visibleMonthChanged(root.viewYear, root.viewMonth)
|
||||
}
|
||||
|
||||
@@ -35,6 +35,10 @@ Singleton {
|
||||
|
||||
readonly property bool anyOverlayOpen: activeOverlay !== ""
|
||||
|
||||
// The date menu is one surface with two deliberate entry points. The clock
|
||||
// opens the Daybook; Super+B and notification actions open message history.
|
||||
property string dateMenuPage: "agenda"
|
||||
|
||||
// 0 means "use the currently focused workspace". A positive value lets a
|
||||
// contextual surface, such as Focus, open Mission Control at its target.
|
||||
property int overviewWorkspaceId: 0
|
||||
@@ -48,6 +52,21 @@ Singleton {
|
||||
root.activeOverlay = name;
|
||||
}
|
||||
|
||||
function openDateMenu(page: string): void {
|
||||
root.dateMenuPage = page === "notifications" ? "notifications" : "agenda";
|
||||
root.activeOverlay = "notifications";
|
||||
}
|
||||
|
||||
function toggleDateMenu(page: string): void {
|
||||
const target = page === "notifications" ? "notifications" : "agenda";
|
||||
if (root.activeOverlay === "notifications" && root.dateMenuPage === target) {
|
||||
root.activeOverlay = "";
|
||||
return;
|
||||
}
|
||||
root.dateMenuPage = target;
|
||||
root.activeOverlay = "notifications";
|
||||
}
|
||||
|
||||
function openOverview(workspaceId: int): void {
|
||||
root.overviewWorkspaceId = Math.max(0, workspaceId);
|
||||
root.overviewQuery = "";
|
||||
|
||||
@@ -253,7 +253,8 @@ ShellRoot {
|
||||
|
||||
IpcHandler {
|
||||
target: "notifications"
|
||||
function toggle(): void { ShellState.toggle("notifications"); }
|
||||
function toggle(): void { ShellState.toggleDateMenu("notifications"); }
|
||||
function open(): void { ShellState.openDateMenu("notifications"); }
|
||||
function clear(): void { Notifs.dismissAll(); }
|
||||
function dnd(): bool {
|
||||
Notifs.doNotDisturb = !Notifs.doNotDisturb;
|
||||
@@ -266,13 +267,15 @@ ShellRoot {
|
||||
function fixture(name: string): void { CalendarAgenda.applyFixture(name); }
|
||||
function reset(): void { CalendarAgenda.clearFixture(); }
|
||||
function refresh(): void { CalendarAgenda.refresh(); }
|
||||
function open(): void { ShellState.open("notifications"); }
|
||||
function open(): void { ShellState.openDateMenu("agenda"); }
|
||||
function close(): void { ShellState.close(); }
|
||||
function select(date: string): void { CalendarAgenda.selectIsoDate(date); }
|
||||
function status(): string {
|
||||
return JSON.stringify({
|
||||
phase: CalendarAgenda.phase,
|
||||
fixture: CalendarAgenda.fixtureMode,
|
||||
open: ShellState.notificationsOpen,
|
||||
page: ShellState.dateMenuPage,
|
||||
sourceCount: CalendarAgenda.sources.length,
|
||||
eventCount: CalendarAgenda.events.length,
|
||||
selectedDate: CalendarAgenda.selectedDateKey,
|
||||
|
||||
Reference in New Issue
Block a user