formatter
This commit is contained in:
@@ -4,50 +4,56 @@ import QtQuick
|
||||
import QtQuick.Shapes
|
||||
|
||||
ShapePath {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
required property Wrapper wrapper
|
||||
required property var sidebar
|
||||
readonly property real rounding: 8
|
||||
readonly property bool flatten: wrapper.height < rounding * 2
|
||||
readonly property real roundingY: flatten ? wrapper.height / 2 : rounding
|
||||
readonly property bool flatten: wrapper.height < rounding * 2
|
||||
readonly property real rounding: 8
|
||||
readonly property real roundingY: flatten ? wrapper.height / 2 : rounding
|
||||
required property var sidebar
|
||||
required property Wrapper wrapper
|
||||
|
||||
strokeWidth: -1
|
||||
fillColor: DynamicColors.palette.m3surface
|
||||
fillColor: DynamicColors.palette.m3surface
|
||||
strokeWidth: -1
|
||||
|
||||
PathLine {
|
||||
relativeX: -(root.wrapper.width + root.rounding)
|
||||
relativeY: 0
|
||||
}
|
||||
PathArc {
|
||||
relativeX: root.rounding
|
||||
relativeY: root.roundingY
|
||||
radiusX: root.rounding
|
||||
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||
}
|
||||
PathLine {
|
||||
relativeX: 0
|
||||
relativeY: root.wrapper.height - root.roundingY * 2
|
||||
}
|
||||
PathArc {
|
||||
relativeX: root.sidebar.notifsRoundingX
|
||||
relativeY: root.roundingY
|
||||
radiusX: root.sidebar.notifsRoundingX
|
||||
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||
direction: PathArc.Counterclockwise
|
||||
}
|
||||
PathLine {
|
||||
relativeX: root.wrapper.height > 0 ? root.wrapper.width - root.rounding - root.sidebar.notifsRoundingX : root.wrapper.width
|
||||
relativeY: 0
|
||||
}
|
||||
PathArc {
|
||||
relativeX: root.rounding
|
||||
relativeY: root.rounding
|
||||
radiusX: root.rounding
|
||||
radiusY: root.rounding
|
||||
}
|
||||
Behavior on fillColor {
|
||||
CAnim {
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on fillColor {
|
||||
CAnim {}
|
||||
}
|
||||
PathLine {
|
||||
relativeX: -(root.wrapper.width + root.rounding)
|
||||
relativeY: 0
|
||||
}
|
||||
|
||||
PathArc {
|
||||
radiusX: root.rounding
|
||||
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||
relativeX: root.rounding
|
||||
relativeY: root.roundingY
|
||||
}
|
||||
|
||||
PathLine {
|
||||
relativeX: 0
|
||||
relativeY: root.wrapper.height - root.roundingY * 2
|
||||
}
|
||||
|
||||
PathArc {
|
||||
direction: PathArc.Counterclockwise
|
||||
radiusX: root.sidebar.notifsRoundingX
|
||||
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||
relativeX: root.sidebar.notifsRoundingX
|
||||
relativeY: root.roundingY
|
||||
}
|
||||
|
||||
PathLine {
|
||||
relativeX: root.wrapper.height > 0 ? root.wrapper.width - root.rounding - root.sidebar.notifsRoundingX : root.wrapper.width
|
||||
relativeY: 0
|
||||
}
|
||||
|
||||
PathArc {
|
||||
radiusX: root.rounding
|
||||
radiusY: root.rounding
|
||||
relativeX: root.rounding
|
||||
relativeY: root.rounding
|
||||
}
|
||||
}
|
||||
|
||||
+153
-155
@@ -6,198 +6,196 @@ import Quickshell.Widgets
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
required property PersistentProperties visibilities
|
||||
required property Item panels
|
||||
readonly property int padding: 6
|
||||
readonly property int padding: 6
|
||||
required property Item panels
|
||||
required property PersistentProperties visibilities
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
implicitHeight: {
|
||||
const count = list.count;
|
||||
if (count === 0)
|
||||
return 0;
|
||||
|
||||
implicitWidth: Config.notifs.sizes.width + padding * 2
|
||||
implicitHeight: {
|
||||
const count = list.count;
|
||||
if (count === 0)
|
||||
return 0;
|
||||
let height = (count - 1) * 8;
|
||||
for (let i = 0; i < count; i++)
|
||||
height += list.itemAtIndex(i)?.nonAnimHeight ?? 0;
|
||||
|
||||
let height = (count - 1) * 8;
|
||||
for (let i = 0; i < count; i++)
|
||||
height += list.itemAtIndex(i)?.nonAnimHeight ?? 0;
|
||||
if (visibilities && panels) {
|
||||
if (visibilities.osd) {
|
||||
const h = panels.osd.y - 8 * 2 - padding * 2;
|
||||
if (height > h)
|
||||
height = h;
|
||||
}
|
||||
|
||||
if (visibilities && panels) {
|
||||
if (visibilities.osd) {
|
||||
const h = panels.osd.y - 8 * 2 - padding * 2;
|
||||
if (height > h)
|
||||
height = h;
|
||||
}
|
||||
if (visibilities.session) {
|
||||
const h = panels.session.y - 8 * 2 - padding * 2;
|
||||
if (height > h)
|
||||
height = h;
|
||||
}
|
||||
}
|
||||
|
||||
if (visibilities.session) {
|
||||
const h = panels.session.y - 8 * 2 - padding * 2;
|
||||
if (height > h)
|
||||
height = h;
|
||||
}
|
||||
}
|
||||
return Math.min((QsWindow.window?.screen?.height ?? 0) - 1 * 2, height + padding * 2);
|
||||
}
|
||||
implicitWidth: Config.notifs.sizes.width + padding * 2
|
||||
|
||||
return Math.min((QsWindow.window?.screen?.height ?? 0) - 1 * 2, height + padding * 2);
|
||||
}
|
||||
Behavior on implicitHeight {
|
||||
Anim {
|
||||
}
|
||||
}
|
||||
|
||||
ClippingWrapperRectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: root.padding
|
||||
ClippingWrapperRectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: root.padding
|
||||
color: "transparent"
|
||||
radius: 4
|
||||
|
||||
color: "transparent"
|
||||
radius: 4
|
||||
CustomListView {
|
||||
id: list
|
||||
|
||||
CustomListView {
|
||||
id: list
|
||||
anchors.fill: parent
|
||||
cacheBuffer: QsWindow.window?.screen.height ?? 0
|
||||
orientation: Qt.Vertical
|
||||
spacing: 0
|
||||
|
||||
model: ScriptModel {
|
||||
values: NotifServer.popups.filter(n => !n.closed)
|
||||
}
|
||||
delegate: Item {
|
||||
id: wrapper
|
||||
|
||||
anchors.fill: parent
|
||||
property int idx
|
||||
required property int index
|
||||
required property NotifServer.Notif modelData
|
||||
readonly property alias nonAnimHeight: notif.nonAnimHeight
|
||||
|
||||
orientation: Qt.Vertical
|
||||
spacing: 0
|
||||
cacheBuffer: QsWindow.window?.screen.height ?? 0
|
||||
implicitHeight: notif.implicitHeight + (idx === 0 ? 0 : 8)
|
||||
implicitWidth: notif.implicitWidth
|
||||
|
||||
delegate: Item {
|
||||
id: wrapper
|
||||
ListView.onRemove: removeAnim.start()
|
||||
onIndexChanged: {
|
||||
if (index !== -1)
|
||||
idx = index;
|
||||
}
|
||||
|
||||
required property NotifServer.Notif modelData
|
||||
required property int index
|
||||
readonly property alias nonAnimHeight: notif.nonAnimHeight
|
||||
property int idx
|
||||
SequentialAnimation {
|
||||
id: removeAnim
|
||||
|
||||
onIndexChanged: {
|
||||
if (index !== -1)
|
||||
idx = index;
|
||||
}
|
||||
PropertyAction {
|
||||
property: "ListView.delayRemove"
|
||||
target: wrapper
|
||||
value: true
|
||||
}
|
||||
|
||||
implicitWidth: notif.implicitWidth
|
||||
implicitHeight: notif.implicitHeight + (idx === 0 ? 0 : 8)
|
||||
PropertyAction {
|
||||
property: "enabled"
|
||||
target: wrapper
|
||||
value: false
|
||||
}
|
||||
|
||||
ListView.onRemove: removeAnim.start()
|
||||
PropertyAction {
|
||||
property: "implicitHeight"
|
||||
target: wrapper
|
||||
value: 0
|
||||
}
|
||||
|
||||
SequentialAnimation {
|
||||
id: removeAnim
|
||||
PropertyAction {
|
||||
property: "z"
|
||||
target: wrapper
|
||||
value: 1
|
||||
}
|
||||
|
||||
PropertyAction {
|
||||
target: wrapper
|
||||
property: "ListView.delayRemove"
|
||||
value: true
|
||||
}
|
||||
PropertyAction {
|
||||
target: wrapper
|
||||
property: "enabled"
|
||||
value: false
|
||||
}
|
||||
PropertyAction {
|
||||
target: wrapper
|
||||
property: "implicitHeight"
|
||||
value: 0
|
||||
}
|
||||
PropertyAction {
|
||||
target: wrapper
|
||||
property: "z"
|
||||
value: 1
|
||||
}
|
||||
Anim {
|
||||
target: notif
|
||||
property: "x"
|
||||
to: (notif.x >= 0 ? Config.notifs.sizes.width : -Config.notifs.sizes.width) * 2
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
PropertyAction {
|
||||
target: wrapper
|
||||
property: "ListView.delayRemove"
|
||||
value: false
|
||||
}
|
||||
}
|
||||
property: "x"
|
||||
target: notif
|
||||
to: (notif.x >= 0 ? Config.notifs.sizes.width : -Config.notifs.sizes.width) * 2
|
||||
}
|
||||
|
||||
ClippingRectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: wrapper.idx === 0 ? 0 : 8
|
||||
PropertyAction {
|
||||
property: "ListView.delayRemove"
|
||||
target: wrapper
|
||||
value: false
|
||||
}
|
||||
}
|
||||
|
||||
color: "transparent"
|
||||
radius: 4
|
||||
implicitWidth: notif.implicitWidth
|
||||
implicitHeight: notif.implicitHeight
|
||||
ClippingRectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: wrapper.idx === 0 ? 0 : 8
|
||||
color: "transparent"
|
||||
implicitHeight: notif.implicitHeight
|
||||
implicitWidth: notif.implicitWidth
|
||||
radius: 4
|
||||
|
||||
Notification {
|
||||
id: notif
|
||||
Notification {
|
||||
id: notif
|
||||
|
||||
modelData: wrapper.modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
modelData: wrapper.modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
displaced: Transition {
|
||||
Anim {
|
||||
property: "y"
|
||||
}
|
||||
}
|
||||
model: ScriptModel {
|
||||
values: NotifServer.popups.filter(n => !n.closed)
|
||||
}
|
||||
move: Transition {
|
||||
Anim {
|
||||
property: "y"
|
||||
}
|
||||
}
|
||||
|
||||
move: Transition {
|
||||
Anim {
|
||||
property: "y"
|
||||
}
|
||||
}
|
||||
ExtraIndicator {
|
||||
anchors.top: parent.top
|
||||
extra: {
|
||||
const count = list.count;
|
||||
if (count === 0)
|
||||
return 0;
|
||||
|
||||
displaced: Transition {
|
||||
Anim {
|
||||
property: "y"
|
||||
}
|
||||
}
|
||||
const scrollY = list.contentY;
|
||||
|
||||
ExtraIndicator {
|
||||
anchors.top: parent.top
|
||||
extra: {
|
||||
const count = list.count;
|
||||
if (count === 0)
|
||||
return 0;
|
||||
let height = 0;
|
||||
for (let i = 0; i < count; i++) {
|
||||
height += (list.itemAtIndex(i)?.nonAnimHeight ?? 0) + 8;
|
||||
|
||||
const scrollY = list.contentY;
|
||||
if (height - 8 >= scrollY)
|
||||
return i;
|
||||
}
|
||||
|
||||
let height = 0;
|
||||
for (let i = 0; i < count; i++) {
|
||||
height += (list.itemAtIndex(i)?.nonAnimHeight ?? 0) + 8;
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
if (height - 8 >= scrollY)
|
||||
return i;
|
||||
}
|
||||
ExtraIndicator {
|
||||
anchors.bottom: parent.bottom
|
||||
extra: {
|
||||
const count = list.count;
|
||||
if (count === 0)
|
||||
return 0;
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
const scrollY = list.contentHeight - (list.contentY + list.height);
|
||||
|
||||
ExtraIndicator {
|
||||
anchors.bottom: parent.bottom
|
||||
extra: {
|
||||
const count = list.count;
|
||||
if (count === 0)
|
||||
return 0;
|
||||
let height = 0;
|
||||
for (let i = count - 1; i >= 0; i--) {
|
||||
height += (list.itemAtIndex(i)?.nonAnimHeight ?? 0) + 8;
|
||||
|
||||
const scrollY = list.contentHeight - (list.contentY + list.height);
|
||||
if (height - 8 >= scrollY)
|
||||
return count - i - 1;
|
||||
}
|
||||
|
||||
let height = 0;
|
||||
for (let i = count - 1; i >= 0; i--) {
|
||||
height += (list.itemAtIndex(i)?.nonAnimHeight ?? 0) + 8;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (height - 8 >= scrollY)
|
||||
return count - i - 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on implicitHeight {
|
||||
Anim {}
|
||||
}
|
||||
|
||||
component Anim: NumberAnimation {
|
||||
easing.type: Easing.BezierSpline
|
||||
component Anim: NumberAnimation {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
easing.type: Easing.BezierSpline
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,473 +12,456 @@ import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
CustomRect {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
required property NotifServer.Notif modelData
|
||||
readonly property bool hasImage: modelData.image.length > 0
|
||||
readonly property bool hasAppIcon: modelData.appIcon.length > 0
|
||||
readonly property int nonAnimHeight: summary.implicitHeight + (root.expanded ? appName.height + body.height + actions.height + actions.anchors.topMargin : bodyPreview.height) + inner.anchors.margins * 2
|
||||
property bool expanded: Config.notifs.openExpanded
|
||||
property bool expanded: Config.notifs.openExpanded
|
||||
readonly property bool hasAppIcon: modelData.appIcon.length > 0
|
||||
readonly property bool hasImage: modelData.image.length > 0
|
||||
required property NotifServer.Notif modelData
|
||||
readonly property int nonAnimHeight: summary.implicitHeight + (root.expanded ? appName.height + body.height + actions.height + actions.anchors.topMargin : bodyPreview.height) + inner.anchors.margins * 2
|
||||
|
||||
color: root.modelData.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3secondaryContainer : DynamicColors.tPalette.m3surfaceContainer
|
||||
radius: 6
|
||||
implicitWidth: Config.notifs.sizes.width
|
||||
implicitHeight: inner.implicitHeight
|
||||
color: root.modelData.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3secondaryContainer : DynamicColors.tPalette.m3surfaceContainer
|
||||
implicitHeight: inner.implicitHeight
|
||||
implicitWidth: Config.notifs.sizes.width
|
||||
radius: 6
|
||||
x: Config.notifs.sizes.width
|
||||
|
||||
x: Config.notifs.sizes.width
|
||||
Component.onCompleted: {
|
||||
x = 0;
|
||||
modelData.lock(this);
|
||||
}
|
||||
Component.onDestruction: modelData.unlock(this)
|
||||
|
||||
Behavior on x {
|
||||
Anim {
|
||||
Behavior on x {
|
||||
Anim {
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
property int startY
|
||||
Component.onCompleted: {
|
||||
x = 0;
|
||||
modelData.lock(this);
|
||||
}
|
||||
Component.onDestruction: modelData.unlock(this)
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: root.expanded && body.hoveredLink ? Qt.PointingHandCursor : pressed ? Qt.ClosedHandCursor : undefined
|
||||
acceptedButtons: Qt.LeftButton | Qt.MiddleButton
|
||||
preventStealing: true
|
||||
MouseArea {
|
||||
property int startY
|
||||
|
||||
onEntered: root.modelData.timer.stop()
|
||||
onExited: {
|
||||
if (!pressed)
|
||||
root.modelData.timer.start();
|
||||
}
|
||||
acceptedButtons: Qt.LeftButton | Qt.MiddleButton
|
||||
anchors.fill: parent
|
||||
cursorShape: root.expanded && body.hoveredLink ? Qt.PointingHandCursor : pressed ? Qt.ClosedHandCursor : undefined
|
||||
drag.axis: Drag.XAxis
|
||||
drag.target: parent
|
||||
hoverEnabled: true
|
||||
preventStealing: true
|
||||
|
||||
drag.target: parent
|
||||
drag.axis: Drag.XAxis
|
||||
onClicked: event => {
|
||||
if (!Config.notifs.actionOnClick || event.button !== Qt.LeftButton)
|
||||
return;
|
||||
|
||||
onPressed: event => {
|
||||
root.modelData.timer.stop();
|
||||
startY = event.y;
|
||||
if (event.button === Qt.MiddleButton)
|
||||
root.modelData.close();
|
||||
}
|
||||
onReleased: event => {
|
||||
if (!containsMouse)
|
||||
root.modelData.timer.start();
|
||||
const actions = root.modelData.actions;
|
||||
if (actions?.length === 1)
|
||||
actions[0].invoke();
|
||||
}
|
||||
onEntered: root.modelData.timer.stop()
|
||||
onExited: {
|
||||
if (!pressed)
|
||||
root.modelData.timer.start();
|
||||
}
|
||||
onPositionChanged: event => {
|
||||
if (pressed) {
|
||||
const diffY = event.y - startY;
|
||||
if (Math.abs(diffY) > Config.notifs.expandThreshold)
|
||||
root.expanded = diffY > 0;
|
||||
}
|
||||
}
|
||||
onPressed: event => {
|
||||
root.modelData.timer.stop();
|
||||
startY = event.y;
|
||||
if (event.button === Qt.MiddleButton)
|
||||
root.modelData.close();
|
||||
}
|
||||
onReleased: event => {
|
||||
if (!containsMouse)
|
||||
root.modelData.timer.start();
|
||||
|
||||
if (Math.abs(root.x) < Config.notifs.sizes.width * Config.notifs.clearThreshold)
|
||||
root.x = 0;
|
||||
else
|
||||
root.modelData.popup = false;
|
||||
}
|
||||
onPositionChanged: event => {
|
||||
if (pressed) {
|
||||
const diffY = event.y - startY;
|
||||
if (Math.abs(diffY) > Config.notifs.expandThreshold)
|
||||
root.expanded = diffY > 0;
|
||||
}
|
||||
}
|
||||
onClicked: event => {
|
||||
if (!Config.notifs.actionOnClick || event.button !== Qt.LeftButton)
|
||||
return;
|
||||
if (Math.abs(root.x) < Config.notifs.sizes.width * Config.notifs.clearThreshold)
|
||||
root.x = 0;
|
||||
else
|
||||
root.modelData.popup = false;
|
||||
}
|
||||
|
||||
const actions = root.modelData.actions;
|
||||
if (actions?.length === 1)
|
||||
actions[0].invoke();
|
||||
}
|
||||
Item {
|
||||
id: inner
|
||||
|
||||
Item {
|
||||
id: inner
|
||||
anchors.left: parent.left
|
||||
anchors.margins: 8
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
implicitHeight: root.nonAnimHeight
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.margins: 8
|
||||
|
||||
implicitHeight: root.nonAnimHeight
|
||||
|
||||
Behavior on implicitHeight {
|
||||
Anim {
|
||||
Behavior on implicitHeight {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: image
|
||||
Loader {
|
||||
id: image
|
||||
|
||||
active: root.hasImage
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
width: Config.notifs.sizes.image
|
||||
height: Config.notifs.sizes.image
|
||||
visible: root.hasImage || root.hasAppIcon
|
||||
active: root.hasImage
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
asynchronous: true
|
||||
height: Config.notifs.sizes.image
|
||||
visible: root.hasImage || root.hasAppIcon
|
||||
width: Config.notifs.sizes.image
|
||||
|
||||
sourceComponent: ClippingRectangle {
|
||||
radius: 1000
|
||||
implicitWidth: Config.notifs.sizes.image
|
||||
implicitHeight: Config.notifs.sizes.image
|
||||
sourceComponent: ClippingRectangle {
|
||||
implicitHeight: Config.notifs.sizes.image
|
||||
implicitWidth: Config.notifs.sizes.image
|
||||
radius: 1000
|
||||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
source: Qt.resolvedUrl(root.modelData.image)
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
asynchronous: true
|
||||
cache: false
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
mipmap: true
|
||||
cache: false
|
||||
asynchronous: true
|
||||
}
|
||||
}
|
||||
}
|
||||
source: Qt.resolvedUrl(root.modelData.image)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: appIcon
|
||||
Loader {
|
||||
id: appIcon
|
||||
|
||||
active: root.hasAppIcon || !root.hasImage
|
||||
|
||||
anchors.horizontalCenter: root.hasImage ? undefined : image.horizontalCenter
|
||||
anchors.verticalCenter: root.hasImage ? undefined : image.verticalCenter
|
||||
anchors.right: root.hasImage ? image.right : undefined
|
||||
anchors.bottom: root.hasImage ? image.bottom : undefined
|
||||
active: root.hasAppIcon || !root.hasImage
|
||||
anchors.bottom: root.hasImage ? image.bottom : undefined
|
||||
anchors.horizontalCenter: root.hasImage ? undefined : image.horizontalCenter
|
||||
anchors.right: root.hasImage ? image.right : undefined
|
||||
anchors.verticalCenter: root.hasImage ? undefined : image.verticalCenter
|
||||
asynchronous: true
|
||||
|
||||
sourceComponent: CustomRect {
|
||||
radius: 1000
|
||||
color: root.modelData.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3error : root.modelData.urgency === NotificationUrgency.Low ? DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, 2) : DynamicColors.palette.m3secondaryContainer
|
||||
implicitWidth: root.hasImage ? Config.notifs.sizes.badge : Config.notifs.sizes.image
|
||||
implicitHeight: root.hasImage ? Config.notifs.sizes.badge : Config.notifs.sizes.image
|
||||
sourceComponent: CustomRect {
|
||||
color: root.modelData.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3error : root.modelData.urgency === NotificationUrgency.Low ? DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, 2) : DynamicColors.palette.m3secondaryContainer
|
||||
implicitHeight: root.hasImage ? Config.notifs.sizes.badge : Config.notifs.sizes.image
|
||||
implicitWidth: root.hasImage ? Config.notifs.sizes.badge : Config.notifs.sizes.image
|
||||
radius: 1000
|
||||
|
||||
Loader {
|
||||
id: icon
|
||||
Loader {
|
||||
id: icon
|
||||
|
||||
active: root.hasAppIcon
|
||||
active: root.hasAppIcon
|
||||
anchors.centerIn: parent
|
||||
asynchronous: true
|
||||
height: Math.round(parent.width * 0.6)
|
||||
width: Math.round(parent.width * 0.6)
|
||||
|
||||
anchors.centerIn: parent
|
||||
sourceComponent: CustomIcon {
|
||||
anchors.fill: parent
|
||||
layer.enabled: root.modelData.appIcon.endsWith("symbolic")
|
||||
source: Quickshell.iconPath(root.modelData.appIcon)
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
active: !root.hasAppIcon
|
||||
anchors.centerIn: parent
|
||||
anchors.horizontalCenterOffset: -18 * 0.02
|
||||
anchors.verticalCenterOffset: 18 * 0.02
|
||||
asynchronous: true
|
||||
|
||||
width: Math.round(parent.width * 0.6)
|
||||
height: Math.round(parent.width * 0.6)
|
||||
sourceComponent: MaterialIcon {
|
||||
color: root.modelData.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3onError : root.modelData.urgency === NotificationUrgency.Low ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3onSecondaryContainer
|
||||
font.pointSize: 18
|
||||
text: Icons.getNotifIcon(root.modelData.summary, root.modelData.urgency)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceComponent: CustomIcon {
|
||||
anchors.fill: parent
|
||||
source: Quickshell.iconPath(root.modelData.appIcon)
|
||||
layer.enabled: root.modelData.appIcon.endsWith("symbolic")
|
||||
}
|
||||
}
|
||||
CustomText {
|
||||
id: appName
|
||||
|
||||
Loader {
|
||||
active: !root.hasAppIcon
|
||||
anchors.centerIn: parent
|
||||
anchors.horizontalCenterOffset: -18 * 0.02
|
||||
anchors.verticalCenterOffset: 18 * 0.02
|
||||
asynchronous: true
|
||||
anchors.left: image.right
|
||||
anchors.leftMargin: 10
|
||||
anchors.top: parent.top
|
||||
animate: true
|
||||
color: DynamicColors.palette.m3onSurfaceVariant
|
||||
font.pointSize: 10
|
||||
maximumLineCount: 1
|
||||
opacity: root.expanded ? 1 : 0
|
||||
text: appNameMetrics.elidedText
|
||||
|
||||
sourceComponent: MaterialIcon {
|
||||
text: Icons.getNotifIcon(root.modelData.summary, root.modelData.urgency)
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
color: root.modelData.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3onError : root.modelData.urgency === NotificationUrgency.Low ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3onSecondaryContainer
|
||||
font.pointSize: 18
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TextMetrics {
|
||||
id: appNameMetrics
|
||||
|
||||
CustomText {
|
||||
id: appName
|
||||
elide: Text.ElideRight
|
||||
elideWidth: expandBtn.x - time.width - timeSep.width - summary.x - 7 * 3
|
||||
font.family: appName.font.family
|
||||
font.pointSize: appName.font.pointSize
|
||||
text: root.modelData.appName
|
||||
}
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: image.right
|
||||
anchors.leftMargin: 10
|
||||
CustomText {
|
||||
id: summary
|
||||
|
||||
animate: true
|
||||
text: appNameMetrics.elidedText
|
||||
maximumLineCount: 1
|
||||
color: DynamicColors.palette.m3onSurfaceVariant
|
||||
font.pointSize: 10
|
||||
anchors.left: image.right
|
||||
anchors.leftMargin: 10
|
||||
anchors.top: parent.top
|
||||
animate: true
|
||||
height: implicitHeight
|
||||
maximumLineCount: 1
|
||||
text: summaryMetrics.elidedText
|
||||
|
||||
opacity: root.expanded ? 1 : 0
|
||||
Behavior on height {
|
||||
Anim {
|
||||
}
|
||||
}
|
||||
states: State {
|
||||
name: "expanded"
|
||||
when: root.expanded
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
PropertyChanges {
|
||||
summary.maximumLineCount: undefined
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
id: appNameMetrics
|
||||
AnchorChanges {
|
||||
anchors.top: appName.bottom
|
||||
target: summary
|
||||
}
|
||||
}
|
||||
transitions: Transition {
|
||||
PropertyAction {
|
||||
property: "maximumLineCount"
|
||||
target: summary
|
||||
}
|
||||
|
||||
text: root.modelData.appName
|
||||
font.family: appName.font.family
|
||||
font.pointSize: appName.font.pointSize
|
||||
elide: Text.ElideRight
|
||||
elideWidth: expandBtn.x - time.width - timeSep.width - summary.x - 7 * 3
|
||||
}
|
||||
|
||||
CustomText {
|
||||
id: summary
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: image.right
|
||||
anchors.leftMargin: 10
|
||||
|
||||
animate: true
|
||||
text: summaryMetrics.elidedText
|
||||
maximumLineCount: 1
|
||||
height: implicitHeight
|
||||
|
||||
states: State {
|
||||
name: "expanded"
|
||||
when: root.expanded
|
||||
|
||||
PropertyChanges {
|
||||
summary.maximumLineCount: undefined
|
||||
}
|
||||
|
||||
AnchorChanges {
|
||||
target: summary
|
||||
anchors.top: appName.bottom
|
||||
}
|
||||
}
|
||||
|
||||
transitions: Transition {
|
||||
PropertyAction {
|
||||
target: summary
|
||||
property: "maximumLineCount"
|
||||
}
|
||||
AnchorAnimation {
|
||||
easing.type: Easing.BezierSpline
|
||||
AnchorAnimation {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on height {
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
id: summaryMetrics
|
||||
|
||||
text: root.modelData.summary
|
||||
font.family: summary.font.family
|
||||
font.pointSize: summary.font.pointSize
|
||||
elide: Text.ElideRight
|
||||
elideWidth: expandBtn.x - time.width - timeSep.width - summary.x - 7 * 3
|
||||
}
|
||||
|
||||
CustomText {
|
||||
id: timeSep
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: summary.right
|
||||
anchors.leftMargin: 7
|
||||
|
||||
text: "•"
|
||||
color: DynamicColors.palette.m3onSurfaceVariant
|
||||
font.pointSize: 10
|
||||
|
||||
states: State {
|
||||
name: "expanded"
|
||||
when: root.expanded
|
||||
|
||||
AnchorChanges {
|
||||
target: timeSep
|
||||
anchors.left: appName.right
|
||||
}
|
||||
}
|
||||
|
||||
transitions: Transition {
|
||||
AnchorAnimation {
|
||||
easing.type: Easing.BezierSpline
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
id: summaryMetrics
|
||||
|
||||
elide: Text.ElideRight
|
||||
elideWidth: expandBtn.x - time.width - timeSep.width - summary.x - 7 * 3
|
||||
font.family: summary.font.family
|
||||
font.pointSize: summary.font.pointSize
|
||||
text: root.modelData.summary
|
||||
}
|
||||
|
||||
CustomText {
|
||||
id: timeSep
|
||||
|
||||
anchors.left: summary.right
|
||||
anchors.leftMargin: 7
|
||||
anchors.top: parent.top
|
||||
color: DynamicColors.palette.m3onSurfaceVariant
|
||||
font.pointSize: 10
|
||||
text: "•"
|
||||
|
||||
states: State {
|
||||
name: "expanded"
|
||||
when: root.expanded
|
||||
|
||||
AnchorChanges {
|
||||
anchors.left: appName.right
|
||||
target: timeSep
|
||||
}
|
||||
}
|
||||
transitions: Transition {
|
||||
AnchorAnimation {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
easing.type: Easing.BezierSpline
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CustomText {
|
||||
id: time
|
||||
CustomText {
|
||||
id: time
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: timeSep.right
|
||||
anchors.leftMargin: 7
|
||||
anchors.left: timeSep.right
|
||||
anchors.leftMargin: 7
|
||||
anchors.top: parent.top
|
||||
animate: true
|
||||
color: DynamicColors.palette.m3onSurfaceVariant
|
||||
font.pointSize: 10
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
text: root.modelData.timeStr
|
||||
}
|
||||
|
||||
animate: true
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
text: root.modelData.timeStr
|
||||
color: DynamicColors.palette.m3onSurfaceVariant
|
||||
font.pointSize: 10
|
||||
}
|
||||
Item {
|
||||
id: expandBtn
|
||||
|
||||
Item {
|
||||
id: expandBtn
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
implicitHeight: expandIcon.height
|
||||
implicitWidth: expandIcon.height
|
||||
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
StateLayer {
|
||||
function onClicked() {
|
||||
root.expanded = !root.expanded;
|
||||
}
|
||||
|
||||
implicitWidth: expandIcon.height
|
||||
implicitHeight: expandIcon.height
|
||||
color: root.modelData.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onSurface
|
||||
radius: 1000
|
||||
}
|
||||
|
||||
StateLayer {
|
||||
radius: 1000
|
||||
color: root.modelData.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onSurface
|
||||
MaterialIcon {
|
||||
id: expandIcon
|
||||
|
||||
function onClicked() {
|
||||
root.expanded = !root.expanded;
|
||||
}
|
||||
}
|
||||
anchors.centerIn: parent
|
||||
animate: true
|
||||
font.pointSize: 13
|
||||
text: root.expanded ? "expand_less" : "expand_more"
|
||||
}
|
||||
}
|
||||
|
||||
MaterialIcon {
|
||||
id: expandIcon
|
||||
CustomText {
|
||||
id: bodyPreview
|
||||
|
||||
anchors.centerIn: parent
|
||||
anchors.left: summary.left
|
||||
anchors.right: expandBtn.left
|
||||
anchors.rightMargin: 7
|
||||
anchors.top: summary.bottom
|
||||
animate: true
|
||||
color: DynamicColors.palette.m3onSurfaceVariant
|
||||
font.pointSize: 10
|
||||
opacity: root.expanded ? 0 : 1
|
||||
text: bodyPreviewMetrics.elidedText
|
||||
textFormat: Text.MarkdownText
|
||||
|
||||
animate: true
|
||||
text: root.expanded ? "expand_less" : "expand_more"
|
||||
font.pointSize: 13
|
||||
}
|
||||
}
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CustomText {
|
||||
id: bodyPreview
|
||||
TextMetrics {
|
||||
id: bodyPreviewMetrics
|
||||
|
||||
anchors.left: summary.left
|
||||
anchors.right: expandBtn.left
|
||||
anchors.top: summary.bottom
|
||||
anchors.rightMargin: 7
|
||||
elide: Text.ElideRight
|
||||
elideWidth: bodyPreview.width
|
||||
font.family: bodyPreview.font.family
|
||||
font.pointSize: bodyPreview.font.pointSize
|
||||
text: root.modelData.body
|
||||
}
|
||||
|
||||
animate: true
|
||||
textFormat: Text.MarkdownText
|
||||
text: bodyPreviewMetrics.elidedText
|
||||
color: DynamicColors.palette.m3onSurfaceVariant
|
||||
font.pointSize: 10
|
||||
CustomText {
|
||||
id: body
|
||||
|
||||
opacity: root.expanded ? 0 : 1
|
||||
anchors.left: summary.left
|
||||
anchors.right: expandBtn.left
|
||||
anchors.rightMargin: 7
|
||||
anchors.top: summary.bottom
|
||||
animate: true
|
||||
color: DynamicColors.palette.m3onSurfaceVariant
|
||||
font.pointSize: 10
|
||||
height: text ? implicitHeight : 0
|
||||
opacity: root.expanded ? 1 : 0
|
||||
text: root.modelData.body
|
||||
textFormat: Text.MarkdownText
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
}
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
id: bodyPreviewMetrics
|
||||
onLinkActivated: link => {
|
||||
if (!root.expanded)
|
||||
return;
|
||||
|
||||
text: root.modelData.body
|
||||
font.family: bodyPreview.font.family
|
||||
font.pointSize: bodyPreview.font.pointSize
|
||||
elide: Text.ElideRight
|
||||
elideWidth: bodyPreview.width
|
||||
}
|
||||
Quickshell.execDetached(["app2unit", "-O", "--", link]);
|
||||
root.modelData.popup = false;
|
||||
}
|
||||
}
|
||||
|
||||
CustomText {
|
||||
id: body
|
||||
RowLayout {
|
||||
id: actions
|
||||
|
||||
anchors.left: summary.left
|
||||
anchors.right: expandBtn.left
|
||||
anchors.top: summary.bottom
|
||||
anchors.rightMargin: 7
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: body.bottom
|
||||
anchors.topMargin: 7
|
||||
opacity: root.expanded ? 1 : 0
|
||||
spacing: 10
|
||||
|
||||
animate: true
|
||||
textFormat: Text.MarkdownText
|
||||
text: root.modelData.body
|
||||
color: DynamicColors.palette.m3onSurfaceVariant
|
||||
font.pointSize: 10
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
height: text ? implicitHeight : 0
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
}
|
||||
}
|
||||
|
||||
onLinkActivated: link => {
|
||||
if (!root.expanded)
|
||||
return;
|
||||
Action {
|
||||
modelData: QtObject {
|
||||
readonly property string text: qsTr("Close")
|
||||
|
||||
Quickshell.execDetached(["app2unit", "-O", "--", link]);
|
||||
root.modelData.popup = false;
|
||||
}
|
||||
function invoke(): void {
|
||||
root.modelData.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
opacity: root.expanded ? 1 : 0
|
||||
Repeater {
|
||||
model: root.modelData.actions
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
delegate: Component {
|
||||
Action {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: actions
|
||||
component Action: CustomRect {
|
||||
id: action
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: body.bottom
|
||||
anchors.topMargin: 7
|
||||
required property var modelData
|
||||
|
||||
spacing: 10
|
||||
Layout.preferredHeight: actionText.height + 4 * 2
|
||||
Layout.preferredWidth: actionText.width + 8 * 2
|
||||
color: root.modelData.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3secondary : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 2)
|
||||
implicitHeight: actionText.height + 4 * 2
|
||||
implicitWidth: actionText.width + 8 * 2
|
||||
radius: 1000
|
||||
|
||||
opacity: root.expanded ? 1 : 0
|
||||
StateLayer {
|
||||
function onClicked(): void {
|
||||
action.modelData.invoke();
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {}
|
||||
}
|
||||
color: root.modelData.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3onSecondary : DynamicColors.palette.m3onSurface
|
||||
radius: 1000
|
||||
}
|
||||
|
||||
Action {
|
||||
modelData: QtObject {
|
||||
readonly property string text: qsTr("Close")
|
||||
function invoke(): void {
|
||||
root.modelData.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
CustomText {
|
||||
id: actionText
|
||||
|
||||
Repeater {
|
||||
model: root.modelData.actions
|
||||
anchors.centerIn: parent
|
||||
color: root.modelData.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3onSecondary : DynamicColors.palette.m3onSurfaceVariant
|
||||
font.pointSize: 10
|
||||
text: actionTextMetrics.elidedText
|
||||
}
|
||||
|
||||
delegate: Component {
|
||||
Action {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TextMetrics {
|
||||
id: actionTextMetrics
|
||||
|
||||
component Action: CustomRect {
|
||||
id: action
|
||||
|
||||
required property var modelData
|
||||
|
||||
radius: 1000
|
||||
color: root.modelData.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3secondary : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 2)
|
||||
|
||||
Layout.preferredWidth: actionText.width + 8 * 2
|
||||
Layout.preferredHeight: actionText.height + 4 * 2
|
||||
implicitWidth: actionText.width + 8 * 2
|
||||
implicitHeight: actionText.height + 4 * 2
|
||||
|
||||
StateLayer {
|
||||
radius: 1000
|
||||
color: root.modelData.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3onSecondary : DynamicColors.palette.m3onSurface
|
||||
|
||||
function onClicked(): void {
|
||||
action.modelData.invoke();
|
||||
}
|
||||
}
|
||||
|
||||
CustomText {
|
||||
id: actionText
|
||||
|
||||
anchors.centerIn: parent
|
||||
text: actionTextMetrics.elidedText
|
||||
color: root.modelData.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3onSecondary : DynamicColors.palette.m3onSurfaceVariant
|
||||
font.pointSize: 10
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
id: actionTextMetrics
|
||||
|
||||
text: action.modelData.text
|
||||
font.family: actionText.font.family
|
||||
font.pointSize: actionText.font.pointSize
|
||||
elide: Text.ElideRight
|
||||
elideWidth: {
|
||||
const numActions = root.modelData.actions.length + 1;
|
||||
return (inner.width - actions.spacing * (numActions - 1)) / numActions - 8 * 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
elide: Text.ElideRight
|
||||
elideWidth: {
|
||||
const numActions = root.modelData.actions.length + 1;
|
||||
return (inner.width - actions.spacing * (numActions - 1)) / numActions - 8 * 2;
|
||||
}
|
||||
font.family: actionText.font.family
|
||||
font.pointSize: actionText.font.pointSize
|
||||
text: action.modelData.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,50 +4,51 @@ import QtQuick
|
||||
import QtQuick.Shapes
|
||||
|
||||
ShapePath {
|
||||
id: root
|
||||
|
||||
required property Wrapper wrapper
|
||||
required property var panels
|
||||
|
||||
readonly property real rounding: 8
|
||||
|
||||
readonly property real notifsWidthDiff: panels.notifications.width - wrapper.width
|
||||
readonly property real notifsRoundingX: panels.notifications.height > 0 && notifsWidthDiff < rounding * 2 ? notifsWidthDiff / 2 : rounding
|
||||
|
||||
readonly property real utilsWidthDiff: panels.utilities.width - wrapper.width
|
||||
readonly property real utilsRoundingX: utilsWidthDiff < rounding * 2 ? utilsWidthDiff / 2 : rounding
|
||||
id: root
|
||||
|
||||
readonly property bool flatten: wrapper.width < rounding * 2
|
||||
readonly property real notifsRoundingX: panels.notifications.height > 0 && notifsWidthDiff < rounding * 2 ? notifsWidthDiff / 2 : rounding
|
||||
readonly property real notifsWidthDiff: panels.notifications.width - wrapper.width
|
||||
required property var panels
|
||||
readonly property real rounding: 8
|
||||
readonly property real utilsRoundingX: utilsWidthDiff < rounding * 2 ? utilsWidthDiff / 2 : rounding
|
||||
readonly property real utilsWidthDiff: panels.utilities.width - wrapper.width
|
||||
required property Wrapper wrapper
|
||||
|
||||
strokeWidth: -1
|
||||
fillColor: flatten ? "transparent" : DynamicColors.palette.m3surface
|
||||
strokeWidth: -1
|
||||
|
||||
PathLine {
|
||||
relativeX: -root.wrapper.width - root.notifsRoundingX
|
||||
relativeY: 0
|
||||
}
|
||||
PathArc {
|
||||
relativeX: root.notifsRoundingX
|
||||
relativeY: root.rounding
|
||||
radiusX: root.notifsRoundingX
|
||||
radiusY: root.rounding
|
||||
}
|
||||
PathLine {
|
||||
relativeX: 0
|
||||
relativeY: root.wrapper.height - root.rounding * 2
|
||||
}
|
||||
PathArc {
|
||||
relativeX: -root.utilsRoundingX
|
||||
relativeY: root.rounding
|
||||
radiusX: root.utilsRoundingX
|
||||
radiusY: root.rounding
|
||||
}
|
||||
PathLine {
|
||||
relativeX: root.wrapper.width + root.utilsRoundingX
|
||||
relativeY: 0
|
||||
}
|
||||
Behavior on fillColor {
|
||||
CAnim {
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on fillColor {
|
||||
CAnim {}
|
||||
}
|
||||
PathLine {
|
||||
relativeX: -root.wrapper.width - root.notifsRoundingX
|
||||
relativeY: 0
|
||||
}
|
||||
|
||||
PathArc {
|
||||
radiusX: root.notifsRoundingX
|
||||
radiusY: root.rounding
|
||||
relativeX: root.notifsRoundingX
|
||||
relativeY: root.rounding
|
||||
}
|
||||
|
||||
PathLine {
|
||||
relativeX: 0
|
||||
relativeY: root.wrapper.height - root.rounding * 2
|
||||
}
|
||||
|
||||
PathArc {
|
||||
radiusX: root.utilsRoundingX
|
||||
radiusY: root.rounding
|
||||
relativeX: -root.utilsRoundingX
|
||||
relativeY: root.rounding
|
||||
}
|
||||
|
||||
PathLine {
|
||||
relativeX: root.wrapper.width + root.utilsRoundingX
|
||||
relativeY: 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,36 +4,34 @@ import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
Item {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
required property Props props
|
||||
required property var visibilities
|
||||
required property Props props
|
||||
required property var visibilities
|
||||
|
||||
ColumnLayout {
|
||||
id: layout
|
||||
ColumnLayout {
|
||||
id: layout
|
||||
|
||||
anchors.fill: parent
|
||||
spacing: 8
|
||||
anchors.fill: parent
|
||||
spacing: 8
|
||||
|
||||
CustomRect {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
CustomRect {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
color: DynamicColors.tPalette.m3surfaceContainerLow
|
||||
radius: 8
|
||||
|
||||
radius: 8
|
||||
color: DynamicColors.tPalette.m3surfaceContainerLow
|
||||
NotifDock {
|
||||
props: root.props
|
||||
visibilities: root.visibilities
|
||||
}
|
||||
}
|
||||
|
||||
NotifDock {
|
||||
props: root.props
|
||||
visibilities: root.visibilities
|
||||
}
|
||||
}
|
||||
|
||||
CustomRect {
|
||||
Layout.topMargin: 8 - layout.spacing
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: 1
|
||||
|
||||
color: DynamicColors.tPalette.m3outlineVariant
|
||||
}
|
||||
}
|
||||
CustomRect {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8 - layout.spacing
|
||||
color: DynamicColors.tPalette.m3outlineVariant
|
||||
implicitHeight: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,158 +9,153 @@ import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
CustomRect {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
required property NotifServer.Notif modelData
|
||||
required property Props props
|
||||
required property bool expanded
|
||||
required property var visibilities
|
||||
readonly property CustomText body: expandedContent.item?.body ?? null
|
||||
required property bool expanded
|
||||
required property NotifServer.Notif modelData
|
||||
readonly property real nonAnimHeight: expanded ? summary.implicitHeight + expandedContent.implicitHeight + expandedContent.anchors.topMargin + 10 * 2 : summaryHeightMetrics.height
|
||||
required property Props props
|
||||
required property var visibilities
|
||||
|
||||
readonly property CustomText body: expandedContent.item?.body ?? null
|
||||
readonly property real nonAnimHeight: expanded ? summary.implicitHeight + expandedContent.implicitHeight + expandedContent.anchors.topMargin + 10 * 2 : summaryHeightMetrics.height
|
||||
color: {
|
||||
const c = root.modelData.urgency === "critical" ? DynamicColors.palette.m3secondaryContainer : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 2);
|
||||
return expanded ? c : Qt.alpha(c, 0);
|
||||
}
|
||||
implicitHeight: nonAnimHeight
|
||||
radius: 6
|
||||
|
||||
implicitHeight: nonAnimHeight
|
||||
|
||||
radius: 6
|
||||
color: {
|
||||
const c = root.modelData.urgency === "critical" ? DynamicColors.palette.m3secondaryContainer : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 2);
|
||||
return expanded ? c : Qt.alpha(c, 0);
|
||||
}
|
||||
|
||||
states: State {
|
||||
name: "expanded"
|
||||
when: root.expanded
|
||||
|
||||
PropertyChanges {
|
||||
summary.anchors.margins: 10
|
||||
dummySummary.anchors.margins: 10
|
||||
compactBody.anchors.margins: 10
|
||||
timeStr.anchors.margins: 10
|
||||
expandedContent.anchors.margins: 10
|
||||
summary.width: root.width - 10 * 2 - timeStr.implicitWidth - 7
|
||||
summary.maximumLineCount: Number.MAX_SAFE_INTEGER
|
||||
}
|
||||
}
|
||||
|
||||
transitions: Transition {
|
||||
Anim {
|
||||
properties: "margins,width,maximumLineCount"
|
||||
}
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
id: summaryHeightMetrics
|
||||
|
||||
font: summary.font
|
||||
text: " " // Use this height to prevent weird characters from changing the line height
|
||||
}
|
||||
|
||||
CustomText {
|
||||
id: summary
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
|
||||
width: parent.width
|
||||
text: root.modelData.summary
|
||||
color: root.modelData.urgency === "critical" ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onSurface
|
||||
elide: Text.ElideRight
|
||||
wrapMode: Text.WordWrap
|
||||
maximumLineCount: 1
|
||||
}
|
||||
|
||||
CustomText {
|
||||
id: dummySummary
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
|
||||
visible: false
|
||||
text: root.modelData.summary
|
||||
}
|
||||
|
||||
WrappedLoader {
|
||||
id: compactBody
|
||||
|
||||
shouldBeActive: !root.expanded
|
||||
anchors.top: parent.top
|
||||
anchors.left: dummySummary.right
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 7
|
||||
|
||||
sourceComponent: CustomText {
|
||||
textFormat: Text.StyledText
|
||||
text: root.modelData.body.replace(/\n/g, " ")
|
||||
color: root.modelData.urgency === "critical" ? DynamicColors.palette.m3secondary : DynamicColors.palette.m3outline
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
|
||||
WrappedLoader {
|
||||
id: timeStr
|
||||
|
||||
shouldBeActive: root.expanded
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
|
||||
sourceComponent: CustomText {
|
||||
animate: true
|
||||
text: root.modelData.timeStr
|
||||
color: DynamicColors.palette.m3outline
|
||||
font.pointSize: 11
|
||||
}
|
||||
}
|
||||
|
||||
WrappedLoader {
|
||||
id: expandedContent
|
||||
|
||||
shouldBeActive: root.expanded
|
||||
anchors.top: summary.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 7 / 2
|
||||
|
||||
sourceComponent: ColumnLayout {
|
||||
readonly property alias body: body
|
||||
|
||||
spacing: 10
|
||||
|
||||
CustomText {
|
||||
id: body
|
||||
|
||||
Layout.fillWidth: true
|
||||
textFormat: Text.MarkdownText
|
||||
text: root.modelData.body.replace(/(.)\n(?!\n)/g, "$1\n\n") || qsTr("No body given")
|
||||
color: root.modelData.urgency === "critical" ? DynamicColors.palette.m3secondary : DynamicColors.palette.m3onSurface
|
||||
wrapMode: Text.WordWrap
|
||||
|
||||
onLinkActivated: link => {
|
||||
Quickshell.execDetached(["app2unit", "-O", "--", link]);
|
||||
root.visibilities.sidebar = false;
|
||||
}
|
||||
}
|
||||
|
||||
NotifActionList {
|
||||
notif: root.modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on implicitHeight {
|
||||
Anim {
|
||||
Behavior on implicitHeight {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
states: State {
|
||||
name: "expanded"
|
||||
when: root.expanded
|
||||
|
||||
component WrappedLoader: Loader {
|
||||
required property bool shouldBeActive
|
||||
PropertyChanges {
|
||||
compactBody.anchors.margins: 10
|
||||
dummySummary.anchors.margins: 10
|
||||
expandedContent.anchors.margins: 10
|
||||
summary.anchors.margins: 10
|
||||
summary.maximumLineCount: Number.MAX_SAFE_INTEGER
|
||||
summary.width: root.width - 10 * 2 - timeStr.implicitWidth - 7
|
||||
timeStr.anchors.margins: 10
|
||||
}
|
||||
}
|
||||
transitions: Transition {
|
||||
Anim {
|
||||
properties: "margins,width,maximumLineCount"
|
||||
}
|
||||
}
|
||||
|
||||
opacity: shouldBeActive ? 1 : 0
|
||||
active: opacity > 0
|
||||
TextMetrics {
|
||||
id: summaryHeightMetrics
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
font: summary.font
|
||||
text: " " // Use this height to prevent weird characters from changing the line height
|
||||
}
|
||||
|
||||
CustomText {
|
||||
id: summary
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
color: root.modelData.urgency === "critical" ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onSurface
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 1
|
||||
text: root.modelData.summary
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
CustomText {
|
||||
id: dummySummary
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
text: root.modelData.summary
|
||||
visible: false
|
||||
}
|
||||
|
||||
WrappedLoader {
|
||||
id: compactBody
|
||||
|
||||
anchors.left: dummySummary.right
|
||||
anchors.leftMargin: 7
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
shouldBeActive: !root.expanded
|
||||
|
||||
sourceComponent: CustomText {
|
||||
color: root.modelData.urgency === "critical" ? DynamicColors.palette.m3secondary : DynamicColors.palette.m3outline
|
||||
elide: Text.ElideRight
|
||||
text: root.modelData.body.replace(/\n/g, " ")
|
||||
textFormat: Text.StyledText
|
||||
}
|
||||
}
|
||||
|
||||
WrappedLoader {
|
||||
id: timeStr
|
||||
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
shouldBeActive: root.expanded
|
||||
|
||||
sourceComponent: CustomText {
|
||||
animate: true
|
||||
color: DynamicColors.palette.m3outline
|
||||
font.pointSize: 11
|
||||
text: root.modelData.timeStr
|
||||
}
|
||||
}
|
||||
|
||||
WrappedLoader {
|
||||
id: expandedContent
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: summary.bottom
|
||||
anchors.topMargin: 7 / 2
|
||||
shouldBeActive: root.expanded
|
||||
|
||||
sourceComponent: ColumnLayout {
|
||||
readonly property alias body: body
|
||||
|
||||
spacing: 10
|
||||
|
||||
CustomText {
|
||||
id: body
|
||||
|
||||
Layout.fillWidth: true
|
||||
color: root.modelData.urgency === "critical" ? DynamicColors.palette.m3secondary : DynamicColors.palette.m3onSurface
|
||||
text: root.modelData.body.replace(/(.)\n(?!\n)/g, "$1\n\n") || qsTr("No body given")
|
||||
textFormat: Text.MarkdownText
|
||||
wrapMode: Text.WordWrap
|
||||
|
||||
onLinkActivated: link => {
|
||||
Quickshell.execDetached(["app2unit", "-O", "--", link]);
|
||||
root.visibilities.sidebar = false;
|
||||
}
|
||||
}
|
||||
|
||||
NotifActionList {
|
||||
notif: root.modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component WrappedLoader: Loader {
|
||||
required property bool shouldBeActive
|
||||
|
||||
active: opacity > 0
|
||||
opacity: shouldBeActive ? 1 : 0
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,125 +10,124 @@ import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
Item {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
required property NotifServer.Notif notif
|
||||
required property NotifServer.Notif notif
|
||||
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: flickable.contentHeight
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: flickable.contentHeight
|
||||
|
||||
CustomFlickable {
|
||||
id: flickable
|
||||
CustomFlickable {
|
||||
id: flickable
|
||||
|
||||
anchors.fill: parent
|
||||
contentWidth: Math.max(width, actionList.implicitWidth)
|
||||
contentHeight: actionList.implicitHeight
|
||||
anchors.fill: parent
|
||||
contentHeight: actionList.implicitHeight
|
||||
contentWidth: Math.max(width, actionList.implicitWidth)
|
||||
|
||||
RowLayout {
|
||||
id: actionList
|
||||
RowLayout {
|
||||
id: actionList
|
||||
|
||||
anchors.fill: parent
|
||||
spacing: 7
|
||||
anchors.fill: parent
|
||||
spacing: 7
|
||||
|
||||
Repeater {
|
||||
model: [
|
||||
{
|
||||
isClose: true
|
||||
},
|
||||
...root.notif.actions,
|
||||
{
|
||||
isCopy: true
|
||||
}
|
||||
]
|
||||
Repeater {
|
||||
model: [
|
||||
{
|
||||
isClose: true
|
||||
},
|
||||
...root.notif.actions,
|
||||
{
|
||||
isCopy: true
|
||||
}
|
||||
]
|
||||
|
||||
CustomRect {
|
||||
id: action
|
||||
CustomRect {
|
||||
id: action
|
||||
|
||||
required property var modelData
|
||||
required property var modelData
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
implicitWidth: actionInner.implicitWidth + 5 * 2
|
||||
implicitHeight: actionInner.implicitHeight + 5 * 2
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: implicitWidth + (actionStateLayer.pressed ? 18 : 0)
|
||||
color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, 4)
|
||||
implicitHeight: actionInner.implicitHeight + 5 * 2
|
||||
implicitWidth: actionInner.implicitWidth + 5 * 2
|
||||
radius: actionStateLayer.pressed ? 6 / 2 : 6
|
||||
|
||||
Layout.preferredWidth: implicitWidth + (actionStateLayer.pressed ? 18 : 0)
|
||||
radius: actionStateLayer.pressed ? 6 / 2 : 6
|
||||
color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, 4)
|
||||
|
||||
Timer {
|
||||
id: copyTimer
|
||||
|
||||
interval: 1000
|
||||
onTriggered: actionInner.item.text = "content_copy"
|
||||
}
|
||||
|
||||
StateLayer {
|
||||
id: actionStateLayer
|
||||
|
||||
function onClicked(): void {
|
||||
if (action.modelData.isClose) {
|
||||
root.notif.close();
|
||||
} else if (action.modelData.isCopy) {
|
||||
Quickshell.clipboardText = root.notif.body;
|
||||
actionInner.item.text = "inventory";
|
||||
copyTimer.start();
|
||||
} else if (action.modelData.invoke) {
|
||||
action.modelData.invoke();
|
||||
} else if (!root.notif.resident) {
|
||||
root.notif.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: actionInner
|
||||
|
||||
anchors.centerIn: parent
|
||||
sourceComponent: action.modelData.isClose || action.modelData.isCopy ? iconBtn : root.notif.hasActionIcons ? iconComp : textComp
|
||||
}
|
||||
|
||||
Component {
|
||||
id: iconBtn
|
||||
|
||||
MaterialIcon {
|
||||
animate: action.modelData.isCopy ?? false
|
||||
text: action.modelData.isCopy ? "content_copy" : "close"
|
||||
color: DynamicColors.palette.m3onSurfaceVariant
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: iconComp
|
||||
|
||||
IconImage {
|
||||
source: Quickshell.iconPath(action.modelData.identifier)
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: textComp
|
||||
|
||||
CustomText {
|
||||
text: action.modelData.text
|
||||
color: DynamicColors.palette.m3onSurfaceVariant
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on Layout.preferredWidth {
|
||||
Anim {
|
||||
Behavior on Layout.preferredWidth {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on radius {
|
||||
Anim {
|
||||
}
|
||||
}
|
||||
Behavior on radius {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: copyTimer
|
||||
|
||||
interval: 1000
|
||||
|
||||
onTriggered: actionInner.item.text = "content_copy"
|
||||
}
|
||||
|
||||
StateLayer {
|
||||
id: actionStateLayer
|
||||
|
||||
function onClicked(): void {
|
||||
if (action.modelData.isClose) {
|
||||
root.notif.close();
|
||||
} else if (action.modelData.isCopy) {
|
||||
Quickshell.clipboardText = root.notif.body;
|
||||
actionInner.item.text = "inventory";
|
||||
copyTimer.start();
|
||||
} else if (action.modelData.invoke) {
|
||||
action.modelData.invoke();
|
||||
} else if (!root.notif.resident) {
|
||||
root.notif.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: actionInner
|
||||
|
||||
anchors.centerIn: parent
|
||||
sourceComponent: action.modelData.isClose || action.modelData.isCopy ? iconBtn : root.notif.hasActionIcons ? iconComp : textComp
|
||||
}
|
||||
|
||||
Component {
|
||||
id: iconBtn
|
||||
|
||||
MaterialIcon {
|
||||
animate: action.modelData.isCopy ?? false
|
||||
color: DynamicColors.palette.m3onSurfaceVariant
|
||||
text: action.modelData.isCopy ? "content_copy" : "close"
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: iconComp
|
||||
|
||||
IconImage {
|
||||
source: Quickshell.iconPath(action.modelData.identifier)
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: textComp
|
||||
|
||||
CustomText {
|
||||
color: DynamicColors.palette.m3onSurfaceVariant
|
||||
text: action.modelData.text
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,183 +10,177 @@ import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
Item {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
required property Props props
|
||||
required property var visibilities
|
||||
readonly property int notifCount: NotifServer.list.reduce((acc, n) => n.closed ? acc : acc + 1, 0)
|
||||
readonly property int notifCount: NotifServer.list.reduce((acc, n) => n.closed ? acc : acc + 1, 0)
|
||||
required property Props props
|
||||
required property var visibilities
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: 8
|
||||
anchors.fill: parent
|
||||
anchors.margins: 8
|
||||
|
||||
Component.onCompleted: NotifServer.list.forEach(n => n.popup = false)
|
||||
Component.onCompleted: NotifServer.list.forEach(n => n.popup = false)
|
||||
|
||||
Item {
|
||||
id: title
|
||||
Item {
|
||||
id: title
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.margins: 4
|
||||
anchors.left: parent.left
|
||||
anchors.margins: 4
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
implicitHeight: Math.max(count.implicitHeight, titleText.implicitHeight)
|
||||
|
||||
implicitHeight: Math.max(count.implicitHeight, titleText.implicitHeight)
|
||||
CustomText {
|
||||
id: count
|
||||
|
||||
CustomText {
|
||||
id: count
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: root.notifCount > 0 ? 0 : -width - titleText.anchors.leftMargin
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: DynamicColors.palette.m3outline
|
||||
font.family: "CaskaydiaCove NF"
|
||||
font.pointSize: 13
|
||||
font.weight: 500
|
||||
opacity: root.notifCount > 0 ? 1 : 0
|
||||
text: root.notifCount
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: root.notifCount > 0 ? 0 : -width - titleText.anchors.leftMargin
|
||||
opacity: root.notifCount > 0 ? 1 : 0
|
||||
Behavior on anchors.leftMargin {
|
||||
Anim {
|
||||
}
|
||||
}
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
text: root.notifCount
|
||||
color: DynamicColors.palette.m3outline
|
||||
font.pointSize: 13
|
||||
font.family: "CaskaydiaCove NF"
|
||||
font.weight: 500
|
||||
CustomText {
|
||||
id: titleText
|
||||
|
||||
Behavior on anchors.leftMargin {
|
||||
Anim {}
|
||||
}
|
||||
anchors.left: count.right
|
||||
anchors.leftMargin: 7
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: DynamicColors.palette.m3outline
|
||||
elide: Text.ElideRight
|
||||
font.family: "CaskaydiaCove NF"
|
||||
font.pointSize: 13
|
||||
font.weight: 500
|
||||
text: root.notifCount > 0 ? qsTr("notification%1").arg(root.notifCount === 1 ? "" : "s") : qsTr("Notifications")
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
ClippingRectangle {
|
||||
id: clipRect
|
||||
|
||||
CustomText {
|
||||
id: titleText
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: title.bottom
|
||||
anchors.topMargin: 10
|
||||
color: "transparent"
|
||||
radius: 6
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: count.right
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 7
|
||||
Loader {
|
||||
active: opacity > 0
|
||||
anchors.centerIn: parent
|
||||
opacity: root.notifCount > 0 ? 0 : 1
|
||||
|
||||
text: root.notifCount > 0 ? qsTr("notification%1").arg(root.notifCount === 1 ? "" : "s") : qsTr("Notifications")
|
||||
color: DynamicColors.palette.m3outline
|
||||
font.pointSize: 13
|
||||
font.family: "CaskaydiaCove NF"
|
||||
font.weight: 500
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
|
||||
ClippingRectangle {
|
||||
id: clipRect
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: title.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.topMargin: 10
|
||||
|
||||
radius: 6
|
||||
color: "transparent"
|
||||
|
||||
Loader {
|
||||
anchors.centerIn: parent
|
||||
active: opacity > 0
|
||||
opacity: root.notifCount > 0 ? 0 : 1
|
||||
|
||||
sourceComponent: ColumnLayout {
|
||||
spacing: 20
|
||||
|
||||
CustomText {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: qsTr("No Notifications")
|
||||
color: DynamicColors.palette.m3outlineVariant
|
||||
font.pointSize: 18
|
||||
font.family: "CaskaydiaCove NF"
|
||||
font.weight: 500
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sourceComponent: ColumnLayout {
|
||||
spacing: 20
|
||||
|
||||
CustomFlickable {
|
||||
id: view
|
||||
CustomText {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
color: DynamicColors.palette.m3outlineVariant
|
||||
font.family: "CaskaydiaCove NF"
|
||||
font.pointSize: 18
|
||||
font.weight: 500
|
||||
text: qsTr("No Notifications")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
CustomFlickable {
|
||||
id: view
|
||||
|
||||
flickableDirection: Flickable.VerticalFlick
|
||||
contentWidth: width
|
||||
contentHeight: notifList.implicitHeight
|
||||
anchors.fill: parent
|
||||
contentHeight: notifList.implicitHeight
|
||||
contentWidth: width
|
||||
flickableDirection: Flickable.VerticalFlick
|
||||
|
||||
CustomScrollBar.vertical: CustomScrollBar {
|
||||
flickable: view
|
||||
}
|
||||
CustomScrollBar.vertical: CustomScrollBar {
|
||||
flickable: view
|
||||
}
|
||||
|
||||
NotifDockList {
|
||||
id: notifList
|
||||
NotifDockList {
|
||||
id: notifList
|
||||
|
||||
props: root.props
|
||||
visibilities: root.visibilities
|
||||
container: view
|
||||
}
|
||||
}
|
||||
}
|
||||
container: view
|
||||
props: root.props
|
||||
visibilities: root.visibilities
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: clearTimer
|
||||
Timer {
|
||||
id: clearTimer
|
||||
|
||||
repeat: true
|
||||
interval: 50
|
||||
onTriggered: {
|
||||
let next = null;
|
||||
for (let i = 0; i < notifList.repeater.count; i++) {
|
||||
next = notifList.repeater.itemAt(i);
|
||||
if (!next?.closed)
|
||||
break;
|
||||
}
|
||||
if (next)
|
||||
next.closeAll();
|
||||
else
|
||||
stop();
|
||||
}
|
||||
}
|
||||
interval: 50
|
||||
repeat: true
|
||||
|
||||
Loader {
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: 8
|
||||
onTriggered: {
|
||||
let next = null;
|
||||
for (let i = 0; i < notifList.repeater.count; i++) {
|
||||
next = notifList.repeater.itemAt(i);
|
||||
if (!next?.closed)
|
||||
break;
|
||||
}
|
||||
if (next)
|
||||
next.closeAll();
|
||||
else
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
scale: root.notifCount > 0 ? 1 : 0.5
|
||||
opacity: root.notifCount > 0 ? 1 : 0
|
||||
active: opacity > 0
|
||||
Loader {
|
||||
active: opacity > 0
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: 8
|
||||
anchors.right: parent.right
|
||||
opacity: root.notifCount > 0 ? 1 : 0
|
||||
scale: root.notifCount > 0 ? 1 : 0.5
|
||||
|
||||
sourceComponent: IconButton {
|
||||
id: clearBtn
|
||||
|
||||
icon: "clear_all"
|
||||
radius: 8
|
||||
padding: 8
|
||||
font.pointSize: Math.round(18 * 1.2)
|
||||
onClicked: clearTimer.start()
|
||||
|
||||
Elevation {
|
||||
anchors.fill: parent
|
||||
radius: parent.radius
|
||||
z: -1
|
||||
level: clearBtn.stateLayer.containsMouse ? 4 : 3
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
Anim {
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
}
|
||||
}
|
||||
Behavior on scale {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sourceComponent: IconButton {
|
||||
id: clearBtn
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
}
|
||||
}
|
||||
}
|
||||
font.pointSize: Math.round(18 * 1.2)
|
||||
icon: "clear_all"
|
||||
padding: 8
|
||||
radius: 8
|
||||
|
||||
onClicked: clearTimer.start()
|
||||
|
||||
Elevation {
|
||||
anchors.fill: parent
|
||||
level: clearBtn.stateLayer.containsMouse ? 4 : 3
|
||||
radius: parent.radius
|
||||
z: -1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,162 +8,158 @@ import Quickshell
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
required property Props props
|
||||
required property Flickable container
|
||||
required property var visibilities
|
||||
required property Flickable container
|
||||
property bool flag
|
||||
required property Props props
|
||||
readonly property alias repeater: repeater
|
||||
readonly property int spacing: 8
|
||||
required property var visibilities
|
||||
|
||||
readonly property alias repeater: repeater
|
||||
readonly property int spacing: 8
|
||||
property bool flag
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
implicitHeight: {
|
||||
const item = repeater.itemAt(repeater.count - 1);
|
||||
return item ? item.y + item.implicitHeight : 0;
|
||||
}
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
implicitHeight: {
|
||||
const item = repeater.itemAt(repeater.count - 1);
|
||||
return item ? item.y + item.implicitHeight : 0;
|
||||
}
|
||||
Repeater {
|
||||
id: repeater
|
||||
|
||||
Repeater {
|
||||
id: repeater
|
||||
model: ScriptModel {
|
||||
values: {
|
||||
const map = new Map();
|
||||
for (const n of NotifServer.notClosed)
|
||||
map.set(n.appName, null);
|
||||
for (const n of NotifServer.list)
|
||||
map.set(n.appName, null);
|
||||
return [...map.keys()];
|
||||
}
|
||||
|
||||
model: ScriptModel {
|
||||
values: {
|
||||
const map = new Map();
|
||||
for (const n of NotifServer.notClosed)
|
||||
map.set(n.appName, null);
|
||||
for (const n of NotifServer.list)
|
||||
map.set(n.appName, null);
|
||||
return [...map.keys()];
|
||||
}
|
||||
onValuesChanged: root.flagChanged()
|
||||
}
|
||||
onValuesChanged: root.flagChanged()
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: notif
|
||||
MouseArea {
|
||||
id: notif
|
||||
|
||||
required property int index
|
||||
required property string modelData
|
||||
readonly property bool closed: notifInner.notifCount === 0
|
||||
required property int index
|
||||
required property string modelData
|
||||
readonly property alias nonAnimHeight: notifInner.nonAnimHeight
|
||||
property int startY
|
||||
|
||||
readonly property bool closed: notifInner.notifCount === 0
|
||||
readonly property alias nonAnimHeight: notifInner.nonAnimHeight
|
||||
property int startY
|
||||
|
||||
function closeAll(): void {
|
||||
for (const n of NotifServer.notClosed.filter(n => n.appName === modelData)) {
|
||||
n.close();
|
||||
function closeAll(): void {
|
||||
for (const n of NotifServer.notClosed.filter(n => n.appName === modelData)) {
|
||||
n.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
y: {
|
||||
root.flag; // Force update
|
||||
let y = 0;
|
||||
for (let i = 0; i < index; i++) {
|
||||
const item = repeater.itemAt(i);
|
||||
if (!item.closed)
|
||||
y += item.nonAnimHeight + root.spacing;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||
cursorShape: pressed ? Qt.ClosedHandCursor : undefined
|
||||
drag.axis: Drag.XAxis
|
||||
drag.target: this
|
||||
enabled: !closed
|
||||
hoverEnabled: true
|
||||
implicitHeight: notifInner.implicitHeight
|
||||
implicitWidth: root.width
|
||||
preventStealing: true
|
||||
y: {
|
||||
root.flag; // Force update
|
||||
let y = 0;
|
||||
for (let i = 0; i < index; i++) {
|
||||
const item = repeater.itemAt(i);
|
||||
if (!item.closed)
|
||||
y += item.nonAnimHeight + root.spacing;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
containmentMask: QtObject {
|
||||
function contains(p: point): bool {
|
||||
if (!root.container.contains(notif.mapToItem(root.container, p)))
|
||||
return false;
|
||||
return notifInner.contains(p);
|
||||
}
|
||||
}
|
||||
|
||||
implicitWidth: root.width
|
||||
implicitHeight: notifInner.implicitHeight
|
||||
|
||||
hoverEnabled: true
|
||||
cursorShape: pressed ? Qt.ClosedHandCursor : undefined
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||
preventStealing: true
|
||||
enabled: !closed
|
||||
|
||||
drag.target: this
|
||||
drag.axis: Drag.XAxis
|
||||
|
||||
onPressed: event => {
|
||||
startY = event.y;
|
||||
if (event.button === Qt.RightButton)
|
||||
notifInner.toggleExpand(!notifInner.expanded);
|
||||
else if (event.button === Qt.MiddleButton)
|
||||
closeAll();
|
||||
}
|
||||
onPositionChanged: event => {
|
||||
if (pressed) {
|
||||
const diffY = event.y - startY;
|
||||
if (Math.abs(diffY) > Config.notifs.expandThreshold)
|
||||
notifInner.toggleExpand(diffY > 0);
|
||||
}
|
||||
}
|
||||
onReleased: event => {
|
||||
if (Math.abs(x) < width * Config.notifs.clearThreshold)
|
||||
x = 0;
|
||||
else
|
||||
closeAll();
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
running: true
|
||||
|
||||
Anim {
|
||||
target: notif
|
||||
property: "opacity"
|
||||
from: 0
|
||||
to: 1
|
||||
}
|
||||
Anim {
|
||||
target: notif
|
||||
property: "scale"
|
||||
from: 0
|
||||
to: 1
|
||||
containmentMask: QtObject {
|
||||
function contains(p: point): bool {
|
||||
if (!root.container.contains(notif.mapToItem(root.container, p)))
|
||||
return false;
|
||||
return notifInner.contains(p);
|
||||
}
|
||||
}
|
||||
Behavior on x {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
running: notif.closed
|
||||
|
||||
Anim {
|
||||
target: notif
|
||||
property: "opacity"
|
||||
to: 0
|
||||
}
|
||||
Anim {
|
||||
target: notif
|
||||
property: "scale"
|
||||
to: 0.6
|
||||
}
|
||||
}
|
||||
|
||||
NotifGroup {
|
||||
id: notifInner
|
||||
|
||||
modelData: notif.modelData
|
||||
props: root.props
|
||||
container: root.container
|
||||
visibilities: root.visibilities
|
||||
}
|
||||
|
||||
Behavior on x {
|
||||
Anim {
|
||||
}
|
||||
}
|
||||
Behavior on y {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on y {
|
||||
Anim {
|
||||
onPositionChanged: event => {
|
||||
if (pressed) {
|
||||
const diffY = event.y - startY;
|
||||
if (Math.abs(diffY) > Config.notifs.expandThreshold)
|
||||
notifInner.toggleExpand(diffY > 0);
|
||||
}
|
||||
}
|
||||
onPressed: event => {
|
||||
startY = event.y;
|
||||
if (event.button === Qt.RightButton)
|
||||
notifInner.toggleExpand(!notifInner.expanded);
|
||||
else if (event.button === Qt.MiddleButton)
|
||||
closeAll();
|
||||
}
|
||||
onReleased: event => {
|
||||
if (Math.abs(x) < width * Config.notifs.clearThreshold)
|
||||
x = 0;
|
||||
else
|
||||
closeAll();
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
running: true
|
||||
|
||||
Anim {
|
||||
from: 0
|
||||
property: "opacity"
|
||||
target: notif
|
||||
to: 1
|
||||
}
|
||||
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
from: 0
|
||||
property: "scale"
|
||||
target: notif
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
running: notif.closed
|
||||
|
||||
Anim {
|
||||
property: "opacity"
|
||||
target: notif
|
||||
to: 0
|
||||
}
|
||||
|
||||
Anim {
|
||||
property: "scale"
|
||||
target: notif
|
||||
to: 0.6
|
||||
}
|
||||
}
|
||||
|
||||
NotifGroup {
|
||||
id: notifInner
|
||||
|
||||
container: root.container
|
||||
modelData: notif.modelData
|
||||
props: root.props
|
||||
visibilities: root.visibilities
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,229 +11,224 @@ import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
CustomRect {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
required property string modelData
|
||||
required property Props props
|
||||
required property Flickable container
|
||||
required property var visibilities
|
||||
readonly property string appIcon: notifs.find(n => !n.closed && n.appIcon.length > 0)?.appIcon ?? ""
|
||||
required property Flickable container
|
||||
readonly property bool expanded: props.expandedNotifs.includes(modelData)
|
||||
readonly property string image: notifs.find(n => !n.closed && n.image.length > 0)?.image ?? ""
|
||||
required property string modelData
|
||||
readonly property int nonAnimHeight: {
|
||||
const headerHeight = header.implicitHeight + (root.expanded ? Math.round(7 / 2) : 0);
|
||||
const columnHeight = headerHeight + notifList.nonAnimHeight + column.Layout.topMargin + column.Layout.bottomMargin;
|
||||
return Math.round(Math.max(Config.notifs.sizes.image, columnHeight) + 10 * 2);
|
||||
}
|
||||
readonly property int notifCount: notifs.reduce((acc, n) => n.closed ? acc : acc + 1, 0)
|
||||
readonly property list<var> notifs: NotifServer.list.filter(n => n.appName === modelData)
|
||||
required property Props props
|
||||
readonly property int urgency: notifs.some(n => !n.closed && n.urgency === NotificationUrgency.Critical) ? NotificationUrgency.Critical : notifs.some(n => n.urgency === NotificationUrgency.Normal) ? NotificationUrgency.Normal : NotificationUrgency.Low
|
||||
required property var visibilities
|
||||
|
||||
readonly property list<var> notifs: NotifServer.list.filter(n => n.appName === modelData)
|
||||
readonly property int notifCount: notifs.reduce((acc, n) => n.closed ? acc : acc + 1, 0)
|
||||
readonly property string image: notifs.find(n => !n.closed && n.image.length > 0)?.image ?? ""
|
||||
readonly property string appIcon: notifs.find(n => !n.closed && n.appIcon.length > 0)?.appIcon ?? ""
|
||||
readonly property int urgency: notifs.some(n => !n.closed && n.urgency === NotificationUrgency.Critical) ? NotificationUrgency.Critical : notifs.some(n => n.urgency === NotificationUrgency.Normal) ? NotificationUrgency.Normal : NotificationUrgency.Low
|
||||
function toggleExpand(expand: bool): void {
|
||||
if (expand) {
|
||||
if (!expanded)
|
||||
props.expandedNotifs.push(modelData);
|
||||
} else if (expanded) {
|
||||
props.expandedNotifs.splice(props.expandedNotifs.indexOf(modelData), 1);
|
||||
}
|
||||
}
|
||||
|
||||
readonly property int nonAnimHeight: {
|
||||
const headerHeight = header.implicitHeight + (root.expanded ? Math.round(7 / 2) : 0);
|
||||
const columnHeight = headerHeight + notifList.nonAnimHeight + column.Layout.topMargin + column.Layout.bottomMargin;
|
||||
return Math.round(Math.max(Config.notifs.sizes.image, columnHeight) + 10 * 2);
|
||||
}
|
||||
readonly property bool expanded: props.expandedNotifs.includes(modelData)
|
||||
anchors.left: parent?.left
|
||||
anchors.right: parent?.right
|
||||
clip: true
|
||||
color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainer, 2)
|
||||
implicitHeight: content.implicitHeight + 10 * 2
|
||||
radius: 8
|
||||
|
||||
function toggleExpand(expand: bool): void {
|
||||
if (expand) {
|
||||
if (!expanded)
|
||||
props.expandedNotifs.push(modelData);
|
||||
} else if (expanded) {
|
||||
props.expandedNotifs.splice(props.expandedNotifs.indexOf(modelData), 1);
|
||||
}
|
||||
}
|
||||
Component.onDestruction: {
|
||||
if (notifCount === 0 && expanded)
|
||||
props.expandedNotifs.splice(props.expandedNotifs.indexOf(modelData), 1);
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
if (notifCount === 0 && expanded)
|
||||
props.expandedNotifs.splice(props.expandedNotifs.indexOf(modelData), 1);
|
||||
}
|
||||
RowLayout {
|
||||
id: content
|
||||
|
||||
anchors.left: parent?.left
|
||||
anchors.right: parent?.right
|
||||
implicitHeight: content.implicitHeight + 10 * 2
|
||||
anchors.left: parent.left
|
||||
anchors.margins: 10
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
spacing: 10
|
||||
|
||||
clip: true
|
||||
radius: 8
|
||||
color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainer, 2)
|
||||
Item {
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
implicitHeight: Config.notifs.sizes.image
|
||||
implicitWidth: Config.notifs.sizes.image
|
||||
|
||||
RowLayout {
|
||||
id: content
|
||||
Component {
|
||||
id: imageComp
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.margins: 10
|
||||
Image {
|
||||
asynchronous: true
|
||||
cache: false
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
height: Config.notifs.sizes.image
|
||||
source: Qt.resolvedUrl(root.image)
|
||||
width: Config.notifs.sizes.image
|
||||
}
|
||||
}
|
||||
|
||||
spacing: 10
|
||||
Component {
|
||||
id: appIconComp
|
||||
|
||||
Item {
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
implicitWidth: Config.notifs.sizes.image
|
||||
implicitHeight: Config.notifs.sizes.image
|
||||
CustomIcon {
|
||||
implicitSize: Math.round(Config.notifs.sizes.image * 0.6)
|
||||
layer.enabled: root.appIcon.endsWith("symbolic")
|
||||
source: Quickshell.iconPath(root.appIcon)
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: imageComp
|
||||
Component {
|
||||
id: materialIconComp
|
||||
|
||||
Image {
|
||||
source: Qt.resolvedUrl(root.image)
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
cache: false
|
||||
asynchronous: true
|
||||
width: Config.notifs.sizes.image
|
||||
height: Config.notifs.sizes.image
|
||||
}
|
||||
}
|
||||
MaterialIcon {
|
||||
color: root.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3onError : root.urgency === NotificationUrgency.Low ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3onSecondaryContainer
|
||||
font.pointSize: 18
|
||||
text: Icons.getNotifIcon(root.notifs[0]?.summary, root.urgency)
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: appIconComp
|
||||
CustomClippingRect {
|
||||
anchors.fill: parent
|
||||
color: root.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3error : root.urgency === NotificationUrgency.Low ? DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 3) : DynamicColors.palette.m3secondaryContainer
|
||||
radius: 1000
|
||||
|
||||
CustomIcon {
|
||||
implicitSize: Math.round(Config.notifs.sizes.image * 0.6)
|
||||
source: Quickshell.iconPath(root.appIcon)
|
||||
layer.enabled: root.appIcon.endsWith("symbolic")
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
anchors.centerIn: parent
|
||||
sourceComponent: root.image ? imageComp : root.appIcon ? appIconComp : materialIconComp
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: materialIconComp
|
||||
Loader {
|
||||
active: root.appIcon && root.image
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
|
||||
MaterialIcon {
|
||||
text: Icons.getNotifIcon(root.notifs[0]?.summary, root.urgency)
|
||||
color: root.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3onError : root.urgency === NotificationUrgency.Low ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3onSecondaryContainer
|
||||
font.pointSize: 18
|
||||
}
|
||||
}
|
||||
sourceComponent: CustomRect {
|
||||
color: root.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3error : root.urgency === NotificationUrgency.Low ? DynamicColors.palette.m3surfaceContainerHigh : DynamicColors.palette.m3secondaryContainer
|
||||
implicitHeight: Config.notifs.sizes.badge
|
||||
implicitWidth: Config.notifs.sizes.badge
|
||||
radius: 1000
|
||||
|
||||
CustomClippingRect {
|
||||
anchors.fill: parent
|
||||
color: root.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3error : root.urgency === NotificationUrgency.Low ? DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 3) : DynamicColors.palette.m3secondaryContainer
|
||||
radius: 1000
|
||||
CustomIcon {
|
||||
anchors.centerIn: parent
|
||||
implicitSize: Math.round(Config.notifs.sizes.badge * 0.6)
|
||||
layer.enabled: root.appIcon.endsWith("symbolic")
|
||||
source: Quickshell.iconPath(root.appIcon)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
anchors.centerIn: parent
|
||||
sourceComponent: root.image ? imageComp : root.appIcon ? appIconComp : materialIconComp
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
id: column
|
||||
|
||||
Loader {
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
active: root.appIcon && root.image
|
||||
Layout.bottomMargin: -10 / 2
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: -10
|
||||
spacing: 0
|
||||
|
||||
sourceComponent: CustomRect {
|
||||
implicitWidth: Config.notifs.sizes.badge
|
||||
implicitHeight: Config.notifs.sizes.badge
|
||||
RowLayout {
|
||||
id: header
|
||||
|
||||
color: root.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3error : root.urgency === NotificationUrgency.Low ? DynamicColors.palette.m3surfaceContainerHigh : DynamicColors.palette.m3secondaryContainer
|
||||
radius: 1000
|
||||
Layout.bottomMargin: root.expanded ? Math.round(7 / 2) : 0
|
||||
Layout.fillWidth: true
|
||||
spacing: 5
|
||||
|
||||
CustomIcon {
|
||||
anchors.centerIn: parent
|
||||
implicitSize: Math.round(Config.notifs.sizes.badge * 0.6)
|
||||
source: Quickshell.iconPath(root.appIcon)
|
||||
layer.enabled: root.appIcon.endsWith("symbolic")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Behavior on Layout.bottomMargin {
|
||||
Anim {
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: column
|
||||
CustomText {
|
||||
Layout.fillWidth: true
|
||||
color: DynamicColors.palette.m3onSurfaceVariant
|
||||
elide: Text.ElideRight
|
||||
font.pointSize: 11
|
||||
text: root.modelData
|
||||
}
|
||||
|
||||
Layout.topMargin: -10
|
||||
Layout.bottomMargin: -10 / 2
|
||||
Layout.fillWidth: true
|
||||
spacing: 0
|
||||
CustomText {
|
||||
animate: true
|
||||
color: DynamicColors.palette.m3outline
|
||||
font.pointSize: 11
|
||||
text: root.notifs.find(n => !n.closed)?.timeStr ?? ""
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: header
|
||||
CustomRect {
|
||||
color: root.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3error : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 3)
|
||||
implicitHeight: groupCount.implicitHeight + 10
|
||||
implicitWidth: expandBtn.implicitWidth + 7 * 2
|
||||
radius: 1000
|
||||
|
||||
Layout.bottomMargin: root.expanded ? Math.round(7 / 2) : 0
|
||||
Layout.fillWidth: true
|
||||
spacing: 5
|
||||
StateLayer {
|
||||
function onClicked(): void {
|
||||
root.toggleExpand(!root.expanded);
|
||||
}
|
||||
|
||||
CustomText {
|
||||
Layout.fillWidth: true
|
||||
text: root.modelData
|
||||
color: DynamicColors.palette.m3onSurfaceVariant
|
||||
font.pointSize: 11
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
color: root.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3onError : DynamicColors.palette.m3onSurface
|
||||
}
|
||||
|
||||
CustomText {
|
||||
animate: true
|
||||
text: root.notifs.find(n => !n.closed)?.timeStr ?? ""
|
||||
color: DynamicColors.palette.m3outline
|
||||
font.pointSize: 11
|
||||
}
|
||||
RowLayout {
|
||||
id: expandBtn
|
||||
|
||||
CustomRect {
|
||||
implicitWidth: expandBtn.implicitWidth + 7 * 2
|
||||
implicitHeight: groupCount.implicitHeight + 10
|
||||
anchors.centerIn: parent
|
||||
spacing: 7 / 2
|
||||
|
||||
color: root.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3error : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 3)
|
||||
radius: 1000
|
||||
CustomText {
|
||||
id: groupCount
|
||||
|
||||
StateLayer {
|
||||
color: root.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3onError : DynamicColors.palette.m3onSurface
|
||||
Layout.leftMargin: 10 / 2
|
||||
animate: true
|
||||
color: root.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3onError : DynamicColors.palette.m3onSurface
|
||||
font.pointSize: 11
|
||||
text: root.notifCount
|
||||
}
|
||||
|
||||
function onClicked(): void {
|
||||
root.toggleExpand(!root.expanded);
|
||||
}
|
||||
}
|
||||
MaterialIcon {
|
||||
Layout.rightMargin: -10 / 2
|
||||
Layout.topMargin: root.expanded ? -Math.floor(7 / 2) : 0
|
||||
color: root.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3onError : DynamicColors.palette.m3onSurface
|
||||
rotation: root.expanded ? 180 : 0
|
||||
text: "expand_more"
|
||||
|
||||
RowLayout {
|
||||
id: expandBtn
|
||||
|
||||
anchors.centerIn: parent
|
||||
spacing: 7 / 2
|
||||
|
||||
CustomText {
|
||||
id: groupCount
|
||||
|
||||
Layout.leftMargin: 10 / 2
|
||||
animate: true
|
||||
text: root.notifCount
|
||||
color: root.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3onError : DynamicColors.palette.m3onSurface
|
||||
font.pointSize: 11
|
||||
}
|
||||
|
||||
MaterialIcon {
|
||||
Layout.rightMargin: -10 / 2
|
||||
text: "expand_more"
|
||||
color: root.urgency === NotificationUrgency.Critical ? DynamicColors.palette.m3onError : DynamicColors.palette.m3onSurface
|
||||
rotation: root.expanded ? 180 : 0
|
||||
Layout.topMargin: root.expanded ? -Math.floor(7 / 2) : 0
|
||||
|
||||
Behavior on rotation {
|
||||
Anim {
|
||||
Behavior on Layout.topMargin {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on Layout.topMargin {
|
||||
Anim {
|
||||
}
|
||||
}
|
||||
Behavior on rotation {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on Layout.bottomMargin {
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
NotifGroupList {
|
||||
id: notifList
|
||||
|
||||
NotifGroupList {
|
||||
id: notifList
|
||||
container: root.container
|
||||
expanded: root.expanded
|
||||
notifs: root.notifs
|
||||
props: root.props
|
||||
visibilities: root.visibilities
|
||||
|
||||
props: root.props
|
||||
notifs: root.notifs
|
||||
expanded: root.expanded
|
||||
container: root.container
|
||||
visibilities: root.visibilities
|
||||
onRequestToggleExpand: expand => root.toggleExpand(expand)
|
||||
}
|
||||
}
|
||||
}
|
||||
onRequestToggleExpand: expand => root.toggleExpand(expand)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,206 +9,201 @@ import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
Item {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
required property Props props
|
||||
required property list<var> notifs
|
||||
required property bool expanded
|
||||
required property Flickable container
|
||||
required property var visibilities
|
||||
required property Flickable container
|
||||
required property bool expanded
|
||||
property bool flag
|
||||
readonly property real nonAnimHeight: {
|
||||
let h = -root.spacing;
|
||||
for (let i = 0; i < repeater.count; i++) {
|
||||
const item = repeater.itemAt(i);
|
||||
if (!item.modelData.closed && !item.previewHidden)
|
||||
h += item.nonAnimHeight + root.spacing;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
required property list<var> notifs
|
||||
required property Props props
|
||||
property bool showAllNotifs
|
||||
readonly property int spacing: Math.round(7 / 2)
|
||||
required property var visibilities
|
||||
|
||||
readonly property real nonAnimHeight: {
|
||||
let h = -root.spacing;
|
||||
for (let i = 0; i < repeater.count; i++) {
|
||||
const item = repeater.itemAt(i);
|
||||
if (!item.modelData.closed && !item.previewHidden)
|
||||
h += item.nonAnimHeight + root.spacing;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
signal requestToggleExpand(expand: bool)
|
||||
|
||||
readonly property int spacing: Math.round(7 / 2)
|
||||
property bool showAllNotifs
|
||||
property bool flag
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: nonAnimHeight
|
||||
|
||||
signal requestToggleExpand(expand: bool)
|
||||
|
||||
onExpandedChanged: {
|
||||
if (expanded) {
|
||||
clearTimer.stop();
|
||||
showAllNotifs = true;
|
||||
} else {
|
||||
clearTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: nonAnimHeight
|
||||
|
||||
Timer {
|
||||
id: clearTimer
|
||||
|
||||
interval: MaterialEasing.standardTime
|
||||
onTriggered: root.showAllNotifs = false
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: repeater
|
||||
|
||||
model: ScriptModel {
|
||||
values: root.showAllNotifs ? root.notifs : root.notifs.slice(0, Config.notifs.groupPreviewNum + 1)
|
||||
onValuesChanged: root.flagChanged()
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: notif
|
||||
|
||||
required property int index
|
||||
required property NotifServer.Notif modelData
|
||||
|
||||
readonly property alias nonAnimHeight: notifInner.nonAnimHeight
|
||||
readonly property bool previewHidden: {
|
||||
if (root.expanded)
|
||||
return false;
|
||||
|
||||
let extraHidden = 0;
|
||||
for (let i = 0; i < index; i++)
|
||||
if (root.notifs[i].closed)
|
||||
extraHidden++;
|
||||
|
||||
return index >= Config.notifs.groupPreviewNum + extraHidden;
|
||||
}
|
||||
property int startY
|
||||
|
||||
y: {
|
||||
root.flag; // Force update
|
||||
let y = 0;
|
||||
for (let i = 0; i < index; i++) {
|
||||
const item = repeater.itemAt(i);
|
||||
if (!item.modelData.closed && !item.previewHidden)
|
||||
y += item.nonAnimHeight + root.spacing;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
containmentMask: QtObject {
|
||||
function contains(p: point): bool {
|
||||
if (!root.container.contains(notif.mapToItem(root.container, p)))
|
||||
return false;
|
||||
return notifInner.contains(p);
|
||||
}
|
||||
}
|
||||
|
||||
opacity: previewHidden ? 0 : 1
|
||||
scale: previewHidden ? 0.7 : 1
|
||||
|
||||
implicitWidth: root.width
|
||||
implicitHeight: notifInner.implicitHeight
|
||||
|
||||
hoverEnabled: true
|
||||
cursorShape: notifInner.body?.hoveredLink ? Qt.PointingHandCursor : pressed ? Qt.ClosedHandCursor : undefined
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||
preventStealing: !root.expanded
|
||||
enabled: !modelData.closed
|
||||
|
||||
drag.target: this
|
||||
drag.axis: Drag.XAxis
|
||||
|
||||
onPressed: event => {
|
||||
startY = event.y;
|
||||
if (event.button === Qt.RightButton)
|
||||
root.requestToggleExpand(!root.expanded);
|
||||
else if (event.button === Qt.MiddleButton)
|
||||
modelData.close();
|
||||
}
|
||||
onPositionChanged: event => {
|
||||
if (pressed && !root.expanded) {
|
||||
const diffY = event.y - startY;
|
||||
if (Math.abs(diffY) > Config.notifs.expandThreshold)
|
||||
root.requestToggleExpand(diffY > 0);
|
||||
}
|
||||
}
|
||||
onReleased: event => {
|
||||
if (Math.abs(x) < width * Config.notifs.clearThreshold)
|
||||
x = 0;
|
||||
else
|
||||
modelData.close();
|
||||
}
|
||||
|
||||
Component.onCompleted: modelData.lock(this)
|
||||
Component.onDestruction: modelData.unlock(this)
|
||||
|
||||
ParallelAnimation {
|
||||
Component.onCompleted: running = !notif.previewHidden
|
||||
|
||||
Anim {
|
||||
target: notif
|
||||
property: "opacity"
|
||||
from: 0
|
||||
to: 1
|
||||
}
|
||||
Anim {
|
||||
target: notif
|
||||
property: "scale"
|
||||
from: 0.7
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
running: notif.modelData.closed
|
||||
onFinished: notif.modelData.unlock(notif)
|
||||
|
||||
Anim {
|
||||
target: notif
|
||||
property: "opacity"
|
||||
to: 0
|
||||
}
|
||||
Anim {
|
||||
target: notif
|
||||
property: "x"
|
||||
to: notif.x >= 0 ? notif.width : -notif.width
|
||||
}
|
||||
}
|
||||
|
||||
Notif {
|
||||
id: notifInner
|
||||
|
||||
anchors.fill: parent
|
||||
modelData: notif.modelData
|
||||
props: root.props
|
||||
expanded: root.expanded
|
||||
visibilities: root.visibilities
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
Anim {}
|
||||
}
|
||||
|
||||
Behavior on x {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on y {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on implicitHeight {
|
||||
Anim {
|
||||
Behavior on implicitHeight {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onExpandedChanged: {
|
||||
if (expanded) {
|
||||
clearTimer.stop();
|
||||
showAllNotifs = true;
|
||||
} else {
|
||||
clearTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: clearTimer
|
||||
|
||||
interval: MaterialEasing.standardTime
|
||||
|
||||
onTriggered: root.showAllNotifs = false
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: repeater
|
||||
|
||||
model: ScriptModel {
|
||||
values: root.showAllNotifs ? root.notifs : root.notifs.slice(0, Config.notifs.groupPreviewNum + 1)
|
||||
|
||||
onValuesChanged: root.flagChanged()
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: notif
|
||||
|
||||
required property int index
|
||||
required property NotifServer.Notif modelData
|
||||
readonly property alias nonAnimHeight: notifInner.nonAnimHeight
|
||||
readonly property bool previewHidden: {
|
||||
if (root.expanded)
|
||||
return false;
|
||||
|
||||
let extraHidden = 0;
|
||||
for (let i = 0; i < index; i++)
|
||||
if (root.notifs[i].closed)
|
||||
extraHidden++;
|
||||
|
||||
return index >= Config.notifs.groupPreviewNum + extraHidden;
|
||||
}
|
||||
property int startY
|
||||
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||
cursorShape: notifInner.body?.hoveredLink ? Qt.PointingHandCursor : pressed ? Qt.ClosedHandCursor : undefined
|
||||
drag.axis: Drag.XAxis
|
||||
drag.target: this
|
||||
enabled: !modelData.closed
|
||||
hoverEnabled: true
|
||||
implicitHeight: notifInner.implicitHeight
|
||||
implicitWidth: root.width
|
||||
opacity: previewHidden ? 0 : 1
|
||||
preventStealing: !root.expanded
|
||||
scale: previewHidden ? 0.7 : 1
|
||||
y: {
|
||||
root.flag; // Force update
|
||||
let y = 0;
|
||||
for (let i = 0; i < index; i++) {
|
||||
const item = repeater.itemAt(i);
|
||||
if (!item.modelData.closed && !item.previewHidden)
|
||||
y += item.nonAnimHeight + root.spacing;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
containmentMask: QtObject {
|
||||
function contains(p: point): bool {
|
||||
if (!root.container.contains(notif.mapToItem(root.container, p)))
|
||||
return false;
|
||||
return notifInner.contains(p);
|
||||
}
|
||||
}
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
}
|
||||
}
|
||||
Behavior on scale {
|
||||
Anim {
|
||||
}
|
||||
}
|
||||
Behavior on x {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
Behavior on y {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: modelData.lock(this)
|
||||
Component.onDestruction: modelData.unlock(this)
|
||||
onPositionChanged: event => {
|
||||
if (pressed && !root.expanded) {
|
||||
const diffY = event.y - startY;
|
||||
if (Math.abs(diffY) > Config.notifs.expandThreshold)
|
||||
root.requestToggleExpand(diffY > 0);
|
||||
}
|
||||
}
|
||||
onPressed: event => {
|
||||
startY = event.y;
|
||||
if (event.button === Qt.RightButton)
|
||||
root.requestToggleExpand(!root.expanded);
|
||||
else if (event.button === Qt.MiddleButton)
|
||||
modelData.close();
|
||||
}
|
||||
onReleased: event => {
|
||||
if (Math.abs(x) < width * Config.notifs.clearThreshold)
|
||||
x = 0;
|
||||
else
|
||||
modelData.close();
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
Component.onCompleted: running = !notif.previewHidden
|
||||
|
||||
Anim {
|
||||
from: 0
|
||||
property: "opacity"
|
||||
target: notif
|
||||
to: 1
|
||||
}
|
||||
|
||||
Anim {
|
||||
from: 0.7
|
||||
property: "scale"
|
||||
target: notif
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
running: notif.modelData.closed
|
||||
|
||||
onFinished: notif.modelData.unlock(notif)
|
||||
|
||||
Anim {
|
||||
property: "opacity"
|
||||
target: notif
|
||||
to: 0
|
||||
}
|
||||
|
||||
Anim {
|
||||
property: "x"
|
||||
target: notif
|
||||
to: notif.x >= 0 ? notif.width : -notif.width
|
||||
}
|
||||
}
|
||||
|
||||
Notif {
|
||||
id: notifInner
|
||||
|
||||
anchors.fill: parent
|
||||
expanded: root.expanded
|
||||
modelData: notif.modelData
|
||||
props: root.props
|
||||
visibilities: root.visibilities
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Quickshell
|
||||
|
||||
PersistentProperties {
|
||||
property list<string> expandedNotifs: []
|
||||
property list<string> expandedNotifs: []
|
||||
|
||||
reloadableId: "sidebar"
|
||||
reloadableId: "sidebar"
|
||||
}
|
||||
|
||||
@@ -4,51 +4,57 @@ import QtQuick
|
||||
import QtQuick.Shapes
|
||||
|
||||
ShapePath {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
required property Wrapper wrapper
|
||||
required property var sidebar
|
||||
readonly property real rounding: 8
|
||||
readonly property bool flatten: wrapper.height < rounding * 2
|
||||
readonly property real roundingY: flatten ? wrapper.height / 2 : rounding
|
||||
readonly property bool flatten: wrapper.height < rounding * 2
|
||||
readonly property real rounding: 8
|
||||
readonly property real roundingY: flatten ? wrapper.height / 2 : rounding
|
||||
required property var sidebar
|
||||
required property Wrapper wrapper
|
||||
|
||||
strokeWidth: -1
|
||||
fillColor: DynamicColors.palette.m3surface
|
||||
fillColor: DynamicColors.palette.m3surface
|
||||
strokeWidth: -1
|
||||
|
||||
PathLine {
|
||||
relativeX: -(root.wrapper.width + root.rounding)
|
||||
relativeY: 0
|
||||
}
|
||||
PathArc {
|
||||
relativeX: root.rounding
|
||||
relativeY: -root.roundingY
|
||||
radiusX: root.rounding
|
||||
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||
direction: PathArc.Counterclockwise
|
||||
}
|
||||
PathLine {
|
||||
relativeX: 0
|
||||
relativeY: -(root.wrapper.height - root.roundingY * 2)
|
||||
}
|
||||
PathArc {
|
||||
relativeX: root.sidebar.utilsRoundingX
|
||||
relativeY: -root.roundingY
|
||||
radiusX: root.sidebar.utilsRoundingX
|
||||
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||
}
|
||||
PathLine {
|
||||
relativeX: root.wrapper.height > 0 ? root.wrapper.width - root.rounding - root.sidebar.utilsRoundingX : root.wrapper.width
|
||||
relativeY: 0
|
||||
}
|
||||
PathArc {
|
||||
relativeX: root.rounding
|
||||
relativeY: -root.rounding
|
||||
radiusX: root.rounding
|
||||
radiusY: root.rounding
|
||||
direction: PathArc.Counterclockwise
|
||||
}
|
||||
Behavior on fillColor {
|
||||
CAnim {
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on fillColor {
|
||||
CAnim {}
|
||||
}
|
||||
PathLine {
|
||||
relativeX: -(root.wrapper.width + root.rounding)
|
||||
relativeY: 0
|
||||
}
|
||||
|
||||
PathArc {
|
||||
direction: PathArc.Counterclockwise
|
||||
radiusX: root.rounding
|
||||
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||
relativeX: root.rounding
|
||||
relativeY: -root.roundingY
|
||||
}
|
||||
|
||||
PathLine {
|
||||
relativeX: 0
|
||||
relativeY: -(root.wrapper.height - root.roundingY * 2)
|
||||
}
|
||||
|
||||
PathArc {
|
||||
radiusX: root.sidebar.utilsRoundingX
|
||||
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||
relativeX: root.sidebar.utilsRoundingX
|
||||
relativeY: -root.roundingY
|
||||
}
|
||||
|
||||
PathLine {
|
||||
relativeX: root.wrapper.height > 0 ? root.wrapper.width - root.rounding - root.sidebar.utilsRoundingX : root.wrapper.width
|
||||
relativeY: 0
|
||||
}
|
||||
|
||||
PathArc {
|
||||
direction: PathArc.Counterclockwise
|
||||
radiusX: root.rounding
|
||||
radiusY: root.rounding
|
||||
relativeX: root.rounding
|
||||
relativeY: -root.rounding
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,75 +8,80 @@ import qs.Modules
|
||||
import qs.Daemons
|
||||
|
||||
CustomRect {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
required property var visibilities
|
||||
required property Item popouts
|
||||
required property Item popouts
|
||||
required property var visibilities
|
||||
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: layout.implicitHeight + 18 * 2
|
||||
Layout.fillWidth: true
|
||||
color: DynamicColors.tPalette.m3surfaceContainer
|
||||
implicitHeight: layout.implicitHeight + 18 * 2
|
||||
radius: 8
|
||||
|
||||
radius: 8
|
||||
color: DynamicColors.tPalette.m3surfaceContainer
|
||||
ColumnLayout {
|
||||
id: layout
|
||||
|
||||
ColumnLayout {
|
||||
id: layout
|
||||
anchors.fill: parent
|
||||
anchors.margins: 18
|
||||
spacing: 10
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: 18
|
||||
spacing: 10
|
||||
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
spacing: 7
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
spacing: 7
|
||||
|
||||
Toggle {
|
||||
visible: QSNetwork.Networking.devices.values.length > 0
|
||||
icon: Network.wifiEnabled ? "wifi" : "wifi_off"
|
||||
checked: Network.wifiEnabled
|
||||
icon: Network.wifiEnabled ? "wifi" : "wifi_off"
|
||||
visible: QSNetwork.Networking.devices.values.length > 0
|
||||
|
||||
onClicked: Network.toggleWifi()
|
||||
}
|
||||
|
||||
Toggle {
|
||||
Toggle {
|
||||
id: toggle
|
||||
icon: NotifServer.dnd ? "notifications_off" : "notifications"
|
||||
checked: !NotifServer.dnd
|
||||
onClicked: NotifServer.dnd = !NotifServer.dnd
|
||||
}
|
||||
|
||||
checked: !NotifServer.dnd
|
||||
icon: NotifServer.dnd ? "notifications_off" : "notifications"
|
||||
|
||||
onClicked: NotifServer.dnd = !NotifServer.dnd
|
||||
}
|
||||
|
||||
Toggle {
|
||||
icon: Audio.sourceMuted ? "mic_off" : "mic"
|
||||
checked: !Audio.sourceMuted
|
||||
icon: Audio.sourceMuted ? "mic_off" : "mic"
|
||||
|
||||
onClicked: {
|
||||
const audio = Audio.source?.audio;
|
||||
if ( audio )
|
||||
if (audio)
|
||||
audio.muted = !audio.muted;
|
||||
}
|
||||
}
|
||||
|
||||
Toggle {
|
||||
icon: Audio.muted ? "volume_off" : "volume_up"
|
||||
checked: !Audio.muted
|
||||
icon: Audio.muted ? "volume_off" : "volume_up"
|
||||
|
||||
onClicked: {
|
||||
const audio = Audio.sink?.audio;
|
||||
if ( audio )
|
||||
if (audio)
|
||||
audio.muted = !audio.muted;
|
||||
}
|
||||
}
|
||||
|
||||
Toggle {
|
||||
visible: Bluetooth.defaultAdapter ?? false
|
||||
icon: Bluetooth.defaultAdapter?.enabled ? "bluetooth" : "bluetooth_disabled"
|
||||
checked: Bluetooth.defaultAdapter?.enabled ?? false
|
||||
icon: Bluetooth.defaultAdapter?.enabled ? "bluetooth" : "bluetooth_disabled"
|
||||
visible: Bluetooth.defaultAdapter ?? false
|
||||
|
||||
onClicked: {
|
||||
// console.log(Bluetooth.defaultAdapter)
|
||||
const adapter = Bluetooth.defaultAdapter
|
||||
if ( adapter )
|
||||
const adapter = Bluetooth.defaultAdapter;
|
||||
if (adapter)
|
||||
adapter.enabled = !adapter.enabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CustomShortcut {
|
||||
name: "toggle-dnd"
|
||||
@@ -86,20 +91,20 @@ CustomRect {
|
||||
}
|
||||
}
|
||||
|
||||
component Toggle: IconButton {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: implicitWidth + (stateLayer.pressed ? 18 : internalChecked ? 7 : 0)
|
||||
radius: stateLayer.pressed ? 6 / 2 : internalChecked ? 6 : 8
|
||||
inactiveColour: DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, 2)
|
||||
toggle: true
|
||||
radiusAnim.duration: MaterialEasing.expressiveEffectsTime
|
||||
radiusAnim.easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
component Toggle: IconButton {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: implicitWidth + (stateLayer.pressed ? 18 : internalChecked ? 7 : 0)
|
||||
inactiveColour: DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, 2)
|
||||
radius: stateLayer.pressed ? 6 / 2 : internalChecked ? 6 : 8
|
||||
radiusAnim.duration: MaterialEasing.expressiveEffectsTime
|
||||
radiusAnim.easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
toggle: true
|
||||
|
||||
Behavior on Layout.preferredWidth {
|
||||
Anim {
|
||||
Behavior on Layout.preferredWidth {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,26 +4,27 @@ import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
Item {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
required property var props
|
||||
required property var visibilities
|
||||
required property Item popouts
|
||||
required property Item popouts
|
||||
required property var props
|
||||
required property var visibilities
|
||||
|
||||
implicitWidth: layout.implicitWidth
|
||||
implicitHeight: layout.implicitHeight
|
||||
implicitHeight: layout.implicitHeight
|
||||
implicitWidth: layout.implicitWidth
|
||||
|
||||
ColumnLayout {
|
||||
id: layout
|
||||
ColumnLayout {
|
||||
id: layout
|
||||
|
||||
anchors.fill: parent
|
||||
spacing: 8
|
||||
anchors.fill: parent
|
||||
spacing: 8
|
||||
|
||||
IdleInhibit {}
|
||||
IdleInhibit {
|
||||
}
|
||||
|
||||
Toggles {
|
||||
visibilities: root.visibilities
|
||||
popouts: root.popouts
|
||||
}
|
||||
}
|
||||
Toggles {
|
||||
popouts: root.popouts
|
||||
visibilities: root.visibilities
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,120 +5,115 @@ import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
CustomRect {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: layout.implicitHeight + (IdleInhibitor.enabled ? activeChip.implicitHeight + activeChip.anchors.topMargin : 0) + 18 * 2
|
||||
Layout.fillWidth: true
|
||||
clip: true
|
||||
color: DynamicColors.tPalette.m3surfaceContainer
|
||||
implicitHeight: layout.implicitHeight + (IdleInhibitor.enabled ? activeChip.implicitHeight + activeChip.anchors.topMargin : 0) + 18 * 2
|
||||
radius: 8
|
||||
|
||||
radius: 8
|
||||
color: DynamicColors.tPalette.m3surfaceContainer
|
||||
clip: true
|
||||
|
||||
RowLayout {
|
||||
id: layout
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.margins: 18
|
||||
spacing: 10
|
||||
|
||||
CustomRect {
|
||||
implicitWidth: implicitHeight
|
||||
implicitHeight: icon.implicitHeight + 7 * 2
|
||||
|
||||
radius: 1000
|
||||
color: IdleInhibitor.enabled ? DynamicColors.palette.m3secondary : DynamicColors.palette.m3secondaryContainer
|
||||
|
||||
MaterialIcon {
|
||||
id: icon
|
||||
|
||||
anchors.centerIn: parent
|
||||
text: "coffee"
|
||||
color: IdleInhibitor.enabled ? DynamicColors.palette.m3onSecondary : DynamicColors.palette.m3onSecondaryContainer
|
||||
font.pointSize: 18
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 0
|
||||
|
||||
CustomText {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Keep Awake")
|
||||
font.pointSize: 13
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
CustomText {
|
||||
Layout.fillWidth: true
|
||||
text: IdleInhibitor.enabled ? qsTr("Preventing sleep mode") : qsTr("Normal power management")
|
||||
color: DynamicColors.palette.m3onSurfaceVariant
|
||||
font.pointSize: 11
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
|
||||
CustomSwitch {
|
||||
checked: IdleInhibitor.enabled
|
||||
onToggled: IdleInhibitor.enabled = checked
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: activeChip
|
||||
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.topMargin: 20
|
||||
anchors.bottomMargin: IdleInhibitor.enabled ? 18 : -implicitHeight
|
||||
anchors.leftMargin: 18
|
||||
|
||||
opacity: IdleInhibitor.enabled ? 1 : 0
|
||||
scale: IdleInhibitor.enabled ? 1 : 0.5
|
||||
|
||||
Component.onCompleted: active = Qt.binding(() => opacity > 0)
|
||||
|
||||
sourceComponent: CustomRect {
|
||||
implicitWidth: activeText.implicitWidth + 10 * 2
|
||||
implicitHeight: activeText.implicitHeight + 10 * 2
|
||||
|
||||
radius: 1000
|
||||
color: DynamicColors.palette.m3primary
|
||||
|
||||
CustomText {
|
||||
id: activeText
|
||||
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("Active since %1").arg(Qt.formatTime(IdleInhibitor.enabledSince, Config.services.useTwelveHourClock ? "hh:mm a" : "hh:mm"))
|
||||
color: DynamicColors.palette.m3onPrimary
|
||||
font.pointSize: Math.round(11 * 0.9)
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on anchors.bottomMargin {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on implicitHeight {
|
||||
Anim {
|
||||
Behavior on implicitHeight {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: layout
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.margins: 18
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
spacing: 10
|
||||
|
||||
CustomRect {
|
||||
color: IdleInhibitor.enabled ? DynamicColors.palette.m3secondary : DynamicColors.palette.m3secondaryContainer
|
||||
implicitHeight: icon.implicitHeight + 7 * 2
|
||||
implicitWidth: implicitHeight
|
||||
radius: 1000
|
||||
|
||||
MaterialIcon {
|
||||
id: icon
|
||||
|
||||
anchors.centerIn: parent
|
||||
color: IdleInhibitor.enabled ? DynamicColors.palette.m3onSecondary : DynamicColors.palette.m3onSecondaryContainer
|
||||
font.pointSize: 18
|
||||
text: "coffee"
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 0
|
||||
|
||||
CustomText {
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
font.pointSize: 13
|
||||
text: qsTr("Keep Awake")
|
||||
}
|
||||
|
||||
CustomText {
|
||||
Layout.fillWidth: true
|
||||
color: DynamicColors.palette.m3onSurfaceVariant
|
||||
elide: Text.ElideRight
|
||||
font.pointSize: 11
|
||||
text: IdleInhibitor.enabled ? qsTr("Preventing sleep mode") : qsTr("Normal power management")
|
||||
}
|
||||
}
|
||||
|
||||
CustomSwitch {
|
||||
checked: IdleInhibitor.enabled
|
||||
|
||||
onToggled: IdleInhibitor.enabled = checked
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: activeChip
|
||||
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: IdleInhibitor.enabled ? 18 : -implicitHeight
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 18
|
||||
anchors.topMargin: 20
|
||||
opacity: IdleInhibitor.enabled ? 1 : 0
|
||||
scale: IdleInhibitor.enabled ? 1 : 0.5
|
||||
|
||||
Behavior on anchors.bottomMargin {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
}
|
||||
}
|
||||
Behavior on scale {
|
||||
Anim {
|
||||
}
|
||||
}
|
||||
sourceComponent: CustomRect {
|
||||
color: DynamicColors.palette.m3primary
|
||||
implicitHeight: activeText.implicitHeight + 10 * 2
|
||||
implicitWidth: activeText.implicitWidth + 10 * 2
|
||||
radius: 1000
|
||||
|
||||
CustomText {
|
||||
id: activeText
|
||||
|
||||
anchors.centerIn: parent
|
||||
color: DynamicColors.palette.m3onPrimary
|
||||
font.pointSize: Math.round(11 * 0.9)
|
||||
text: qsTr("Active since %1").arg(Qt.formatTime(IdleInhibitor.enabledSince, Config.services.useTwelveHourClock ? "hh:mm a" : "hh:mm"))
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: active = Qt.binding(() => opacity > 0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,91 +6,89 @@ import Quickshell
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
required property var visibilities
|
||||
required property Item sidebar
|
||||
required property Item popouts
|
||||
required property Item popouts
|
||||
readonly property PersistentProperties props: PersistentProperties {
|
||||
property string recordingConfirmDelete
|
||||
property bool recordingListExpanded: false
|
||||
property string recordingMode
|
||||
|
||||
readonly property PersistentProperties props: PersistentProperties {
|
||||
property bool recordingListExpanded: false
|
||||
property string recordingConfirmDelete
|
||||
property string recordingMode
|
||||
reloadableId: "utilities"
|
||||
}
|
||||
readonly property bool shouldBeActive: visibilities.sidebar
|
||||
required property Item sidebar
|
||||
required property var visibilities
|
||||
|
||||
reloadableId: "utilities"
|
||||
}
|
||||
readonly property bool shouldBeActive: visibilities.sidebar
|
||||
implicitHeight: 0
|
||||
implicitWidth: sidebar.visible ? sidebar.width : Config.utilities.sizes.width
|
||||
visible: height > 0
|
||||
|
||||
visible: height > 0
|
||||
implicitHeight: 0
|
||||
implicitWidth: sidebar.visible ? sidebar.width : Config.utilities.sizes.width
|
||||
states: State {
|
||||
name: "visible"
|
||||
when: root.shouldBeActive
|
||||
|
||||
onStateChanged: {
|
||||
if (state === "visible" && timer.running) {
|
||||
timer.triggered();
|
||||
timer.stop();
|
||||
}
|
||||
}
|
||||
PropertyChanges {
|
||||
root.implicitHeight: content.implicitHeight + 8 * 2
|
||||
}
|
||||
}
|
||||
transitions: [
|
||||
Transition {
|
||||
from: ""
|
||||
to: "visible"
|
||||
|
||||
states: State {
|
||||
name: "visible"
|
||||
when: root.shouldBeActive
|
||||
|
||||
PropertyChanges {
|
||||
root.implicitHeight: content.implicitHeight + 8 * 2
|
||||
}
|
||||
}
|
||||
|
||||
transitions: [
|
||||
Transition {
|
||||
from: ""
|
||||
to: "visible"
|
||||
|
||||
Anim {
|
||||
target: root
|
||||
property: "implicitHeight"
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
},
|
||||
Transition {
|
||||
from: "visible"
|
||||
to: ""
|
||||
property: "implicitHeight"
|
||||
target: root
|
||||
}
|
||||
},
|
||||
Transition {
|
||||
from: "visible"
|
||||
to: ""
|
||||
|
||||
Anim {
|
||||
target: root
|
||||
property: "implicitHeight"
|
||||
Anim {
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
]
|
||||
property: "implicitHeight"
|
||||
target: root
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Timer {
|
||||
id: timer
|
||||
onStateChanged: {
|
||||
if (state === "visible" && timer.running) {
|
||||
timer.triggered();
|
||||
timer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
running: true
|
||||
interval: 1000
|
||||
onTriggered: {
|
||||
content.active = Qt.binding(() => root.shouldBeActive || root.visible);
|
||||
content.visible = true;
|
||||
}
|
||||
}
|
||||
Timer {
|
||||
id: timer
|
||||
|
||||
Loader {
|
||||
id: content
|
||||
interval: 1000
|
||||
running: true
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.margins: 8
|
||||
onTriggered: {
|
||||
content.active = Qt.binding(() => root.shouldBeActive || root.visible);
|
||||
content.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
visible: false
|
||||
active: true
|
||||
Loader {
|
||||
id: content
|
||||
|
||||
sourceComponent: Content {
|
||||
implicitWidth: root.implicitWidth - 8 * 2
|
||||
props: root.props
|
||||
visibilities: root.visibilities
|
||||
popouts: root.popouts
|
||||
}
|
||||
}
|
||||
active: true
|
||||
anchors.left: parent.left
|
||||
anchors.margins: 8
|
||||
anchors.top: parent.top
|
||||
visible: false
|
||||
|
||||
sourceComponent: Content {
|
||||
implicitWidth: root.implicitWidth - 8 * 2
|
||||
popouts: root.popouts
|
||||
props: root.props
|
||||
visibilities: root.visibilities
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,64 +5,64 @@ import qs.Config
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
required property var visibilities
|
||||
required property var panels
|
||||
readonly property Props props: Props {}
|
||||
required property var panels
|
||||
readonly property Props props: Props {
|
||||
}
|
||||
required property var visibilities
|
||||
|
||||
visible: width > 0
|
||||
implicitWidth: 0
|
||||
implicitWidth: 0
|
||||
visible: width > 0
|
||||
|
||||
states: State {
|
||||
name: "visible"
|
||||
when: root.visibilities.sidebar
|
||||
states: State {
|
||||
name: "visible"
|
||||
when: root.visibilities.sidebar
|
||||
|
||||
PropertyChanges {
|
||||
root.implicitWidth: Config.sidebar.sizes.width
|
||||
}
|
||||
}
|
||||
PropertyChanges {
|
||||
root.implicitWidth: Config.sidebar.sizes.width
|
||||
}
|
||||
}
|
||||
transitions: [
|
||||
Transition {
|
||||
from: ""
|
||||
to: "visible"
|
||||
|
||||
transitions: [
|
||||
Transition {
|
||||
from: ""
|
||||
to: "visible"
|
||||
|
||||
Anim {
|
||||
target: root
|
||||
property: "implicitWidth"
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
},
|
||||
Transition {
|
||||
from: "visible"
|
||||
to: ""
|
||||
property: "implicitWidth"
|
||||
target: root
|
||||
}
|
||||
},
|
||||
Transition {
|
||||
from: "visible"
|
||||
to: ""
|
||||
|
||||
Anim {
|
||||
target: root
|
||||
property: "implicitWidth"
|
||||
Anim {
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
]
|
||||
property: "implicitWidth"
|
||||
target: root
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Loader {
|
||||
id: content
|
||||
Loader {
|
||||
id: content
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.margins: 8
|
||||
anchors.bottomMargin: 0
|
||||
active: true
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.margins: 8
|
||||
anchors.top: parent.top
|
||||
|
||||
active: true
|
||||
Component.onCompleted: active = Qt.binding(() => (root.visibilities.sidebar && Config.sidebar.enabled) || root.visible)
|
||||
sourceComponent: Content {
|
||||
implicitWidth: Config.sidebar.sizes.width - 8 * 2
|
||||
props: root.props
|
||||
visibilities: root.visibilities
|
||||
}
|
||||
|
||||
sourceComponent: Content {
|
||||
implicitWidth: Config.sidebar.sizes.width - 8 * 2
|
||||
props: root.props
|
||||
visibilities: root.visibilities
|
||||
}
|
||||
}
|
||||
Component.onCompleted: active = Qt.binding(() => (root.visibilities.sidebar && Config.sidebar.enabled) || root.visible)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,37 +3,36 @@ import qs.Components
|
||||
import qs.Config
|
||||
|
||||
Item {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
required property var visibilities
|
||||
required property Item panels
|
||||
required property Item panels
|
||||
required property var visibilities
|
||||
|
||||
visible: height > 0
|
||||
implicitWidth: Math.max(panels.sidebar.width, content.implicitWidth)
|
||||
implicitHeight: content.implicitHeight
|
||||
implicitHeight: content.implicitHeight
|
||||
implicitWidth: Math.max(panels.sidebar.width, content.implicitWidth)
|
||||
visible: height > 0
|
||||
|
||||
states: State {
|
||||
name: "hidden"
|
||||
when: root.visibilities.sidebar
|
||||
states: State {
|
||||
name: "hidden"
|
||||
when: root.visibilities.sidebar
|
||||
|
||||
PropertyChanges {
|
||||
root.implicitHeight: 0
|
||||
}
|
||||
}
|
||||
PropertyChanges {
|
||||
root.implicitHeight: 0
|
||||
}
|
||||
}
|
||||
transitions: Transition {
|
||||
Anim {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
property: "implicitHeight"
|
||||
target: root
|
||||
}
|
||||
}
|
||||
|
||||
transitions: Transition {
|
||||
Anim {
|
||||
target: root
|
||||
property: "implicitHeight"
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
Content {
|
||||
id: content
|
||||
|
||||
Content {
|
||||
id: content
|
||||
|
||||
visibilities: root.visibilities
|
||||
panels: root.panels
|
||||
}
|
||||
panels: root.panels
|
||||
visibilities: root.visibilities
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user