1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-07 05:55:37 -05:00
Files
DankMaterialShell/Modules/CentcomCenter/CentcomPopout.qml
2025-07-24 20:32:28 -04:00

268 lines
8.4 KiB
QML

import QtQuick
import QtQuick.Controls
import QtQuick.Effects
import Quickshell
import Quickshell.Services.Mpris
import Quickshell.Wayland
import Quickshell.Widgets
import qs.Common
import qs.Modules.CentcomCenter
import qs.Services
PanelWindow {
id: root
readonly property bool hasActiveMedia: MprisController.activePlayer !== null
property bool calendarVisible: false
property bool internalVisible: false
visible: internalVisible
onCalendarVisibleChanged: {
if (calendarVisible) {
internalVisible = true;
Qt.callLater(() => {
// This ensures opacity changes after window is visible
internalVisible = true;
// Force re-trigger if needed
// Ensure events are loaded for current display month
calendarGrid.loadEventsForMonth();
});
} else {
internalVisible = false;
}
}
onVisibleChanged: {
if (visible && calendarGrid)
calendarGrid.loadEventsForMonth();
}
implicitWidth: 480
implicitHeight: 600
WlrLayershell.layer: WlrLayershell.Overlay
WlrLayershell.exclusiveZone: -1
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
color: "transparent"
anchors {
top: true
left: true
right: true
bottom: true
}
Rectangle {
id: mainContainer
readonly property real targetWidth: Math.min(Screen.width * 0.9, 600)
function calculateWidth() {
let baseWidth = 320;
if (leftWidgets.hasAnyWidgets)
return Math.min(parent.width * 0.9, 600);
return Math.min(parent.width * 0.7, 400);
}
function calculateHeight() {
let contentHeight = Theme.spacingM * 2; // margins
// Main row with widgets and calendar
let widgetHeight = 160;
// Media widget always present
widgetHeight += 140 + Theme.spacingM;
// Weather widget always present
let calendarHeight = 300;
let mainRowHeight = Math.max(widgetHeight, calendarHeight);
contentHeight += mainRowHeight + Theme.spacingM;
// Add events widget height - use calculated height instead of actual
if (CalendarService && CalendarService.khalAvailable) {
let hasEvents = events.selectedDateEvents && events.selectedDateEvents.length > 0;
let eventsHeight = hasEvents ? Math.min(300, 80 + events.selectedDateEvents.length * 60) : 120;
contentHeight += eventsHeight;
} else {
// When no khal, reduce bottom margin to match top
contentHeight -= Theme.spacingM;
}
return Math.min(contentHeight, parent.height * 0.9);
}
width: targetWidth
height: calculateHeight()
color: Theme.surfaceContainer
radius: Theme.cornerRadiusLarge
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 1
layer.enabled: true
opacity: calendarVisible ? 1 : 0
scale: calendarVisible ? 1 : 0.9
x: (Screen.width - targetWidth) / 2
y: Theme.barHeight + 4
// Only resize after animation is complete
onOpacityChanged: {
if (opacity === 1)
// Animation finished, now we can safely resize
Qt.callLater(() => {
height = calculateHeight();
});
}
Connections {
function onEventsByDateChanged() {
if (mainContainer.opacity === 1)
mainContainer.height = mainContainer.calculateHeight();
}
function onKhalAvailableChanged() {
if (mainContainer.opacity === 1)
mainContainer.height = mainContainer.calculateHeight();
}
target: CalendarService
enabled: CalendarService !== null
}
Connections {
function onSelectedDateEventsChanged() {
if (mainContainer.opacity === 1)
mainContainer.height = mainContainer.calculateHeight();
}
target: events
enabled: events !== null
}
Rectangle {
anchors.fill: parent
color: Qt.rgba(Theme.surfaceTint.r, Theme.surfaceTint.g, Theme.surfaceTint.b, 0.04)
radius: parent.radius
SequentialAnimation on opacity {
running: calendarVisible
loops: Animation.Infinite
NumberAnimation {
to: 0.08
duration: Theme.extraLongDuration
easing.type: Theme.standardEasing
}
NumberAnimation {
to: 0.02
duration: Theme.extraLongDuration
easing.type: Theme.standardEasing
}
}
}
Column {
anchors.fill: parent
anchors.margins: Theme.spacingM
spacing: Theme.spacingM
// Main row with widgets and calendar - improved spacing and proportions
Row {
width: parent.width
height: {
let widgetHeight = 160; // Media widget
widgetHeight += 140 + Theme.spacingM; // Weather widget with spacing
let calendarHeight = 300; // Calendar
return Math.max(widgetHeight, calendarHeight);
}
spacing: Theme.spacingM
// Left section for widgets - improved visual hierarchy
Column {
id: leftWidgets
property bool hasAnyWidgets: true
width: hasAnyWidgets ? parent.width * 0.42 : 0 // Slightly narrower for better proportions
height: childrenRect.height
spacing: Theme.spacingM
visible: hasAnyWidgets
anchors.top: parent.top
MediaPlayer {
width: parent.width
height: 160
}
Weather {
width: parent.width
height: 140
}
}
// Right section for calendar - enhanced container
Rectangle {
width: leftWidgets.hasAnyWidgets ? parent.width * 0.55 - Theme.spacingM : parent.width
height: parent.height
radius: Theme.cornerRadiusLarge
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.2)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 1
CalendarGrid {
id: calendarGrid
anchors.fill: parent
anchors.margins: Theme.spacingS
}
}
}
Events {
id: events
width: parent.width
selectedDate: calendarGrid.selectedDate
}
}
Behavior on opacity {
NumberAnimation {
duration: Anims.durMed
easing.type: Easing.BezierSpline
easing.bezierCurve: Anims.emphasized
}
}
Behavior on scale {
NumberAnimation {
duration: Anims.durMed
easing.type: Easing.BezierSpline
easing.bezierCurve: Anims.emphasized
}
}
layer.effect: MultiEffect {
shadowEnabled: true
shadowHorizontalOffset: 0
shadowVerticalOffset: 4
shadowBlur: 0.5
shadowColor: Qt.rgba(0, 0, 0, 0.15)
shadowOpacity: 0.15
}
}
MouseArea {
anchors.fill: parent
z: -1
enabled: calendarVisible
onClicked: function(mouse) {
// Only close if click is outside the main container
var localPos = mapToItem(mainContainer, mouse.x, mouse.y);
if (localPos.x < 0 || localPos.x > mainContainer.width || localPos.y < 0 || localPos.y > mainContainer.height)
calendarVisible = false;
}
}
}