mirror of
https://github.com/kossLAN/dots.git
synced 2025-11-04 22:49:50 -05:00
Initial commit
remove syncthing folder bar/popops: fix menu window anims and positioning bar/popops: change anims a little and add dropshadow Update README.md widgets/coloredicon: move to colorization, looks worse but..., yea bar/popops: make popup window dissapear on menu close README: add todo list, and brief desc Update README.md Update README.md Update README.md bar/systray: issue recreate on interact bar/systray: hide popup on interact bar/systray: add arrow for entries with children bar/battery: start of battery widget wallpaper/matugen: add foot template extra sizing conditions for sys tray bar/systray: add some more margin to text update settings schema bar/workspaces: filter by monitor, switch to scriptmodel settings: fix settings lol bar/systray: fix right item feat: screenshot tool clipboard one day... feat: init lockscreen mpris: add ipc handler for multimedia keys mpris stuff save progress put shell in subdir, and add nix package move readme back woops bar/volume: make tool bar smaller greeter: init greeter greeter: fixed resource links readme: update checklist progress maybe, maybe not fix: fixed screenshot tool not working fix: bar layout issues progress save progress update track styled popup still broken but getting there still broken but getting there fix: gitignore qmlls.ini fix: remove qmlls.ini progress save new popup system new popup system new popup system more work on popups fix: mask issues on popups update readme
This commit is contained in:
commit
9e44812e93
102 changed files with 4592 additions and 0 deletions
218
shell/notifications/ActiveToast.qml
Normal file
218
shell/notifications/ActiveToast.qml
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import Quickshell.Services.Notifications
|
||||
import "../widgets/" as Widgets
|
||||
import ".."
|
||||
import "../.."
|
||||
|
||||
Item {
|
||||
id: root
|
||||
required property var notification
|
||||
signal expired(Notification notification)
|
||||
signal closed(Notification notification)
|
||||
|
||||
width: parent.width
|
||||
height: Math.min(row.implicitHeight + 30, 400)
|
||||
|
||||
Rectangle {
|
||||
id: container
|
||||
radius: 10
|
||||
color: ShellSettings.colors["surface_container"]
|
||||
anchors.fill: parent
|
||||
|
||||
Item {
|
||||
id: timerController
|
||||
property int totalDuration: 5000
|
||||
property int remainingTime: totalDuration
|
||||
property bool isRunning: false
|
||||
property real lastTime: 0
|
||||
|
||||
Timer {
|
||||
id: internalTimer
|
||||
interval: 16
|
||||
repeat: true
|
||||
running: timerController.isRunning
|
||||
|
||||
onTriggered: {
|
||||
var currentTime = Date.now();
|
||||
if (timerController.lastTime > 0) {
|
||||
var delta = currentTime - timerController.lastTime;
|
||||
timerController.remainingTime -= delta;
|
||||
if (timerController.remainingTime <= 0) {
|
||||
timerController.isRunning = false;
|
||||
root.expired(root.notification);
|
||||
}
|
||||
}
|
||||
timerController.lastTime = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
function start() {
|
||||
if (!isRunning) {
|
||||
lastTime = Date.now();
|
||||
isRunning = true;
|
||||
}
|
||||
}
|
||||
|
||||
function pause() {
|
||||
isRunning = false;
|
||||
lastTime = 0;
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: notificationArea
|
||||
hoverEnabled: true
|
||||
anchors.fill: parent
|
||||
|
||||
onContainsMouseChanged: {
|
||||
progressAnimation.paused = containsMouse;
|
||||
if (containsMouse) {
|
||||
timerController.pause();
|
||||
} else {
|
||||
timerController.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: row
|
||||
spacing: 5
|
||||
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: 15
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
RowLayout {
|
||||
id: topRow
|
||||
spacing: 10
|
||||
Layout.fillWidth: true
|
||||
|
||||
IconImage {
|
||||
visible: root.notification.appIcon != ""
|
||||
source: Quickshell.iconPath(root.notification.appIcon)
|
||||
implicitSize: 24
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
Text {
|
||||
id: appName
|
||||
text: root.notification.appName
|
||||
color: ShellSettings.colors["inverse_surface"]
|
||||
font.pointSize: 11
|
||||
font.bold: true
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 1
|
||||
Layout.preferredWidth: implicitWidth
|
||||
Layout.maximumWidth: topRow.width * 0.3
|
||||
}
|
||||
|
||||
Widgets.Separator {}
|
||||
|
||||
Text {
|
||||
id: summaryText
|
||||
text: root.notification.summary
|
||||
color: ShellSettings.colors["inverse_surface"]
|
||||
font.pointSize: 11
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 1
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: closeButton
|
||||
width: 24
|
||||
height: 24
|
||||
Layout.alignment: Qt.AlignTop
|
||||
|
||||
Canvas {
|
||||
id: progressCircle
|
||||
anchors.fill: parent
|
||||
antialiasing: true
|
||||
|
||||
property real progress: 1.0
|
||||
onProgressChanged: requestPaint()
|
||||
|
||||
onPaint: {
|
||||
var ctx = getContext("2d");
|
||||
ctx.reset();
|
||||
|
||||
var centerX = width / 2;
|
||||
var centerY = height / 2;
|
||||
var radius = Math.min(width, height) / 2 - 2;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(centerX, centerY, radius, -Math.PI / 2, -Math.PI / 2 + 2 * Math.PI * progress);
|
||||
ctx.strokeStyle = ShellSettings.colors["primary"];
|
||||
ctx.lineWidth = 2;
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
id: progressAnimation
|
||||
target: progressCircle
|
||||
property: "progress"
|
||||
from: 1.0
|
||||
to: 0.0
|
||||
duration: 5000
|
||||
running: true
|
||||
easing.type: Easing.Linear
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: closeButtonBg
|
||||
anchors.centerIn: parent
|
||||
width: 16
|
||||
height: 16
|
||||
color: "#FF474D"
|
||||
radius: 10
|
||||
visible: closeButtonArea.containsMouse
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: closeButtonArea
|
||||
hoverEnabled: true
|
||||
anchors.fill: parent
|
||||
onPressed: root.closed(root.notification)
|
||||
}
|
||||
|
||||
IconImage {
|
||||
source: "image://icon/window-close"
|
||||
implicitSize: 16
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
Text {
|
||||
id: bodyText
|
||||
text: root.notification.body
|
||||
color: ShellSettings.colors["inverse_surface"]
|
||||
font.pointSize: 11
|
||||
wrapMode: Text.Wrap
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 10
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
98
shell/notifications/Controller.qml
Normal file
98
shell/notifications/Controller.qml
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import ".."
|
||||
|
||||
Scope {
|
||||
id: root
|
||||
|
||||
Connections {
|
||||
target: Notifications.notificationServer
|
||||
|
||||
function onNotification(notification) {
|
||||
notificationLoader.item.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
id: notificationLoader
|
||||
loading: true
|
||||
|
||||
PanelWindow {
|
||||
id: notificationWindow
|
||||
property var visibleCount: {
|
||||
let count = 0;
|
||||
|
||||
for (let i = 0; i < toastList.count; i++) {
|
||||
let item = toastList.itemAt(i);
|
||||
|
||||
if (item && item.visible) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
onVisibleCountChanged: visible = visibleCount != 0
|
||||
|
||||
color: "transparent"
|
||||
implicitWidth: 525
|
||||
visible: false
|
||||
exclusionMode: ExclusionMode.Normal
|
||||
|
||||
mask: Region {
|
||||
item: notifLayout
|
||||
}
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
bottom: true
|
||||
right: true
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "length: " + notificationWindow.visibleCount
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: notifLayout
|
||||
spacing: 15
|
||||
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
margins: 5
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: toastList
|
||||
model: ScriptModel {
|
||||
values: Notifications.notificationServer.trackedNotifications.values.concat()
|
||||
}
|
||||
|
||||
delegate: ActiveToast {
|
||||
id: toast
|
||||
required property var modelData
|
||||
notification: modelData
|
||||
|
||||
Connections {
|
||||
target: toast
|
||||
|
||||
function onExpired(notification) {
|
||||
toast.visible = false;
|
||||
}
|
||||
|
||||
function onClosed(notification) {
|
||||
notification.dismiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
278
shell/notifications/NotificationCenter.qml
Normal file
278
shell/notifications/NotificationCenter.qml
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Qt5Compat.GraphicalEffects
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Widgets
|
||||
import "../widgets" as Widgets
|
||||
import ".."
|
||||
|
||||
Singleton {
|
||||
PersistentProperties {
|
||||
id: persist
|
||||
property bool notificationsOpen: false
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
id: ipc
|
||||
target: "notifications"
|
||||
|
||||
function open(): void {
|
||||
persist.notificationsOpen = true;
|
||||
}
|
||||
|
||||
function close(): void {
|
||||
persist.notificationsOpen = false;
|
||||
}
|
||||
|
||||
function toggle(): void {
|
||||
persist.notificationsOpen = !persist.notificationsOpen;
|
||||
}
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
id: loader
|
||||
activeAsync: persist.notificationsOpen
|
||||
|
||||
PanelWindow {
|
||||
id: notificationPanel
|
||||
color: "red"
|
||||
implicitWidth: 500
|
||||
exclusionMode: ExclusionMode.Ignore
|
||||
// WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
|
||||
anchors {
|
||||
top: true
|
||||
right: true
|
||||
bottom: true
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 10
|
||||
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: 10
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Notifications: " + toastList.count
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: toastList
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
clip: true
|
||||
spacing: 5
|
||||
|
||||
model: ScriptModel {
|
||||
values: {
|
||||
const notifications = Notifications.notificationServer.trackedNotifications.values.concat();
|
||||
|
||||
const groupedByApp = notifications.reduce((groups, notification) => {
|
||||
const appName = notification.appName;
|
||||
|
||||
if (!groups[appName]) {
|
||||
groups[appName] = {
|
||||
appName: appName,
|
||||
summaryGroups: {}
|
||||
};
|
||||
}
|
||||
|
||||
const summary = notification.summary;
|
||||
const image = notification.image;
|
||||
|
||||
if (!groups[appName].summaryGroups[summary]) {
|
||||
groups[appName].summaryGroups[summary] = {
|
||||
summary: summary,
|
||||
image: image,
|
||||
notifications: []
|
||||
};
|
||||
}
|
||||
|
||||
groups[appName].summaryGroups[summary].notifications.push(notification);
|
||||
|
||||
return groups;
|
||||
}, {});
|
||||
|
||||
return Object.values(groupedByApp).map(appGroup => {
|
||||
return {
|
||||
appName: appGroup.appName,
|
||||
summaryGroups: Object.values(appGroup.summaryGroups)
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
id: toastWrapper
|
||||
required property var modelData
|
||||
width: ListView.view.width
|
||||
height: toastContent.height
|
||||
|
||||
Item {
|
||||
id: toastContent
|
||||
width: parent.width
|
||||
height: contentColumn.implicitHeight
|
||||
anchors.centerIn: parent
|
||||
|
||||
ColumnLayout {
|
||||
id: contentColumn
|
||||
spacing: 2
|
||||
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: 0
|
||||
}
|
||||
|
||||
// Notification content
|
||||
Repeater {
|
||||
model: toastWrapper.modelData.summaryGroups
|
||||
|
||||
delegate: Rectangle {
|
||||
id: summaryGroup
|
||||
required property var modelData
|
||||
required property int index
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: groupContent.implicitHeight + 24
|
||||
color: ShellSettings.colors["surface_container"]
|
||||
antialiasing: true
|
||||
|
||||
topLeftRadius: index === 0 ? 25 : 5
|
||||
topRightRadius: index === 0 ? 25 : 5
|
||||
bottomLeftRadius: index === (toastWrapper.modelData.summaryGroups.length - 1) ? 25 : 5
|
||||
bottomRightRadius: index === (toastWrapper.modelData.summaryGroups.length - 1) ? 25 : 5
|
||||
|
||||
ColumnLayout {
|
||||
id: groupContent
|
||||
spacing: 8
|
||||
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: 12
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 12
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignTop
|
||||
|
||||
ColumnLayout {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
spacing: 0
|
||||
|
||||
Item {
|
||||
id: imageContainer
|
||||
Layout.preferredWidth: 36
|
||||
Layout.preferredHeight: 36
|
||||
visible: summaryGroup.modelData.image != ""
|
||||
antialiasing: true
|
||||
|
||||
Image {
|
||||
id: notificationImage
|
||||
anchors.fill: parent
|
||||
source: summaryGroup.modelData.image
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: OpacityMask {
|
||||
maskSource: Rectangle {
|
||||
width: notificationImage.width
|
||||
height: notificationImage.height
|
||||
radius: notificationImage.width / 2
|
||||
antialiasing: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Content column
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignTop
|
||||
spacing: 8
|
||||
|
||||
// Header row
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 8
|
||||
|
||||
Text {
|
||||
text: summaryGroup.modelData.summary
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.Medium
|
||||
color: ShellSettings.colors["on_surface"]
|
||||
wrapMode: Text.WordWrap
|
||||
maximumLineCount: 2
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
Widgets.Separator {}
|
||||
|
||||
Text {
|
||||
text: "now"
|
||||
font.pixelSize: 14
|
||||
color: ShellSettings.colors["on_surface_variant"]
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
}
|
||||
|
||||
// Notification bodies
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 2
|
||||
|
||||
Repeater {
|
||||
model: summaryGroup.modelData.notifications
|
||||
|
||||
delegate: ColumnLayout {
|
||||
id: bodyDelegate
|
||||
required property var modelData
|
||||
required property int index
|
||||
Layout.fillWidth: true
|
||||
spacing: 0
|
||||
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
text: bodyDelegate.modelData.body
|
||||
font.pixelSize: 14
|
||||
color: ShellSettings.colors["on_surface_variant"]
|
||||
wrapMode: Text.WordWrap
|
||||
maximumLineCount: 4
|
||||
elide: Text.ElideRight
|
||||
lineHeight: 1.3
|
||||
visible: bodyDelegate.modelData.body != ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// HyprlanFocusGrab {
|
||||
// id: grab
|
||||
// windows: [notificationPanel]
|
||||
// onCleared: {
|
||||
// ipc.hide();
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
}
|
||||
}
|
||||
23
shell/notifications/Notifications.qml
Normal file
23
shell/notifications/Notifications.qml
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
pragma Singleton
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Services.Notifications
|
||||
|
||||
Singleton {
|
||||
property alias notificationServer: notifServer
|
||||
|
||||
NotificationServer {
|
||||
id: notifServer
|
||||
actionsSupported: true
|
||||
persistenceSupported: true
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: notifServer
|
||||
|
||||
function onNotification(notification) {
|
||||
notification.tracked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue