Merge branch 'new-one'
This commit is contained in:
11
.gitignore
vendored
11
.gitignore
vendored
@@ -1 +1,12 @@
|
|||||||
.session
|
.session
|
||||||
|
|
||||||
|
# Devenv
|
||||||
|
.devenv*
|
||||||
|
devenv.local.nix
|
||||||
|
devenv.local.yaml
|
||||||
|
|
||||||
|
# direnv
|
||||||
|
.direnv
|
||||||
|
|
||||||
|
# pre-commit
|
||||||
|
.pre-commit-config.yaml
|
||||||
|
|||||||
93
Bar.qml
93
Bar.qml
@@ -1,10 +1,10 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Effects
|
import QtQuick.Effects
|
||||||
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Hyprland
|
import Quickshell.Hyprland
|
||||||
import "Components/Color.js" as Colors
|
import "Bar"
|
||||||
|
import "Color.js" as Colors
|
||||||
import "Components"
|
|
||||||
|
|
||||||
Scope {
|
Scope {
|
||||||
Variants {
|
Variants {
|
||||||
@@ -14,32 +14,28 @@ Scope {
|
|||||||
PanelWindow {
|
PanelWindow {
|
||||||
id: win
|
id: win
|
||||||
|
|
||||||
|
property double barExclusionZone: 15
|
||||||
|
property double barMaxHeight: 1000
|
||||||
required property var modelData
|
required property var modelData
|
||||||
property HyprlandMonitor monitor: Hyprland.monitorFor(modelData)
|
property HyprlandMonitor monitor: Hyprland.monitorFor(modelData)
|
||||||
|
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
exclusionMode: ExclusionMode.Normal
|
exclusionMode: ExclusionMode.Normal
|
||||||
exclusiveZone: 20
|
exclusiveZone: barExclusionZone
|
||||||
implicitHeight: 1000
|
implicitHeight: barMaxHeight
|
||||||
screen: modelData
|
screen: modelData
|
||||||
|
|
||||||
Behavior on implicitHeight {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: 0
|
|
||||||
easing.type: Easing.InOutQuad
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mask: Region {
|
mask: Region {
|
||||||
Region {
|
Region {
|
||||||
item: workspaceSwitcher
|
item: left
|
||||||
}
|
}
|
||||||
|
|
||||||
Region {
|
Region {
|
||||||
item: pillItem
|
item: center
|
||||||
}
|
}
|
||||||
|
|
||||||
Region {
|
Region {
|
||||||
item: utilsItem
|
item: right
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,34 +45,52 @@ Scope {
|
|||||||
top: true
|
top: true
|
||||||
}
|
}
|
||||||
|
|
||||||
Workspace {
|
|
||||||
id: workspaceSwitcher
|
|
||||||
|
|
||||||
monitor: win.monitor
|
|
||||||
}
|
|
||||||
|
|
||||||
RectangularShadow {
|
|
||||||
anchors.fill: pillItem
|
|
||||||
blur: 20
|
|
||||||
color: Colors.crust
|
|
||||||
offset.x: 3
|
|
||||||
offset.y: 3
|
|
||||||
radius: pillItem.radius
|
|
||||||
spread: 7
|
|
||||||
}
|
|
||||||
|
|
||||||
Pill {
|
|
||||||
id: pillItem
|
|
||||||
|
|
||||||
monitor: win.monitor
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
anchors.fill: parent
|
anchors {
|
||||||
|
fill: parent
|
||||||
|
topMargin: 3
|
||||||
|
}
|
||||||
|
|
||||||
Utils {
|
Row {
|
||||||
id: utilsItem
|
id: left
|
||||||
|
|
||||||
|
height: childrenRect.height
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
leftMargin: 7
|
||||||
|
}
|
||||||
|
|
||||||
|
Left {
|
||||||
|
monitor: win.monitor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: center
|
||||||
|
|
||||||
|
height: childrenRect.height
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Center {
|
||||||
|
monitor: win.monitor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: right
|
||||||
|
|
||||||
|
height: childrenRect.height
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
right: parent.right
|
||||||
|
rightMargin: 7
|
||||||
|
}
|
||||||
|
|
||||||
|
Right {
|
||||||
monitor: win.monitor
|
monitor: win.monitor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -84,3 +98,4 @@ Scope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
264
Bar/Center.qml
Normal file
264
Bar/Center.qml
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import Quickshell.Services.Mpris
|
||||||
|
import Quickshell.Services.Notifications
|
||||||
|
import "../Color.js" as Colors
|
||||||
|
import "../Components/"
|
||||||
|
import "../Services/"
|
||||||
|
import "./Center"
|
||||||
|
|
||||||
|
Container {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property Notification latestNotification: NotificationManager.getLatestNotification() || null
|
||||||
|
required property HyprlandMonitor monitor
|
||||||
|
property NotificationServer notifServer: NotificationManager.notif
|
||||||
|
property string previousState
|
||||||
|
|
||||||
|
boxColor: Colors.mauve
|
||||||
|
defaultItem: time
|
||||||
|
exclusiveMonitor: root.monitor
|
||||||
|
exclusiveToScreen: true
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: ""
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
root.boxHeight: 28
|
||||||
|
root.boxRadius: 9
|
||||||
|
root.boxWidth: 100
|
||||||
|
root.visibleTopMargin: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
StateChangeScript {
|
||||||
|
script: {
|
||||||
|
if (root.previousState != "hovered") {
|
||||||
|
root.stack.replace(time);
|
||||||
|
}
|
||||||
|
root.previousState = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "hovered"
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
root.boxHeight: 35
|
||||||
|
root.boxRadius: 15
|
||||||
|
root.boxWidth: 110
|
||||||
|
root.visibleTopMargin: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
StateChangeScript {
|
||||||
|
script: {
|
||||||
|
root.previousState = "hovered";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "mprisToast"
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
root.boxHeight: 35
|
||||||
|
root.boxRadius: 15
|
||||||
|
root.boxWidth: 350
|
||||||
|
root.visibleTopMargin: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
StateChangeScript {
|
||||||
|
script: {
|
||||||
|
root.previousState = "mpris";
|
||||||
|
root.stack.replace(mpris);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "expanded"
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
root.boxHeight: 140
|
||||||
|
root.boxRadius: 30
|
||||||
|
root.boxWidth: 300
|
||||||
|
root.visibleTopMargin: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
StateChangeScript {
|
||||||
|
script: {
|
||||||
|
if (root.state != "notifications") {
|
||||||
|
root.stack.replace(fullTime);
|
||||||
|
root.previousState = "expanded";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
extend: "expanded"
|
||||||
|
name: "notifications"
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
root.boxHeight: 320
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "notified"
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
root.boxHeight: 90
|
||||||
|
root.boxRadius: 30
|
||||||
|
root.boxWidth: 330
|
||||||
|
root.visibleTopMargin: 20
|
||||||
|
}
|
||||||
|
|
||||||
|
StateChangeScript {
|
||||||
|
script: {
|
||||||
|
root.stack.replace(notification);
|
||||||
|
root.previousState = "notified";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
hover.onHoveredChanged: {
|
||||||
|
if (hover.hovered == true) {
|
||||||
|
if (root.state == "notified") {
|
||||||
|
root.state = "notified";
|
||||||
|
notificationViewTimer.stop();
|
||||||
|
} else if (MprisManager.getPlaying() == true) {
|
||||||
|
root.state = "mprisToast";
|
||||||
|
} else {
|
||||||
|
root.state = "hovered";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
root.state = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onLatestNotificationChanged: {
|
||||||
|
if (latestNotification != null && Hyprland.focusedMonitor == monitor) {
|
||||||
|
if (root.latestNotification.lastGeneration == false) {
|
||||||
|
root.state = "notified";
|
||||||
|
notificationViewTimer.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tap.onTapped: {
|
||||||
|
root.state == "hovered" ? root.state = "expanded" : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
function onTrackChanged() {
|
||||||
|
if (Hyprland.focusedMonitor == root.monitor) {
|
||||||
|
musicToastTimer.restart();
|
||||||
|
if (root.state == "") {
|
||||||
|
root.state = "mprisToast";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
target: MprisManager.defaultPlayer
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: notificationViewTimer
|
||||||
|
|
||||||
|
interval: 3000
|
||||||
|
repeat: false
|
||||||
|
running: false
|
||||||
|
|
||||||
|
onTriggered: {
|
||||||
|
root.state = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: musicToastTimer
|
||||||
|
|
||||||
|
interval: 3000
|
||||||
|
repeat: false
|
||||||
|
running: false
|
||||||
|
|
||||||
|
onTriggered: {
|
||||||
|
if (!root.hover.hovered) {
|
||||||
|
console.log("some");
|
||||||
|
root.state = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: time
|
||||||
|
|
||||||
|
Item {
|
||||||
|
CenteredText {
|
||||||
|
text: Time.time
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: mpris
|
||||||
|
|
||||||
|
Mpris {
|
||||||
|
TapHandler {
|
||||||
|
onTapped: root.state = "expanded"
|
||||||
|
}
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
acceptedButtons: Qt.RightButton
|
||||||
|
|
||||||
|
onTapped: MprisManager.skip()
|
||||||
|
}
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
acceptedButtons: Qt.MiddleButton
|
||||||
|
|
||||||
|
onTapped: MprisManager.prev()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: fullTime
|
||||||
|
|
||||||
|
Expanded {
|
||||||
|
NotificationList {
|
||||||
|
id: notifList
|
||||||
|
|
||||||
|
animEnabled: false
|
||||||
|
radius: root.boxRadius
|
||||||
|
rootState: root.state
|
||||||
|
server: root.notifServer
|
||||||
|
state: ""
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
onTapped: {
|
||||||
|
notifList.animEnabled = true;
|
||||||
|
root.state = "notifications";
|
||||||
|
Qt.callLater(() => {
|
||||||
|
notifList.animEnabled = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: notification
|
||||||
|
|
||||||
|
NotificationDisplay {
|
||||||
|
body: root.latestNotification.body
|
||||||
|
summary: root.latestNotification.summary
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
onTapped: {
|
||||||
|
root.state = "notifications";
|
||||||
|
root.stack.replace(fullTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
55
Bar/Center/Expanded.qml
Normal file
55
Bar/Center/Expanded.qml
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import "../../Color.js" as Colors
|
||||||
|
import "../../Components/"
|
||||||
|
import "../../Services/"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: fullTimeRoot
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: 30
|
||||||
|
|
||||||
|
gradient: MidpointGradient {
|
||||||
|
color: Colors.red
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: timeColumnContainer
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: timeColumn
|
||||||
|
|
||||||
|
spacing: 5
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
centerIn: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
color: Colors.surface0
|
||||||
|
text: Time.time
|
||||||
|
|
||||||
|
font {
|
||||||
|
pointSize: 30
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
color: Colors.surface1
|
||||||
|
text: Time.date
|
||||||
|
|
||||||
|
font {
|
||||||
|
pointSize: 9
|
||||||
|
weight: 400
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
62
Bar/Center/Mpris.qml
Normal file
62
Bar/Center/Mpris.qml
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell.Services.Mpris
|
||||||
|
import "../../Color.js" as Colors
|
||||||
|
import "../../Components/"
|
||||||
|
import "../../Services/"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property MprisPlayer player: MprisManager.defaultPlayer
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
color: Colors.red
|
||||||
|
radius: 5
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
bottomMargin: 15
|
||||||
|
fill: parent
|
||||||
|
leftMargin: 10
|
||||||
|
rightMargin: parent.width - ((parent.width * MprisManager.pos) - 10)
|
||||||
|
topMargin: 15
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors {
|
||||||
|
bottomMargin: 2
|
||||||
|
fill: parent
|
||||||
|
leftMargin: 7
|
||||||
|
rightMargin: 7
|
||||||
|
topMargin: 2
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.preferredWidth: height
|
||||||
|
|
||||||
|
Image {
|
||||||
|
anchors.fill: parent
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
source: MprisManager.defaultPlayer.trackArtUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
elide: Qt.ElideRight
|
||||||
|
horizontalAlignment: Qt.AlignHCenter
|
||||||
|
text: MprisManager.defaultPlayer.trackArtist + " - " + MprisManager.defaultPlayer.trackTitle
|
||||||
|
verticalAlignment: Qt.AlignVCenter
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
fill: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
47
Bar/Center/NotificationDisplay.qml
Normal file
47
Bar/Center/NotificationDisplay.qml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Services.Notifications
|
||||||
|
import "../../Color.js" as Colors
|
||||||
|
import "../../Components/"
|
||||||
|
import "../../Services/"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property string body
|
||||||
|
required property string summary
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: 30
|
||||||
|
|
||||||
|
gradient: MidpointGradient {
|
||||||
|
color: Colors.green
|
||||||
|
midpoint: 0.7
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: 5
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
font.pointSize: 11
|
||||||
|
text: root.summary
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
elide: Text.ElideRight
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
text: root.body
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
width: root.width - 20
|
||||||
|
|
||||||
|
font {
|
||||||
|
pointSize: 10
|
||||||
|
weight: 500
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
307
Bar/Center/NotificationList.qml
Normal file
307
Bar/Center/NotificationList.qml
Normal file
@@ -0,0 +1,307 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Effects
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Services.Notifications
|
||||||
|
import "../../Color.js" as Colors
|
||||||
|
import "../../Components/"
|
||||||
|
import "../../Services/"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property bool animEnabled
|
||||||
|
required property double radius
|
||||||
|
required property string rootState
|
||||||
|
required property NotificationServer server
|
||||||
|
|
||||||
|
Behavior on anchors.topMargin {
|
||||||
|
enabled: root.animEnabled
|
||||||
|
|
||||||
|
SpringAnimation {
|
||||||
|
damping: 0.35
|
||||||
|
spring: 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: ""
|
||||||
|
when: root.rootState != "notifications"
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
root.anchors.topMargin: root.parent.height - 21
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "expanded"
|
||||||
|
when: root.rootState == "notifications"
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
root.anchors.topMargin: 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
bottom: parent.bottom
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
top: parent.top
|
||||||
|
topMargin: parent.height - 21
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: background
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
color: Colors.surface0
|
||||||
|
radius: root.radius - 3
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: ""
|
||||||
|
when: root.rootState != "notifications"
|
||||||
|
|
||||||
|
PropertyChanges {}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "expanded"
|
||||||
|
when: root.rootState == "notifications"
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
background.anchors.bottomMargin: 5
|
||||||
|
background.anchors.leftMargin: 5
|
||||||
|
background.anchors.rightMargin: 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
bottomMargin: 15
|
||||||
|
leftMargin: 20
|
||||||
|
rightMargin: 20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: notifListContainer
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
clip: true
|
||||||
|
opacity: 0
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
bottomMargin: 5
|
||||||
|
leftMargin: 5
|
||||||
|
rightMargin: 5
|
||||||
|
topMargin: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
CenteredText {
|
||||||
|
color: Colors.overlay0
|
||||||
|
text: "No Notifications"
|
||||||
|
visible: root.server.trackedNotifications.values.length <= 0
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: notifScrollingList
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
|
height: Math.min(contentHeight, parent.height)
|
||||||
|
implicitHeight: background.height
|
||||||
|
model: root.server.trackedNotifications.values.length
|
||||||
|
spacing: 7
|
||||||
|
|
||||||
|
delegate: Item {
|
||||||
|
id: notifRoot
|
||||||
|
|
||||||
|
property Notification currentNotif: root.server.trackedNotifications.values[(notifRoot.notifLen
|
||||||
|
- 1) - index]
|
||||||
|
required property real index
|
||||||
|
property real notifLen: root.server.trackedNotifications.values.length
|
||||||
|
|
||||||
|
height: 50
|
||||||
|
width: ListView.view.width
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: ""
|
||||||
|
when: notifHover.hovered == false
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "hovered"
|
||||||
|
when: notifHover.hovered == false
|
||||||
|
|
||||||
|
PropertyChanges {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
HoverHandler {
|
||||||
|
id: notifHover
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: dismissButton
|
||||||
|
|
||||||
|
color: Colors.red
|
||||||
|
implicitWidth: 100
|
||||||
|
radius: 10
|
||||||
|
|
||||||
|
Behavior on anchors.rightMargin {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: ""
|
||||||
|
when: notifHover.hovered == false
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "hovered"
|
||||||
|
when: notifHover.hovered == true
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
dismissButton.anchors.rightMargin: 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
color: Colors.surface0
|
||||||
|
font.pointSize: 15
|
||||||
|
horizontalAlignment: Qt.AlignRight
|
||||||
|
text: ""
|
||||||
|
verticalAlignment: Qt.AlignVCenter
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
fill: parent
|
||||||
|
rightMargin: 14
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
onTapped: {
|
||||||
|
notifRoot.currentNotif.dismiss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
bottom: parent.bottom
|
||||||
|
bottomMargin: 3
|
||||||
|
right: parent.right
|
||||||
|
rightMargin: 10
|
||||||
|
top: parent.top
|
||||||
|
topMargin: 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: textContainer
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
clip: true
|
||||||
|
color: Colors.surface2
|
||||||
|
radius: 9
|
||||||
|
|
||||||
|
Behavior on anchors.rightMargin {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: ""
|
||||||
|
when: notifHover.hovered == false
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "hovered"
|
||||||
|
when: notifHover.hovered == true
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
textContainer.anchors.rightMargin: 40
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: textColumn
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
centerIn: parent
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
color: Colors.text
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
text: notifRoot.currentNotif.summary
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
width: notifRoot.width - 10
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
color: Colors.subtext1
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
text: notifRoot.currentNotif.body
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
width: notifRoot.width - 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
bottomMargin: 5
|
||||||
|
leftMargin: 10
|
||||||
|
rightMargin: 10
|
||||||
|
topMargin: 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiEffect {
|
||||||
|
id: notifListClipper
|
||||||
|
|
||||||
|
anchors.fill: notifListContainer
|
||||||
|
maskEnabled: true
|
||||||
|
maskSource: clipsource
|
||||||
|
opacity: 0
|
||||||
|
source: notifListContainer
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: ""
|
||||||
|
when: root.rootState != "notifications"
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
notifListClipper.opacity: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "expanded"
|
||||||
|
when: root.rootState == "notifications"
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
notifListClipper.opacity: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: clipsource
|
||||||
|
|
||||||
|
anchors.fill: background
|
||||||
|
color: "black"
|
||||||
|
layer.enabled: true
|
||||||
|
radius: background.radius
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
}
|
||||||
70
Bar/Left.qml
Normal file
70
Bar/Left.qml
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import Quickshell.Services.Notifications
|
||||||
|
import "../Color.js" as Colors
|
||||||
|
import "../Components/"
|
||||||
|
import "../Services/"
|
||||||
|
import "./Center"
|
||||||
|
import "./Left/"
|
||||||
|
|
||||||
|
Container {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property double extraHoveredWidth: 0
|
||||||
|
required property HyprlandMonitor monitor
|
||||||
|
property double rowLeftMargin: 4
|
||||||
|
property double rowSpacing: 3
|
||||||
|
property double rowYmargin: 3
|
||||||
|
property double selectorFocusedExtra: 15
|
||||||
|
property double selectorHeight: 20
|
||||||
|
property double selectorWidth: 20
|
||||||
|
property double spacing: 3
|
||||||
|
property double workspaceNumber: WorkspaceManager.getNumberOfWorkspaces(monitor)
|
||||||
|
|
||||||
|
boxHeight: 25
|
||||||
|
boxWidth: (selectorWidth * workspaceNumber) + ((2 * rowLeftMargin) + (rowSpacing * (
|
||||||
|
workspaceNumber - 1))) + extraHoveredWidth + (hoverHandler.hovered == true
|
||||||
|
? selectorFocusedExtra : 0)
|
||||||
|
exclusiveMonitor: monitor
|
||||||
|
|
||||||
|
defaultItem: WorkspaceContainer {
|
||||||
|
extraHoveredWidth: root.extraHoveredWidth
|
||||||
|
monitor: root.monitor
|
||||||
|
rowLeftMargin: root.rowLeftMargin
|
||||||
|
rowSpacing: root.rowSpacing
|
||||||
|
rowYmargin: root.rowYmargin
|
||||||
|
selectorFocusedExtra: root.selectorFocusedExtra
|
||||||
|
selectorHeight: root.selectorHeight
|
||||||
|
selectorWidth: root.selectorWidth
|
||||||
|
}
|
||||||
|
Behavior on rowYmargin {
|
||||||
|
SpringAnimation {
|
||||||
|
damping: 0.3
|
||||||
|
spring: 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: ""
|
||||||
|
when: !hoverHandler.hovered
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "hovered"
|
||||||
|
when: hoverHandler.hovered
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
root.boxHeight: 40
|
||||||
|
root.extraHoveredWidth: 25
|
||||||
|
root.rowYmargin: 5
|
||||||
|
root.selectorWidth: 40
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
HoverHandler {
|
||||||
|
id: hoverHandler
|
||||||
|
}
|
||||||
|
}
|
||||||
86
Bar/Left/WorkspaceContainer.qml
Normal file
86
Bar/Left/WorkspaceContainer.qml
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import "../../Color.js" as Colors
|
||||||
|
import "../../Components/"
|
||||||
|
import "../../Services/"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property double extraHoveredWidth
|
||||||
|
required property HyprlandMonitor monitor
|
||||||
|
required property double rowLeftMargin
|
||||||
|
required property double rowSpacing
|
||||||
|
required property double rowYmargin
|
||||||
|
required property double selectorFocusedExtra
|
||||||
|
required property double selectorHeight
|
||||||
|
required property double selectorWidth
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: newWorkspaceButton
|
||||||
|
|
||||||
|
implicitWidth: 20
|
||||||
|
opacity: root.extraHoveredWidth > 0 ? 1 : 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
id: tapHandler
|
||||||
|
|
||||||
|
onTapped: WorkspaceManager.activateNextFreeWorkspace()
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
bottom: parent.bottom
|
||||||
|
bottomMargin: 5 + root.rowYmargin
|
||||||
|
right: parent.right
|
||||||
|
rightMargin: 4
|
||||||
|
top: parent.top
|
||||||
|
topMargin: 5 + root.rowYmargin
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: Colors.green
|
||||||
|
radius: 4
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: "+"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
spacing: root.rowSpacing
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
bottom: parent.bottom
|
||||||
|
bottomMargin: root.rowYmargin
|
||||||
|
left: parent.left
|
||||||
|
leftMargin: root.rowLeftMargin
|
||||||
|
top: parent.top
|
||||||
|
topMargin: root.rowYmargin
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: WorkspaceManager.getWorkspacesForMonitor(root.monitor)
|
||||||
|
|
||||||
|
WorkspaceSelector {
|
||||||
|
required property HyprlandWorkspace modelData
|
||||||
|
|
||||||
|
extraHoveredWidth: root.extraHoveredWidth
|
||||||
|
selectorFocusedExtra: root.selectorFocusedExtra
|
||||||
|
selectorHeight: root.selectorHeight
|
||||||
|
selectorWidth: root.selectorWidth
|
||||||
|
workspace: modelData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
87
Bar/Left/WorkspaceSelector.qml
Normal file
87
Bar/Left/WorkspaceSelector.qml
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import "../../Color.js" as Colors
|
||||||
|
import "../../Components/"
|
||||||
|
import "../../Services/"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property double extraHoveredWidth
|
||||||
|
property bool hovered: extraHoveredWidth > 0 ? true : false
|
||||||
|
property color selectorColor: Colors.surface2
|
||||||
|
required property double selectorFocusedExtra
|
||||||
|
required property double selectorHeight
|
||||||
|
required property double selectorWidth
|
||||||
|
required property HyprlandWorkspace workspace
|
||||||
|
property string workspaceState: WorkspaceManager.getWorkspaceState(workspace)
|
||||||
|
|
||||||
|
implicitWidth: selectorWidth + (root.hovered == true ? (root.workspaceState == "focused"
|
||||||
|
? selectorFocusedExtra : 0) : 0)
|
||||||
|
|
||||||
|
Behavior on implicitWidth {
|
||||||
|
SpringAnimation {
|
||||||
|
damping: 0.3
|
||||||
|
spring: 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: ""
|
||||||
|
when: root.workspaceState == "inactive"
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
root.selectorColor: Colors.surface2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "active"
|
||||||
|
when: root.workspaceState == "active"
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
root.selectorColor: Colors.overlay2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "focused"
|
||||||
|
when: root.workspaceState == "focused"
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
root.selectorColor: Colors.lavender
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
id: tapHandler
|
||||||
|
|
||||||
|
onTapped: root.workspace.activate()
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
bottom: parent.bottom
|
||||||
|
top: parent.top
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
color: root.selectorColor
|
||||||
|
radius: 6
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
fill: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
CenteredText {
|
||||||
|
font.pointSize: 10.5
|
||||||
|
text: root.workspace.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
Bar/Right.qml
Normal file
21
Bar/Right.qml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import Quickshell.Services.Notifications
|
||||||
|
import "../Color.js" as Colors
|
||||||
|
import "../Components/"
|
||||||
|
import "../Services/"
|
||||||
|
import "./Center"
|
||||||
|
import "./Right/"
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property HyprlandMonitor monitor
|
||||||
|
|
||||||
|
Bluetooth {
|
||||||
|
exclusiveMonitor: root.monitor
|
||||||
|
}
|
||||||
|
}
|
||||||
72
Bar/Right/Bluetooth.qml
Normal file
72
Bar/Right/Bluetooth.qml
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Bluetooth
|
||||||
|
import "../../Color.js" as Colors
|
||||||
|
import "../../Components/"
|
||||||
|
import "../../Services/"
|
||||||
|
import "Bluetooth"
|
||||||
|
|
||||||
|
Container {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
animOffset: 200
|
||||||
|
boxColor: Colors.peach
|
||||||
|
boxHeight: 25
|
||||||
|
boxWidth: 30
|
||||||
|
defaultItem: icon
|
||||||
|
exclusiveToScreen: true
|
||||||
|
forceHidden: BluetoothManager.getConnected()
|
||||||
|
state: ""
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: ""
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
root.boxHeight: 25
|
||||||
|
root.boxWidth: 30
|
||||||
|
}
|
||||||
|
|
||||||
|
StateChangeScript {
|
||||||
|
script: {
|
||||||
|
root.stack.replace(icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "expanded"
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
root.boxHeight: 250
|
||||||
|
root.boxRadius: 20
|
||||||
|
root.boxWidth: 350
|
||||||
|
}
|
||||||
|
|
||||||
|
StateChangeScript {
|
||||||
|
script: {
|
||||||
|
root.stack.replace(expanded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
hover.onHoveredChanged: hover.hovered == false ? state = "" : undefined
|
||||||
|
tap.onTapped: state = "expanded"
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: icon
|
||||||
|
|
||||||
|
Item {
|
||||||
|
CenteredText {
|
||||||
|
text: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: expanded
|
||||||
|
|
||||||
|
Expanded {}
|
||||||
|
}
|
||||||
|
}
|
||||||
384
Bar/Right/Bluetooth/Expanded.qml
Normal file
384
Bar/Right/Bluetooth/Expanded.qml
Normal file
@@ -0,0 +1,384 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell.Bluetooth
|
||||||
|
import "../../../Color.js" as Colors
|
||||||
|
import "../../../Components/"
|
||||||
|
import "../../../Services/"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property double topBarHeight: 35
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
color: Colors.surface0
|
||||||
|
radius: 17
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
bottomMargin: 5
|
||||||
|
fill: parent
|
||||||
|
leftMargin: 5
|
||||||
|
rightMargin: 5
|
||||||
|
topMargin: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: topBar
|
||||||
|
|
||||||
|
property double topBarHeight: root.topBarHeight
|
||||||
|
|
||||||
|
color: Colors.peach
|
||||||
|
implicitHeight: topBarHeight
|
||||||
|
radius: 9
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
leftMargin: 5
|
||||||
|
right: parent.right
|
||||||
|
rightMargin: 5
|
||||||
|
top: parent.top
|
||||||
|
topMargin: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: topBarRow
|
||||||
|
|
||||||
|
property double topBarRowPadding: 4
|
||||||
|
|
||||||
|
spacing: 3
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
leftMargin: topBarRowPadding
|
||||||
|
right: parent.right
|
||||||
|
rightMargin: topBarRowPadding
|
||||||
|
top: parent.top
|
||||||
|
topMargin: topBarRowPadding
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
// color: Qt.lighter(Colors.peach, 1.2)
|
||||||
|
color: Colors.surface1
|
||||||
|
implicitHeight: topBar.topBarHeight - (topBarRow.topBarRowPadding * 2)
|
||||||
|
radius: 6
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
color: Colors.text
|
||||||
|
horizontalAlignment: Qt.AlignLeft
|
||||||
|
text: " " + BluetoothManager.defaultAdapterName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: scanButton
|
||||||
|
|
||||||
|
color: Qt.lighter(Colors.peach, 1.15)
|
||||||
|
implicitHeight: topBar.topBarHeight - (topBarRow.topBarRowPadding * 2)
|
||||||
|
implicitWidth: topBar.topBarHeight - (topBarRow.topBarRowPadding * 2)
|
||||||
|
radius: 6
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: "hovered"
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
scanButton.color: Colors.green
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
border {
|
||||||
|
color: Colors.surface0
|
||||||
|
width: 2
|
||||||
|
}
|
||||||
|
|
||||||
|
HoverHandler {
|
||||||
|
onHoveredChanged: hovered == true ? scanButton.state = "hovered" : scanButton.state = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
onTapped: {
|
||||||
|
BluetoothManager.toggleDiscover();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CenteredText {
|
||||||
|
id: scanButtonText
|
||||||
|
|
||||||
|
text: ""
|
||||||
|
|
||||||
|
NumberAnimation {
|
||||||
|
id: animateRotation
|
||||||
|
|
||||||
|
duration: 1000
|
||||||
|
from: 0
|
||||||
|
loops: Animation.Infinite
|
||||||
|
properties: "rotation"
|
||||||
|
running: BluetoothManager.defaultAdapter.discovering
|
||||||
|
target: scanButtonText
|
||||||
|
to: 360
|
||||||
|
|
||||||
|
onStopped: {
|
||||||
|
scanButton.rotation = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
|
clip: true
|
||||||
|
model: BluetoothManager.getDevicesList()
|
||||||
|
spacing: 5
|
||||||
|
|
||||||
|
delegate: Item {
|
||||||
|
id: deviceRoot
|
||||||
|
|
||||||
|
required property real index
|
||||||
|
required property BluetoothDevice modelData
|
||||||
|
|
||||||
|
height: 55
|
||||||
|
width: ListView.view.width
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: containerBox
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
clip: true
|
||||||
|
color: Colors.peach
|
||||||
|
radius: 7
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
color: Colors.green
|
||||||
|
implicitHeight: parent.height - 10
|
||||||
|
implicitWidth: parent.width * (deviceRoot.modelData.batteryAvailable == true
|
||||||
|
? deviceRoot.modelData.battery : 0) - 10
|
||||||
|
opacity: 0.7
|
||||||
|
radius: 7
|
||||||
|
visible: deviceRoot.modelData.batteryAvailable == true
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors {
|
||||||
|
bottomMargin: 4
|
||||||
|
fill: parent
|
||||||
|
leftMargin: 4
|
||||||
|
rightMargin: 4
|
||||||
|
topMargin: 4
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.preferredWidth: height
|
||||||
|
color: deviceRoot.modelData.connected ? Colors.green : Qt.lighter(Colors.peach, 1.25)
|
||||||
|
radius: 5
|
||||||
|
|
||||||
|
CenteredText {
|
||||||
|
color: Colors.surface0
|
||||||
|
font.pointSize: 30
|
||||||
|
text: BluetoothManager.getIcon(deviceRoot.modelData.icon)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: Qt.lighter(Colors.peach, 1.15)
|
||||||
|
radius: 4
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
elide: Qt.ElideRight
|
||||||
|
text: deviceRoot.modelData.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
color: Colors.surface2
|
||||||
|
font.weight: 300
|
||||||
|
text: deviceRoot.modelData.address
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.preferredWidth: height
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: itemEntry
|
||||||
|
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: Colors.red
|
||||||
|
radius: 3
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: deleteButtonLoader
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
sourceComponent: forgetButton
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: ""
|
||||||
|
when: deviceRoot.modelData.connected == false
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
deleteButtonLoader.sourceComponent: forgetButton
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "connected"
|
||||||
|
when: deviceRoot.modelData.connected == true
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
deleteButtonLoader.sourceComponent: disconnectButton
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: disconnectButton
|
||||||
|
|
||||||
|
Item {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
onTapped: deviceRoot.modelData.disconnect()
|
||||||
|
}
|
||||||
|
|
||||||
|
CenteredText {
|
||||||
|
text: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: forgetButton
|
||||||
|
|
||||||
|
Item {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
onTapped: deviceRoot.modelData.forget()
|
||||||
|
}
|
||||||
|
|
||||||
|
CenteredText {
|
||||||
|
text: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: greenButton
|
||||||
|
|
||||||
|
property Component loadedItem: connectButton
|
||||||
|
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: Colors.green
|
||||||
|
radius: 3
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: ""
|
||||||
|
when: deviceRoot.modelData.paired == true
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
greenButton.color: Colors.green
|
||||||
|
greenButton.loadedItem: connectButton
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "unpaired"
|
||||||
|
when: deviceRoot.modelData.paired == false
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
greenButton.color: Colors.blue
|
||||||
|
greenButton.loadedItem: pairButton
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
anchors.fill: parent
|
||||||
|
sourceComponent: greenButton.loadedItem
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: connectButton
|
||||||
|
|
||||||
|
Item {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
CenteredText {
|
||||||
|
text: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
onTapped: deviceRoot.modelData.connect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: pairButton
|
||||||
|
|
||||||
|
Item {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
CenteredText {
|
||||||
|
text: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
onTapped: {
|
||||||
|
deviceRoot.modelData.pair();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
bottomMargin: 5
|
||||||
|
fill: parent
|
||||||
|
leftMargin: 5
|
||||||
|
rightMargin: 5
|
||||||
|
topMargin: 10 + root.topBarHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
Components/CenteredText.qml
Normal file
7
Components/CenteredText.qml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import QtQuick
|
||||||
|
import "../Color.js" as Colors
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
// Time.qml
|
|
||||||
|
|
||||||
// with this line our type becomes a Singleton
|
|
||||||
pragma Singleton
|
|
||||||
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Io
|
|
||||||
import QtQuick
|
|
||||||
|
|
||||||
// your singletons should always have Singleton as the type
|
|
||||||
Singleton {
|
|
||||||
id: root
|
|
||||||
property string time
|
|
||||||
property string day
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: timeProc
|
|
||||||
command: ["date", "+%T"]
|
|
||||||
running: true
|
|
||||||
|
|
||||||
stdout: StdioCollector {
|
|
||||||
onStreamFinished: root.time = this.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: dateProc
|
|
||||||
command: ["date", "+%A %B %d %Y"]
|
|
||||||
running: true
|
|
||||||
|
|
||||||
stdout: StdioCollector {
|
|
||||||
onStreamFinished: root.day = this.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
interval: 500
|
|
||||||
running: true
|
|
||||||
repeat: true
|
|
||||||
onTriggered: timeProc.running = true, dateProc.running = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
140
Components/Container.qml
Normal file
140
Components/Container.qml
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Effects
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
|
||||||
|
import "../Color.js" as Colors
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property double animOffset: 0
|
||||||
|
property color boxColor: Colors.surface0
|
||||||
|
property double boxHeight: 28
|
||||||
|
property double boxRadius: 9
|
||||||
|
property double boxWidth: 100
|
||||||
|
readonly property double calculatedTopMargin: {
|
||||||
|
if (root.exclusiveToScreen) {
|
||||||
|
if (Hyprland.focusedMonitor != root.exclusiveMonitor || forceHidden == true) {
|
||||||
|
return -4 - root.boxHeight - 5;
|
||||||
|
} else {
|
||||||
|
return visibleTopMargin;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return visibleTopMargin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
property Component defaultItem
|
||||||
|
required property HyprlandMonitor exclusiveMonitor
|
||||||
|
property bool exclusiveToScreen: false
|
||||||
|
property bool forceHidden: false
|
||||||
|
property alias hover: hoverHandler
|
||||||
|
property alias rect: container
|
||||||
|
property alias stack: containerContent
|
||||||
|
property alias tap: tapHandler
|
||||||
|
property double visibleTopMargin: 0
|
||||||
|
|
||||||
|
implicitHeight: boxHeight
|
||||||
|
implicitWidth: boxWidth
|
||||||
|
|
||||||
|
Behavior on anchors.topMargin {
|
||||||
|
animation: defaultCurve
|
||||||
|
}
|
||||||
|
Behavior on boxHeight {
|
||||||
|
SpringAnimation {
|
||||||
|
damping: 0.3
|
||||||
|
spring: 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on boxRadius {
|
||||||
|
SpringAnimation {
|
||||||
|
damping: 0.3
|
||||||
|
spring: 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on boxWidth {
|
||||||
|
SpringAnimation {
|
||||||
|
damping: 0.3
|
||||||
|
spring: 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
topMargin: calculatedTopMargin
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberAnimation {
|
||||||
|
id: defaultCurve
|
||||||
|
|
||||||
|
duration: 200 + root.animOffset
|
||||||
|
easing: Easing.InOutBack
|
||||||
|
}
|
||||||
|
|
||||||
|
HoverHandler {
|
||||||
|
id: hoverHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
id: tapHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
RectangularShadow {
|
||||||
|
anchors.fill: container
|
||||||
|
blur: 30
|
||||||
|
color: Colors.mantle
|
||||||
|
offset.x: 7
|
||||||
|
offset.y: 3
|
||||||
|
radius: container.radius
|
||||||
|
spread: 10
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: container
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
clip: true
|
||||||
|
color: root.boxColor
|
||||||
|
radius: root.boxRadius
|
||||||
|
|
||||||
|
StackView {
|
||||||
|
id: containerContent
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
replaceEnter: Transition {
|
||||||
|
PropertyAnimation {
|
||||||
|
duration: 100
|
||||||
|
from: 0
|
||||||
|
property: "opacity"
|
||||||
|
to: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyAnimation {
|
||||||
|
duration: 100
|
||||||
|
from: -5
|
||||||
|
property: "anchors.topMargin"
|
||||||
|
to: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
replaceExit: Transition {
|
||||||
|
PropertyAnimation {
|
||||||
|
duration: 100
|
||||||
|
from: 1
|
||||||
|
property: "opacity"
|
||||||
|
to: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: containerContent.push(root.defaultItem)
|
||||||
|
onCurrentItemChanged: {
|
||||||
|
if (currentItem) {
|
||||||
|
// Dynamically center the incoming child to the StackView
|
||||||
|
currentItem.anchors.horizontalCenter = containerContent.horizontalCenter;
|
||||||
|
currentItem.anchors.verticalCenter = containerContent.verticalCenter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
23
Components/MidpointGradient.qml
Normal file
23
Components/MidpointGradient.qml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import QtQuick
|
||||||
|
|
||||||
|
Gradient {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property color color
|
||||||
|
property double midpoint: 0.6
|
||||||
|
|
||||||
|
GradientStop {
|
||||||
|
color: "transparent"
|
||||||
|
position: 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
GradientStop {
|
||||||
|
color: "transparent"
|
||||||
|
position: root.midpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
GradientStop {
|
||||||
|
color: root.color
|
||||||
|
position: 1.0
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
import Quickshell
|
|
||||||
import Quickshell.Hyprland
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Controls
|
|
||||||
import QtQuick.Effects
|
|
||||||
import "Color.js" as Colors
|
|
||||||
|
|
||||||
import "./Pill"
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
required property HyprlandMonitor monitor
|
|
||||||
id: container
|
|
||||||
state: ""
|
|
||||||
visible: true
|
|
||||||
|
|
||||||
property bool shown: monitor !== null && monitor.focused
|
|
||||||
|
|
||||||
Behavior on anchors.topMargin {
|
|
||||||
SmoothedAnimation { duration: 70; easing.type: Easing.OutBounce }
|
|
||||||
}
|
|
||||||
|
|
||||||
opacity: shown ? 1 : 0
|
|
||||||
|
|
||||||
Behavior on opacity {
|
|
||||||
NumberAnimation {duration: 50}
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
top: parent.top
|
|
||||||
topMargin: shown ? 5 : -implicitHeight
|
|
||||||
horizontalCenter: parent.horizontalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: mouseArea
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
onClicked: container.state == 'expanded' ? container.state = "" : container.state = 'expanded';
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
implicitWidth: 130
|
|
||||||
implicitHeight: 30
|
|
||||||
|
|
||||||
radius: 30
|
|
||||||
|
|
||||||
property real gradientMidpoint: 0.4
|
|
||||||
|
|
||||||
gradient: Gradient {
|
|
||||||
GradientStop { position: 0.0; color: Colors.surface0 }
|
|
||||||
GradientStop { position: container.gradientMidpoint; color: Colors.surface0 }
|
|
||||||
GradientStop { position: 1.0; color: Colors.surface2 }
|
|
||||||
}
|
|
||||||
|
|
||||||
border {color: Colors.lavender; width: 2}
|
|
||||||
|
|
||||||
component SmoothAnim: SpringAnimation {
|
|
||||||
spring: 3
|
|
||||||
mass: 0.5
|
|
||||||
damping: 0.18
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on implicitHeight {
|
|
||||||
SmoothAnim {}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on implicitWidth {
|
|
||||||
SmoothAnim {}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on gradientMidpoint {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: 100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
states: [
|
|
||||||
State {
|
|
||||||
name: ""
|
|
||||||
StateChangeScript {
|
|
||||||
script: mainLoader.replace(defaultComponent)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
State {
|
|
||||||
name: "expanded"
|
|
||||||
StateChangeScript {
|
|
||||||
script: mainLoader.replace(expandedComponent)
|
|
||||||
}
|
|
||||||
PropertyChanges { container.gradientMidpoint: 0.7}
|
|
||||||
PropertyChanges { container.implicitHeight: 130}
|
|
||||||
PropertyChanges { container.implicitWidth: 300}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
StackView {
|
|
||||||
id: mainLoader
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: mouseAreaStack
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
|
|
||||||
// FIX part 1: Prevent internal StackView items from changing cursor grab
|
|
||||||
propagateComposedEvents: true
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
container.state == 'expanded' ? container.state = "" : container.state = 'expanded';
|
|
||||||
}
|
|
||||||
|
|
||||||
onExited: {
|
|
||||||
container.state = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enabled:false
|
|
||||||
|
|
||||||
initialItem: defaultComponent
|
|
||||||
|
|
||||||
// Custom animations for switching components
|
|
||||||
replaceEnter: Transition {
|
|
||||||
PropertyAnimation { property: "opacity"; from: 0; to: 1; duration: 100 }
|
|
||||||
PropertyAnimation { property: "scale"; from: 0.9; to: 1.0; duration: 100 }
|
|
||||||
}
|
|
||||||
replaceExit: Transition {
|
|
||||||
PropertyAnimation { property: "opacity"; from: 1; to: 0; duration: 100 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: defaultComponent
|
|
||||||
Default {}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: expandedComponent
|
|
||||||
Expanded {}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
import Quickshell
|
|
||||||
import Quickshell.Hyprland
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Controls
|
|
||||||
import "../Color.js" as Colors
|
|
||||||
import "../"
|
|
||||||
|
|
||||||
Item {
|
|
||||||
Text {
|
|
||||||
font.family: "FiraMono Nerd Font"
|
|
||||||
anchors.centerIn: parent
|
|
||||||
font.pixelSize: 15
|
|
||||||
color: Colors.text
|
|
||||||
text: Clock.time
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
import Quickshell
|
|
||||||
import Quickshell.Hyprland
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import "../Color.js" as Colors
|
|
||||||
import "../"
|
|
||||||
|
|
||||||
Item {
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
Column {
|
|
||||||
spacing: 5
|
|
||||||
anchors.centerIn: parent
|
|
||||||
|
|
||||||
Text {
|
|
||||||
font.family: "FiraMono Nerd Font"
|
|
||||||
font.pixelSize: 40
|
|
||||||
color: Colors.text
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
text: Clock.time
|
|
||||||
}
|
|
||||||
Text {
|
|
||||||
font.family: "FiraMono Nerd Font"
|
|
||||||
color: Colors.subtext0
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
text: Clock.day
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
13
Components/StyledText.qml
Normal file
13
Components/StyledText.qml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import QtQuick
|
||||||
|
import "../Color.js" as Colors
|
||||||
|
|
||||||
|
Text {
|
||||||
|
color: Colors.base
|
||||||
|
elide: Text.ElideRight
|
||||||
|
|
||||||
|
font {
|
||||||
|
family: "FiraMono Nerd Font"
|
||||||
|
pointSize: 12
|
||||||
|
weight: 600
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
pragma ComponentBehavior: Bound
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
|
||||||
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Hyprland
|
|
||||||
|
|
||||||
import "./Utils"
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
id: utilsContainer
|
|
||||||
|
|
||||||
required property HyprlandMonitor monitor
|
|
||||||
property bool shown: monitor !== null && monitor.focused
|
|
||||||
|
|
||||||
opacity: shown ? 1 : 0
|
|
||||||
state: ""
|
|
||||||
|
|
||||||
Behavior on anchors.topMargin {
|
|
||||||
SmoothedAnimation {
|
|
||||||
duration: 300
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Behavior on opacity {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: 50
|
|
||||||
}
|
|
||||||
}
|
|
||||||
states: [
|
|
||||||
State {
|
|
||||||
name: ""
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
right: parent.right
|
|
||||||
rightMargin: 7
|
|
||||||
top: parent.top
|
|
||||||
topMargin: shown ? -33 : -40
|
|
||||||
}
|
|
||||||
|
|
||||||
Battery {}
|
|
||||||
// Mpris {}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
import QtQuick
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Services.UPower
|
|
||||||
|
|
||||||
import "../Color.js" as Colors
|
|
||||||
|
|
||||||
import "./"
|
|
||||||
|
|
||||||
Container {
|
|
||||||
id: batteryRoot
|
|
||||||
|
|
||||||
boxColor: Colors.green
|
|
||||||
boxState: ""
|
|
||||||
sourceComponent: batteryClosed
|
|
||||||
visible: UPower.devices[0] ? true : false
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
enabled: true
|
|
||||||
hoverEnabled: true
|
|
||||||
propagateComposedEvents: true
|
|
||||||
|
|
||||||
onClicked: batteryRoot.boxState == "" ? batteryRoot.boxState = "open" : batteryRoot.boxState = ""
|
|
||||||
onExited: batteryRoot.boxState = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: batteryClosed
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: batteryRoot
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
Text {
|
|
||||||
color: Colors.base
|
|
||||||
text: "something"
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
bottom: parent.bottom
|
|
||||||
horizontalCenter: parent.horizontalCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import Quickshell
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: container
|
|
||||||
|
|
||||||
required property color boxColor
|
|
||||||
property double boxHeight
|
|
||||||
property double boxRadius
|
|
||||||
required property string boxState
|
|
||||||
property double boxWidth
|
|
||||||
property double openHeight
|
|
||||||
property double openWidth
|
|
||||||
required property Component sourceComponent
|
|
||||||
|
|
||||||
Layout.topMargin: 0
|
|
||||||
implicitHeight: boxHeight || 50
|
|
||||||
implicitWidth: boxWidth || 30
|
|
||||||
state: boxState
|
|
||||||
|
|
||||||
Behavior on anchors.topMargin {
|
|
||||||
SmoothAnim {}
|
|
||||||
}
|
|
||||||
Behavior on implicitHeight {
|
|
||||||
SmoothAnim {}
|
|
||||||
}
|
|
||||||
Behavior on implicitWidth {
|
|
||||||
SmoothAnim {}
|
|
||||||
}
|
|
||||||
states: [
|
|
||||||
State {
|
|
||||||
name: ""
|
|
||||||
},
|
|
||||||
State {
|
|
||||||
name: "open"
|
|
||||||
|
|
||||||
PropertyChanges {
|
|
||||||
container.Layout.topMargin: 35
|
|
||||||
container.implicitHeight: openHeight || 150
|
|
||||||
container.implicitWidth: openWidth || 200
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: mainBackground
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
color: container.boxColor
|
|
||||||
radius: container.boxRadius || 10
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
anchors.fill: parent
|
|
||||||
sourceComponent: container.sourceComponent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
component SmoothAnim: SpringAnimation {
|
|
||||||
damping: 0.18
|
|
||||||
mass: 0.5
|
|
||||||
spring: 3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
import QtQuick
|
|
||||||
import Quickshell
|
|
||||||
|
|
||||||
Item {}
|
|
||||||
@@ -1,290 +0,0 @@
|
|||||||
pragma ComponentBehavior: Bound
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Effects
|
|
||||||
import QtQuick.Layouts
|
|
||||||
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Hyprland
|
|
||||||
|
|
||||||
import "Color.js" as Colors
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: workspaceRowContainer
|
|
||||||
|
|
||||||
required property HyprlandMonitor monitor
|
|
||||||
property int textBottomMargin: 0
|
|
||||||
|
|
||||||
function getNextEmptyWorkspaceId() {
|
|
||||||
let maxId = 0;
|
|
||||||
let workspaces = Hyprland.workspaces.values;
|
|
||||||
|
|
||||||
for (let i = 0; i < workspaces.length; i++) {
|
|
||||||
let ws = workspaces[i];
|
|
||||||
// Look at all numerical workspaces globally (ignoring special workspaces like scratchpads)
|
|
||||||
if (ws.id > maxId && ws.id < 99) {
|
|
||||||
maxId = ws.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the next global workspace ID (e.g., if max is 3, returns 4)
|
|
||||||
console.log(maxId + 1);
|
|
||||||
return maxId === 0 ? 1 : maxId + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
implicitHeight: 65
|
|
||||||
implicitWidth: 200
|
|
||||||
state: ""
|
|
||||||
|
|
||||||
Behavior on anchors.topMargin {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: 100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
states: [
|
|
||||||
State {
|
|
||||||
name: ""
|
|
||||||
// When not hovered, stay at default
|
|
||||||
when: !workspaceHoverHandler.hovered
|
|
||||||
|
|
||||||
PropertyChanges {
|
|
||||||
workspaceRowContainer.anchors.topMargin: -33
|
|
||||||
}
|
|
||||||
},
|
|
||||||
State {
|
|
||||||
name: "hovered"
|
|
||||||
// Keep the workspace dropped whenever hovered is true
|
|
||||||
when: workspaceHoverHandler.hovered
|
|
||||||
|
|
||||||
PropertyChanges {
|
|
||||||
workspaceRowContainer.anchors.topMargin: -20
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyChanges {
|
|
||||||
workspaceRowContainer.textBottomMargin: 7
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
Behavior on textBottomMargin {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: 80
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
left: parent.left
|
|
||||||
leftMargin: 15
|
|
||||||
top: parent.top
|
|
||||||
topMargin: -33
|
|
||||||
}
|
|
||||||
|
|
||||||
HoverHandler {
|
|
||||||
id: workspaceHoverHandler
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: workspaceRow
|
|
||||||
|
|
||||||
spacing: 5
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: Hyprland.workspaces.values
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: selectorContainer
|
|
||||||
|
|
||||||
property HyprlandWorkspace activeWorkspace: workspaceRowContainer.monitor.activeWorkspace
|
|
||||||
property HyprlandWorkspace currentWorkspace: Hyprland.workspaces.values[index]
|
|
||||||
property HyprlandWorkspace globalFocusedWorkspace: Hyprland.focusedWorkspace
|
|
||||||
required property int index
|
|
||||||
|
|
||||||
function getImplicitWidth() {
|
|
||||||
let implicitWidth = 25;
|
|
||||||
|
|
||||||
if (workspaceRowContainer.state == "hovered") {
|
|
||||||
implicitWidth += 5;
|
|
||||||
if (currentWorkspace.focused) {
|
|
||||||
implicitWidth += 20;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return implicitWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
function shouldBeVisible() {
|
|
||||||
let isSpecialWorkspace = !selectorContainer.currentWorkspace.name.includes("special:");
|
|
||||||
let isCurrentMonitor = Hyprland.workspaces.values[index].monitor
|
|
||||||
== workspaceRowContainer.monitor;
|
|
||||||
return isSpecialWorkspace && isCurrentMonitor;
|
|
||||||
}
|
|
||||||
|
|
||||||
implicitHeight: 50
|
|
||||||
implicitWidth: getImplicitWidth()
|
|
||||||
visible: shouldBeVisible()
|
|
||||||
|
|
||||||
Behavior on anchors.topMargin {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: 100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Behavior on implicitWidth {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: 100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
states: [
|
|
||||||
State {
|
|
||||||
name: ""
|
|
||||||
when: !selectorHoverHandler.hovered
|
|
||||||
|
|
||||||
PropertyChanges {
|
|
||||||
selectorContainer.anchors.topMargin: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
State {
|
|
||||||
name: "individualHovered"
|
|
||||||
when: selectorHoverHandler.hovered
|
|
||||||
|
|
||||||
PropertyChanges {
|
|
||||||
selectorContainer.anchors.topMargin: 10
|
|
||||||
}
|
|
||||||
},
|
|
||||||
State {
|
|
||||||
name: "workspaceSwitched"
|
|
||||||
|
|
||||||
PropertyChanges {
|
|
||||||
selectorContainer.anchors.topMargin: 5
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
// onActiveWorkspaceChanged: {
|
|
||||||
// if (workspaceRowContainer.monitor.activeWorkspace.id == "1") {}
|
|
||||||
// if (workspaceRowContainer.monitor.activeWorkspace.id == "4") {}
|
|
||||||
// }
|
|
||||||
onGlobalFocusedWorkspaceChanged: {
|
|
||||||
if (globalFocusedWorkspace.name === currentWorkspace.name && globalFocusedWorkspace.monitor
|
|
||||||
=== workspaceRowContainer.monitor && workspaceRowContainer.monitor.activeWorkspace.name
|
|
||||||
=== currentWorkspace.name) {
|
|
||||||
selectorContainer.state = "workspaceSwitched";
|
|
||||||
switchFeedbackTimer.restart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: switchFeedbackTimer
|
|
||||||
|
|
||||||
interval: 200
|
|
||||||
repeat: false
|
|
||||||
|
|
||||||
onTriggered: selectorContainer.state = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
top: parent.top
|
|
||||||
topMargin: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
HoverHandler {
|
|
||||||
id: selectorHoverHandler
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: selectorMouseArea
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
propagateComposedEvents: true
|
|
||||||
|
|
||||||
onClicked: selectorContainer.currentWorkspace.activate()
|
|
||||||
}
|
|
||||||
|
|
||||||
RectangularShadow {
|
|
||||||
anchors.fill: selector
|
|
||||||
blur: 20
|
|
||||||
color: Colors.crust
|
|
||||||
offset.x: 3
|
|
||||||
offset.y: 3
|
|
||||||
radius: selector.radius
|
|
||||||
spread: 7
|
|
||||||
z: -1
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: selector
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
color: selectorContainer.currentWorkspace.focused ? Colors.mauve :
|
|
||||||
workspaceRowContainer.monitor.activeWorkspace
|
|
||||||
== selectorContainer.currentWorkspace ? Colors.lavender : Colors.overlay1
|
|
||||||
radius: 8
|
|
||||||
state: ""
|
|
||||||
z: 1
|
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
ColorAnimation {
|
|
||||||
duration: 100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: workspaceIdentifier
|
|
||||||
|
|
||||||
font.family: "FiraMono Nerd Font"
|
|
||||||
font.pixelSize: workspaceRowContainer.state == "hovered" ? 15 : 13
|
|
||||||
text: selectorContainer.currentWorkspace.name
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
bottom: parent.bottom
|
|
||||||
bottomMargin: workspaceRowContainer.textBottomMargin
|
|
||||||
horizontalCenter: parent.horizontalCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
implicitHeight: 40
|
|
||||||
implicitWidth: 20
|
|
||||||
|
|
||||||
Behavior on anchors.topMargin {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: 100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
top: parent.top
|
|
||||||
topMargin: workspaceRowContainer.state == "hovered" ? 0 : -10
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: newWorkspaceButton
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
onClicked: Hyprland.dispatch(`hl.dsp.focus({workspace =
|
|
||||||
${workspaceRowContainer.getNextEmptyWorkspaceId()}})`)
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
border.color: Colors.text
|
|
||||||
border.width: 2
|
|
||||||
color: Colors.surface2
|
|
||||||
radius: 10
|
|
||||||
|
|
||||||
Text {
|
|
||||||
color: Colors.text
|
|
||||||
font.family: "FiraMono Nerd Font"
|
|
||||||
font.pixelSize: 20
|
|
||||||
text: "+"
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
bottom: parent.bottom
|
|
||||||
horizontalCenter: parent.horizontalCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
69
Services/BluetoothManager.qml
Normal file
69
Services/BluetoothManager.qml
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
pragma Singleton
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Bluetooth
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property BluetoothAdapter defaultAdapter: Bluetooth.defaultAdapter
|
||||||
|
property string defaultAdapterName: Bluetooth.defaultAdapter.adapterId
|
||||||
|
|
||||||
|
function getConnected() {
|
||||||
|
let deviceList = getDevicesList();
|
||||||
|
for (let device in deviceList) {
|
||||||
|
let currentDevice = deviceList[device];
|
||||||
|
if (currentDevice.connected == true) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDevicesList() {
|
||||||
|
return root.defaultAdapter.devices.values;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getIcon(name) {
|
||||||
|
const icons = {
|
||||||
|
"audio-card": "",
|
||||||
|
"audio-input-microphone": "",
|
||||||
|
"audio-headphones": "",
|
||||||
|
"audio-headset": "",
|
||||||
|
"battery": "",
|
||||||
|
"camera-photo": "",
|
||||||
|
"computer": "",
|
||||||
|
"input-keyboard": "",
|
||||||
|
"input-mouse": "",
|
||||||
|
"input-gaming": "",
|
||||||
|
"phone": ""
|
||||||
|
};
|
||||||
|
|
||||||
|
return icons[name] || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function pairTrustConnect(device) {
|
||||||
|
device.pair();
|
||||||
|
device.trusted = true;
|
||||||
|
device.connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleDiscover() {
|
||||||
|
if (defaultAdapter.discovering == true) {
|
||||||
|
defaultAdapter.discovering = false;
|
||||||
|
} else {
|
||||||
|
defaultAdapter.discovering = true;
|
||||||
|
discoveringTimeout.running = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: discoveringTimeout
|
||||||
|
|
||||||
|
interval: 15000
|
||||||
|
repeat: false
|
||||||
|
running: false
|
||||||
|
|
||||||
|
onTriggered: defaultAdapter.discovering = false
|
||||||
|
}
|
||||||
|
}
|
||||||
27
Services/MprisManager.qml
Normal file
27
Services/MprisManager.qml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
pragma Singleton
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Services.Mpris
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property MprisPlayer defaultPlayer: Mpris.players.values[0]
|
||||||
|
property real pos: defaultPlayer.position / defaultPlayer.length
|
||||||
|
|
||||||
|
function getPlaying() {
|
||||||
|
if (!defaultPlayer) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return defaultPlayer.playbackState == MprisPlaybackState.Playing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function prev() {
|
||||||
|
defaultPlayer.previous();
|
||||||
|
}
|
||||||
|
|
||||||
|
function skip() {
|
||||||
|
defaultPlayer.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
32
Services/NotificationManager.qml
Normal file
32
Services/NotificationManager.qml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
pragma Singleton
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Services.Notifications
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property alias notif: server
|
||||||
|
|
||||||
|
function getLatestNotification() {
|
||||||
|
let notificationList = server.trackedNotifications.values;
|
||||||
|
let len = notificationList.length;
|
||||||
|
if (len <= 0) {
|
||||||
|
len = 1;
|
||||||
|
}
|
||||||
|
let latestNotification = notificationList[len - 1];
|
||||||
|
return latestNotification;
|
||||||
|
}
|
||||||
|
|
||||||
|
NotificationServer {
|
||||||
|
id: server
|
||||||
|
|
||||||
|
actionsSupported: true
|
||||||
|
bodyMarkupSupported: true
|
||||||
|
bodySupported: true
|
||||||
|
|
||||||
|
onNotification: notification => {
|
||||||
|
notification.tracked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
49
Services/Time.qml
Normal file
49
Services/Time.qml
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
// Time.qml
|
||||||
|
|
||||||
|
// with this line our type becomes a Singleton
|
||||||
|
pragma Singleton
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
|
||||||
|
// your singletons should always have Singleton as the type
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string date
|
||||||
|
property string time
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: timeProc
|
||||||
|
|
||||||
|
command: ["date", "+%T"]
|
||||||
|
running: true
|
||||||
|
|
||||||
|
stdout: StdioCollector {
|
||||||
|
onStreamFinished: root.time = this.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: dateProc
|
||||||
|
|
||||||
|
command: ["date", "+%A %B %d %Y"]
|
||||||
|
running: true
|
||||||
|
|
||||||
|
stdout: StdioCollector {
|
||||||
|
onStreamFinished: root.date = this.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 1000
|
||||||
|
repeat: true
|
||||||
|
running: true
|
||||||
|
|
||||||
|
onTriggered: {
|
||||||
|
timeProc.running = true;
|
||||||
|
dateProc.running = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
79
Services/WorkspaceManager.qml
Normal file
79
Services/WorkspaceManager.qml
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
pragma Singleton
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
function activateNextFreeWorkspace() {
|
||||||
|
let nextFree = getNextFreeWorkspace();
|
||||||
|
activateWorkspaceById(nextFree);
|
||||||
|
}
|
||||||
|
|
||||||
|
function activateWorkspaceById(id) {
|
||||||
|
Hyprland.dispatch(`hl.dsp.focus({workspace = ${id}})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAllNumberedWorkspaces() {
|
||||||
|
let allWorkspaces = Hyprland.workspaces.values;
|
||||||
|
let filteredWorkspaces = [];
|
||||||
|
for (let workspace in allWorkspaces) {
|
||||||
|
let currentWorkspace = allWorkspaces[workspace];
|
||||||
|
if (!currentWorkspace.name.includes("special")) {
|
||||||
|
if (currentWorkspace) {
|
||||||
|
filteredWorkspaces.push(currentWorkspace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filteredWorkspaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNextFreeWorkspace() {
|
||||||
|
let workspaceList = getAllNumberedWorkspaces();
|
||||||
|
|
||||||
|
if (workspaceList[workspaceList.length - 1].id == workspaceList.length) {
|
||||||
|
return workspaceList.length + 1;
|
||||||
|
} else {
|
||||||
|
let prevWorkspace = 0;
|
||||||
|
for (let workspace in workspaceList) {
|
||||||
|
let currentWorkspace = workspaceList[workspace];
|
||||||
|
if (currentWorkspace.id != (prevWorkspace + 1)) {
|
||||||
|
return currentWorkspace.id - 1;
|
||||||
|
} else {
|
||||||
|
prevWorkspace = currentWorkspace.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNumberOfWorkspaces(monitor) {
|
||||||
|
let workspaceList = getWorkspacesForMonitor(monitor);
|
||||||
|
return workspaceList.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWorkspaceState(workspace) {
|
||||||
|
if (workspace.focused == true) {
|
||||||
|
return "focused";
|
||||||
|
} else if (workspace.active == true) {
|
||||||
|
return "active";
|
||||||
|
} else {
|
||||||
|
return "inactive";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWorkspacesForMonitor(monitor) {
|
||||||
|
let allWorkspaces = getAllNumberedWorkspaces();
|
||||||
|
let monitorWorkspaces = [];
|
||||||
|
|
||||||
|
for (let workspace in allWorkspaces) {
|
||||||
|
let currentWorkspace = allWorkspaces[workspace];
|
||||||
|
if (currentWorkspace.monitor == monitor) {
|
||||||
|
if (currentWorkspace) {
|
||||||
|
monitorWorkspaces.push(currentWorkspace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return monitorWorkspaces;
|
||||||
|
}
|
||||||
|
}
|
||||||
6
Services/qmldir
Normal file
6
Services/qmldir
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
module Services
|
||||||
|
singleton Time 1.0 Time.qml
|
||||||
|
singleton NotificationManager 1.0 NotificationManager.qml
|
||||||
|
singleton WorkspaceManager 1.0 WorkspaceManager.qml
|
||||||
|
singleton BluetoothManager 1.0 BluetoothManager.qml
|
||||||
|
singleton MprisManager 1.0 MprisManager.qml
|
||||||
65
devenv.lock
Normal file
65
devenv.lock
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"devenv": {
|
||||||
|
"locked": {
|
||||||
|
"dir": "src/modules",
|
||||||
|
"lastModified": 1782153911,
|
||||||
|
"narHash": "sha256-Z7BG4cSJX1ybJeZztEMV8WlE6GrXJsSd34x9eHvpzU8=",
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "devenv",
|
||||||
|
"rev": "d894e487bb23ed87e0555d2158710844bde65322",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"dir": "src/modules",
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "devenv",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs-src": "nixpkgs-src"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1782132010,
|
||||||
|
"narHash": "sha256-ZnAVHdVrotp80iIMm5CSR1fdxPlw7Uwmwxb+O/wsgZ8=",
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "devenv-nixpkgs",
|
||||||
|
"rev": "12866ae2dddbc0ab8b329915f8072bb9c75bde89",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "cachix",
|
||||||
|
"ref": "rolling",
|
||||||
|
"repo": "devenv-nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs-src": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1781607440,
|
||||||
|
"narHash": "sha256-rxO+uc/KFbSJp+pgyXRuAX6QlG9hJdnt0BXpEQRXY+U=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "3e41b24abd260e8f71dbe2f5737d24122f972158",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"devenv": "devenv",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
17
devenv.nix
Normal file
17
devenv.nix
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
{
|
||||||
|
env.DEVSHELL_NAME = " devenv/#fab387| quickshell/green";
|
||||||
|
|
||||||
|
packages = with pkgs; [
|
||||||
|
quickshell
|
||||||
|
kdePackages.qtdeclarative
|
||||||
|
];
|
||||||
|
|
||||||
|
processes = {
|
||||||
|
qs.exec = "quickshell -p .";
|
||||||
|
};
|
||||||
|
}
|
||||||
4
devenv.yaml
Normal file
4
devenv.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# yaml-language-server: $schema=https://devenv.sh/devenv.schema.json
|
||||||
|
inputs:
|
||||||
|
nixpkgs:
|
||||||
|
url: github:cachix/devenv-nixpkgs/rolling
|
||||||
61
flake.lock
generated
61
flake.lock
generated
@@ -1,61 +0,0 @@
|
|||||||
{
|
|
||||||
"nodes": {
|
|
||||||
"nixpkgs": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1780243769,
|
|
||||||
"narHash": "sha256-x5UQuRsH3MqI0U9afaXSNqzTPSeZlRLvFAav2Ux1pNw=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "331800de5053fcebacf6813adb5db9c9dca22a0c",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixos-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": "nixpkgs",
|
|
||||||
"utils": "utils"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"systems": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1681028828,
|
|
||||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"utils": {
|
|
||||||
"inputs": {
|
|
||||||
"systems": "systems"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1731533236,
|
|
||||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": "root",
|
|
||||||
"version": 7
|
|
||||||
}
|
|
||||||
42
flake.nix
42
flake.nix
@@ -1,42 +0,0 @@
|
|||||||
{
|
|
||||||
description = "A simple Rust development environment";
|
|
||||||
|
|
||||||
inputs = {
|
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
|
||||||
utils.url = "github:numtide/flake-utils";
|
|
||||||
};
|
|
||||||
|
|
||||||
outputs =
|
|
||||||
{
|
|
||||||
self,
|
|
||||||
nixpkgs,
|
|
||||||
utils,
|
|
||||||
}:
|
|
||||||
utils.lib.eachDefaultSystem (
|
|
||||||
system:
|
|
||||||
let
|
|
||||||
pkgs = import nixpkgs { inherit system; };
|
|
||||||
in
|
|
||||||
{
|
|
||||||
devShells.default = pkgs.mkShell {
|
|
||||||
|
|
||||||
name = "flake";
|
|
||||||
|
|
||||||
buildInputs = with pkgs; [
|
|
||||||
quickshell
|
|
||||||
kdePackages.qtdeclarative
|
|
||||||
];
|
|
||||||
|
|
||||||
# Environment variables
|
|
||||||
shellHook = ''
|
|
||||||
export DEVSHELL_NAME=" flake/#89dceb| quickshell/green"
|
|
||||||
|
|
||||||
# Trigger zsh
|
|
||||||
if [[ -z "$ZSH_VERSION" ]]; then
|
|
||||||
exec zsh
|
|
||||||
fi
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user