mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-16 00:04:01 -04:00
219 lines
7.0 KiB
QML
219 lines
7.0 KiB
QML
import QtQuick
|
|
import qs.Common
|
|
import qs.Modules.ControlCenter
|
|
import qs.DCommon.Widgets
|
|
import qs.Widgets
|
|
import "../../../DCommon/Common/FocusNavigation.js" as FocusNavigation
|
|
|
|
Item {
|
|
id: root
|
|
|
|
property string iconName: ""
|
|
property string title: ""
|
|
property string subtitle: ""
|
|
property string statusText: ""
|
|
property color statusColor: Theme.surfaceVariantText
|
|
property bool shown: false
|
|
property real panelWidth: CcMetrics.dialogWidth
|
|
property vector4d cornerRadii: Qt.vector4d(Theme.windowRadius, Theme.windowRadius, Theme.windowRadius, Theme.windowRadius)
|
|
property Item backdrop: null
|
|
readonly property real presence: panel.opacity
|
|
default property alias content: contentSlot.data
|
|
property alias showScrollBar: contentFlickable.showScrollBar
|
|
|
|
signal dismissed
|
|
|
|
anchors.fill: parent
|
|
visible: shown || panel.opacity > 0
|
|
z: CcMetrics.overlayZ
|
|
|
|
function present() {
|
|
contentFlickable.contentY = 0;
|
|
shown = true;
|
|
focusScope.forceActiveFocus();
|
|
}
|
|
|
|
function dismiss() {
|
|
shown = false;
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
enabled: root.shown
|
|
hoverEnabled: true
|
|
preventStealing: true
|
|
acceptedButtons: Qt.AllButtons
|
|
onClicked: root.dismiss()
|
|
onWheel: wheel => wheel.accepted = true
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
topLeftRadius: root.cornerRadii.x
|
|
topRightRadius: root.cornerRadii.y
|
|
bottomRightRadius: root.cornerRadii.z
|
|
bottomLeftRadius: root.cornerRadii.w
|
|
color: Theme.withAlpha(Theme.scrimColor, Theme.scrimAlpha)
|
|
opacity: root.shown ? 1 : 0
|
|
|
|
Behavior on opacity {
|
|
enabled: CcMetrics.animationsEnabled
|
|
NumberAnimation {
|
|
duration: Theme.expressiveDurations.expressiveEffects
|
|
easing.type: Easing.BezierSpline
|
|
easing.bezierCurve: Theme.expressiveCurves.expressiveEffects
|
|
}
|
|
}
|
|
}
|
|
|
|
FocusScope {
|
|
id: focusScope
|
|
anchors.fill: parent
|
|
focus: root.shown
|
|
enabled: root.shown
|
|
|
|
Keys.onEscapePressed: event => {
|
|
root.dismiss();
|
|
event.accepted = true;
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: panel
|
|
parent: focusScope
|
|
anchors.centerIn: parent
|
|
width: Math.min(root.panelWidth, root.width - Theme.spacingL * 2)
|
|
height: column.implicitHeight + Theme.spacingL * 2
|
|
radius: Theme.windowRadius
|
|
color: CcMetrics.dialogColor
|
|
border.width: Theme.layerOutlineWidth
|
|
border.color: Theme.outlineMedium
|
|
opacity: root.shown ? 1 : 0
|
|
scale: root.shown ? 1 : CcMetrics.popupEnterScale
|
|
|
|
onOpacityChanged: {
|
|
if (opacity > 0 || root.shown)
|
|
return;
|
|
root.dismissed();
|
|
}
|
|
|
|
Behavior on opacity {
|
|
enabled: CcMetrics.animationsEnabled
|
|
NumberAnimation {
|
|
duration: Theme.expressiveDurations.expressiveEffects
|
|
easing.type: Easing.BezierSpline
|
|
easing.bezierCurve: Theme.expressiveCurves.expressiveEffects
|
|
}
|
|
}
|
|
|
|
Behavior on scale {
|
|
enabled: CcMetrics.animationsEnabled
|
|
NumberAnimation {
|
|
duration: Theme.expressiveDurations.expressiveEffects
|
|
easing.type: Easing.BezierSpline
|
|
easing.bezierCurve: Theme.expressiveCurves.expressiveEffects
|
|
}
|
|
}
|
|
|
|
// In-window sheets get no compositor blur, so blur the covered content behind the panel only.
|
|
Loader {
|
|
anchors.fill: parent
|
|
z: -1
|
|
active: root.backdrop !== null && root.visible && CcMetrics.hideCoveredContent
|
|
sourceComponent: BackdropBlur {
|
|
radius: panel.radius
|
|
sourceItem: root.backdrop
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
preventStealing: true
|
|
acceptedButtons: Qt.AllButtons
|
|
onClicked: mouse => mouse.accepted = true
|
|
onWheel: wheel => wheel.accepted = true
|
|
}
|
|
|
|
Column {
|
|
id: column
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.top: parent.top
|
|
anchors.margins: Theme.spacingL
|
|
spacing: Theme.spacingM
|
|
|
|
Row {
|
|
id: header
|
|
width: parent.width
|
|
spacing: Theme.spacingM
|
|
|
|
DIcon {
|
|
name: root.iconName
|
|
size: Theme.iconSizeLarge
|
|
color: Theme.primary
|
|
visible: name !== ""
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
}
|
|
|
|
Column {
|
|
width: parent.width - (root.iconName !== "" ? Theme.iconSizeLarge + parent.spacing : 0)
|
|
spacing: Theme.spacingXXS
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
StyledText {
|
|
width: parent.width
|
|
text: root.title
|
|
font.pixelSize: Theme.fontSizeLarge
|
|
font.weight: Theme.fontWeightMedium
|
|
color: Theme.surfaceText
|
|
elide: Text.ElideRight
|
|
}
|
|
|
|
StyledText {
|
|
width: parent.width
|
|
text: root.subtitle
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
color: Theme.surfaceVariantText
|
|
elide: Text.ElideRight
|
|
visible: text !== ""
|
|
}
|
|
}
|
|
}
|
|
|
|
StyledText {
|
|
id: status
|
|
width: parent.width
|
|
text: root.statusText
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
color: root.statusColor
|
|
wrapMode: Text.WordWrap
|
|
visible: text !== ""
|
|
}
|
|
|
|
DFlickable {
|
|
id: contentFlickable
|
|
width: parent.width
|
|
height: Math.min(contentHeight, Math.max(0, root.height - Theme.spacingL * 4 - header.height - column.spacing - (status.visible ? status.height + column.spacing : 0)))
|
|
contentHeight: contentSlot.implicitHeight
|
|
clip: true
|
|
|
|
readonly property Item windowFocusItem: Window.activeFocusItem
|
|
onWindowFocusItemChanged: {
|
|
const item = windowFocusItem;
|
|
if (!root.shown || !item || !FocusNavigation.containsFocus(contentSlot))
|
|
return;
|
|
const top = item.mapToItem(contentSlot, 0, 0).y;
|
|
contentFlickable.revealRange(top, top + item.height);
|
|
}
|
|
|
|
Column {
|
|
id: contentSlot
|
|
width: parent.width
|
|
spacing: CcMetrics.detailContentGap
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|