dcontent: create bluetooth panel

This commit is contained in:
2 * r + 2 * t 2025-07-23 23:04:28 +10:00
parent 1835271c28
commit 982a5a3e8d
9 changed files with 372 additions and 3 deletions

View file

@ -11,6 +11,7 @@ Singleton {
property alias bar: adapter.bar
property alias border: adapter.border
property alias dashboard: adapter.dashboard
property alias dcontent: adapter.dcontent
property alias launcher: adapter.launcher
property alias notifs: adapter.notifs
property alias osd: adapter.osd
@ -33,6 +34,7 @@ Singleton {
property BarConfig bar: BarConfig {}
property BorderConfig border: BorderConfig {}
property DashboardConfig dashboard: DashboardConfig {}
property DContentConfig dcontent: DContentConfig {}
property LauncherConfig launcher: LauncherConfig {}
property NotifsConfig notifs: NotifsConfig {}
property OsdConfig osd: OsdConfig {}

11
config/DContentConfig.qml Normal file
View file

@ -0,0 +1,11 @@
import Quickshell.Io
JsonObject {
property Sizes sizes: Sizes {}
component Sizes: JsonObject {
property real heightMult: 0.7
property real ratio: 16 / 9
property real expandedNavWidth: 180
}
}

View file

@ -8,7 +8,7 @@ ShapePath {
required property Wrapper wrapper
required property bool invertBottomRounding
readonly property real rounding: Config.border.rounding
readonly property real rounding: wrapper.isDetached ? Appearance.rounding.normal : Config.border.rounding
readonly property bool flatten: wrapper.width < rounding * 2
readonly property real roundingX: flatten ? wrapper.width / 2 : rounding
property real ibr: invertBottomRounding ? -1 : 1

View file

@ -12,6 +12,8 @@ import QtQuick.Layouts
ColumnLayout {
id: root
required property Item wrapper
spacing: Appearance.spacing.small
StyledText {
@ -170,6 +172,42 @@ ColumnLayout {
}
}
StyledRect {
Layout.topMargin: Appearance.spacing.small
implicitWidth: expandBtn.implicitWidth + Appearance.padding.normal * 2
implicitHeight: expandBtn.implicitHeight + Appearance.padding.small
radius: Appearance.rounding.normal
color: Colours.palette.m3primaryContainer
StateLayer {
color: Colours.palette.m3onPrimaryContainer
function onClicked(): void {
root.wrapper.detach("bluetooth");
}
}
RowLayout {
id: expandBtn
anchors.centerIn: parent
spacing: Appearance.spacing.small
StyledText {
Layout.leftMargin: Appearance.padding.smaller
text: qsTr("Open panel")
color: Colours.palette.m3onPrimaryContainer
}
MaterialIcon {
text: "chevron_right"
color: Colours.palette.m3onPrimaryContainer
font.pointSize: Appearance.font.size.large
}
}
}
component Toggle: RowLayout {
required property string label
property alias checked: toggle.checked

View file

@ -35,7 +35,9 @@ Item {
Popout {
name: "bluetooth"
source: "Bluetooth.qml"
sourceComponent: Bluetooth {
wrapper: root.wrapper
}
}
Popout {

View file

@ -3,6 +3,7 @@ pragma ComponentBehavior: Bound
import qs.services
import qs.config
import qs.modules.windowinfo
import qs.modules.detachedcontent
import Quickshell
import Quickshell.Wayland
import Quickshell.Hyprland
@ -21,6 +22,7 @@ Item {
property bool hasCurrent
property string detachedMode
property string queuedMode
readonly property bool isDetached: detachedMode.length > 0
property int animLength: Appearance.anim.durations.normal
@ -28,7 +30,12 @@ Item {
function detach(mode: string): void {
animLength = Appearance.anim.durations.large;
detachedMode = mode;
if (mode === "winfo") {
detachedMode = mode;
} else {
detachedMode = "any";
queuedMode = mode;
}
focus = true;
}
@ -86,6 +93,19 @@ Item {
}
}
Comp {
id: detachedContent
shouldBeActive: root.detachedMode === "any"
asynchronous: true
anchors.centerIn: parent
sourceComponent: DetachedContent {
screen: root.screen
active: root.queuedMode
}
}
Behavior on x {
Anim {
duration: root.animLength

View file

@ -0,0 +1,98 @@
pragma ComponentBehavior: Bound
import qs.widgets
import qs.services
import qs.config
import Quickshell
import QtQuick
import QtQuick.Layouts
import QtQuick.Effects
Item {
id: root
required property ShellScreen screen
property alias active: session.active
readonly property Session session: Session {
id: session
}
implicitWidth: implicitHeight * Config.dcontent.sizes.ratio
implicitHeight: screen.height * Config.dcontent.sizes.heightMult
GridLayout {
anchors.fill: parent
rows: 2
columns: 2
rowSpacing: 0
columnSpacing: 0
StyledRect {
Layout.fillHeight: true
Layout.rowSpan: 2
topLeftRadius: Appearance.rounding.normal
bottomLeftRadius: Appearance.rounding.normal
implicitWidth: navRail.implicitWidth
color: Colours.palette.m3surfaceContainer
NavRail {
id: navRail
session: root.session
}
}
StyledRect {
Layout.fillWidth: true
implicitHeight: 50
topRightRadius: Appearance.rounding.normal
color: Colours.palette.m3surfaceContainer
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
StyledText {
anchors.centerIn: parent
text: qsTr("Work in progress")
color: Colours.palette.m3outline
font.pointSize: Appearance.font.size.extraLarge
font.weight: 500
}
StyledRect {
anchors.fill: parent
color: Colours.palette.m3surfaceContainer
bottomRightRadius: Appearance.rounding.normal
layer.enabled: true
layer.effect: MultiEffect {
maskSource: mask
maskEnabled: true
maskInverted: true
maskThresholdMin: 0.5
maskSpreadAtMin: 1
}
}
Item {
id: mask
anchors.fill: parent
layer.enabled: true
visible: false
Rectangle {
anchors.fill: parent
anchors.margins: Appearance.padding.normal
anchors.topMargin: 0
anchors.leftMargin: 0
radius: Appearance.rounding.small
}
}
}
}
}

View file

@ -0,0 +1,193 @@
pragma ComponentBehavior: Bound
import qs.widgets
import qs.services
import qs.config
import QtQuick
import QtQuick.Layouts
Item {
id: root
required property Session session
property bool expanded
implicitWidth: layout.implicitWidth + Appearance.padding.large * 4
implicitHeight: layout.implicitHeight + Appearance.padding.large * 2
ColumnLayout {
id: layout
anchors.centerIn: parent
spacing: Appearance.spacing.normal
states: State {
name: "expanded"
when: root.expanded
PropertyChanges {
layout.spacing: Appearance.spacing.small / 2
menuIcon.opacity: 0
menuIconExpanded.opacity: 1
menuIcon.rotation: 180
menuIconExpanded.rotation: 0
}
AnchorChanges {
target: menuIcon
anchors.horizontalCenter: undefined
}
AnchorChanges {
target: menuIconExpanded
anchors.horizontalCenter: undefined
}
}
transitions: Transition {
Anim {
properties: "spacing,opacity,rotation"
}
}
Item {
Layout.fillWidth: true
Layout.bottomMargin: Appearance.spacing.small / 2
implicitHeight: Math.max(menuIcon.implicitHeight, menuIconExpanded.implicitHeight) + Appearance.padding.normal * 2
StateLayer {
radius: Appearance.rounding.small
function onClicked(): void {
root.expanded = !root.expanded;
}
}
MaterialIcon {
id: menuIcon
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
text: "menu"
font.pointSize: Appearance.font.size.large
}
MaterialIcon {
id: menuIconExpanded
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
text: "menu_open"
font.pointSize: Appearance.font.size.large
opacity: 0
rotation: -180
}
}
NavItem {
icon: "settings_bluetooth"
label: "bluetooth"
}
}
component NavItem: Item {
id: item
required property string icon
required property string label
readonly property bool active: root.session.active === label
implicitWidth: background.implicitWidth
implicitHeight: background.implicitHeight + smallLabel.implicitHeight + smallLabel.anchors.topMargin
states: State {
name: "expanded"
when: root.expanded
PropertyChanges {
expandedLabel.opacity: 1
smallLabel.opacity: 0
background.implicitWidth: Config.dcontent.sizes.expandedNavWidth
background.implicitHeight: icon.implicitHeight + Appearance.padding.normal * 2
item.implicitHeight: background.implicitHeight
}
}
transitions: Transition {
Anim {
property: "opacity"
duration: Appearance.anim.durations.small
}
Anim {
properties: "implicitWidth,implicitHeight"
duration: Appearance.anim.durations.expressiveDefaultSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
}
}
StyledRect {
id: background
radius: Appearance.rounding.full
color: item.active ? Colours.palette.m3secondaryContainer : Colours.palette.m3surfaceContainer
implicitWidth: icon.implicitWidth + icon.anchors.leftMargin * 2
implicitHeight: icon.implicitHeight + Appearance.padding.small
StateLayer {
color: item.active ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface
function onClicked(): void {
root.session.active = item.label;
}
}
MaterialIcon {
id: icon
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: Appearance.padding.large
text: item.icon
color: item.active ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface
font.pointSize: Appearance.font.size.large
fill: item.active ? 1 : 0
Behavior on fill {
Anim {}
}
}
StyledText {
id: expandedLabel
anchors.left: icon.right
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: Appearance.spacing.small
opacity: 0
text: item.label
color: item.active ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface
font.capitalization: Font.Capitalize
}
StyledText {
id: smallLabel
anchors.horizontalCenter: icon.horizontalCenter
anchors.top: icon.bottom
anchors.topMargin: Appearance.spacing.small / 2
text: item.label
font.pointSize: Appearance.font.size.small
font.capitalization: Font.Capitalize
}
}
}
component Anim: NumberAnimation {
duration: Appearance.anim.durations.normal
easing.type: Easing.BezierSpline
easing.bezierCurve: Appearance.anim.curves.standard
}
}

View file

@ -0,0 +1,5 @@
import QtQuick
QtObject {
property string active
}