controlcenter: created dev panel for wireless testing

This commit is contained in:
ATMDA 2025-11-13 16:56:49 -05:00
parent 38c613a75e
commit baa10d6ccf
9 changed files with 747 additions and 0 deletions

View file

@ -0,0 +1,94 @@
pragma ComponentBehavior: Bound
import "."
import ".."
import qs.components
import qs.components.controls
import qs.services
import qs.config
import Quickshell
import QtQuick
import QtQuick.Layouts
Item {
id: root
required property ShellScreen screen
readonly property int rounding: floating ? 0 : Appearance.rounding.normal
property alias floating: session.floating
property alias active: session.active
property alias navExpanded: session.navExpanded
readonly property DevSession session: DevSession {
id: session
root: root
}
function close(): void {
}
implicitWidth: implicitHeight * Config.controlCenter.sizes.ratio
implicitHeight: screen.height * Config.controlCenter.sizes.heightMult
GridLayout {
anchors.fill: parent
rowSpacing: 0
columnSpacing: 0
rows: root.floating ? 2 : 1
columns: 2
Loader {
Layout.fillWidth: true
Layout.columnSpan: 2
asynchronous: true
active: root.floating
visible: active
sourceComponent: DevWindowTitle {
screen: root.screen
session: root.session
}
}
StyledRect {
Layout.fillHeight: true
topLeftRadius: root.rounding
bottomLeftRadius: root.rounding
implicitWidth: navRail.implicitWidth
color: Colours.tPalette.m3surfaceContainer
CustomMouseArea {
anchors.fill: parent
function onWheel(event: WheelEvent): void {
if (event.angleDelta.y < 0)
root.session.activeIndex = Math.min(root.session.activeIndex + 1, root.session.panes.length - 1);
else if (event.angleDelta.y > 0)
root.session.activeIndex = Math.max(root.session.activeIndex - 1, 0);
}
}
DevNavRail {
id: navRail
screen: root.screen
session: root.session
}
}
DevPanes {
Layout.fillWidth: true
Layout.fillHeight: true
topRightRadius: root.rounding
bottomRightRadius: root.rounding
session: root.session
}
}
}

View file

@ -0,0 +1,170 @@
pragma ComponentBehavior: Bound
import "."
import ".."
import qs.components
import qs.components.controls
import qs.components.containers
import qs.config
import Quickshell
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
Item {
id: root
required property DevSession session
anchors.fill: parent
ColumnLayout {
anchors.fill: parent
anchors.margins: Appearance.padding.large
spacing: Appearance.spacing.normal
StyledText {
text: qsTr("Debug Panel")
font.pointSize: Appearance.font.size.larger
font.weight: 500
}
// Action Buttons Section
StyledRect {
Layout.fillWidth: true
implicitHeight: buttonsLayout.implicitHeight + Appearance.padding.large * 2
radius: Appearance.rounding.normal
color: Colours.tPalette.m3surfaceContainer
ColumnLayout {
id: buttonsLayout
anchors.fill: parent
anchors.margins: Appearance.padding.large
spacing: Appearance.spacing.normal
StyledText {
text: qsTr("Actions")
font.pointSize: Appearance.font.size.normal
font.weight: 500
}
Flow {
Layout.fillWidth: true
spacing: Appearance.spacing.small
TextButton {
text: qsTr("Clear Log")
onClicked: {
debugOutput.text = "";
appendLog("Debug log cleared");
}
}
TextButton {
text: qsTr("Test Action")
onClicked: {
appendLog("Test action executed at " + new Date().toLocaleTimeString());
}
}
TextButton {
text: qsTr("Log Network State")
onClicked: {
appendLog("Network state:");
appendLog(" Active: " + (root.session.network.active ? "Yes" : "No"));
}
}
}
}
}
// Debug Output Section
StyledRect {
Layout.fillWidth: true
Layout.fillHeight: true
radius: Appearance.rounding.normal
color: Colours.tPalette.m3surfaceContainer
ColumnLayout {
anchors.fill: parent
anchors.margins: Appearance.padding.large
spacing: Appearance.spacing.small
RowLayout {
Layout.fillWidth: true
StyledText {
text: qsTr("Debug Output")
font.pointSize: Appearance.font.size.normal
font.weight: 500
}
Item {
Layout.fillWidth: true
}
TextButton {
text: qsTr("Copy")
onClicked: {
debugOutput.selectAll();
debugOutput.copy();
debugOutput.deselect();
appendLog("Output copied to clipboard");
}
}
}
StyledFlickable {
id: flickable
Layout.fillWidth: true
Layout.fillHeight: true
flickableDirection: Flickable.VerticalFlick
contentHeight: debugOutput.implicitHeight
TextEdit {
id: debugOutput
width: flickable.width
readOnly: true
wrapMode: TextEdit.Wrap
font.family: Appearance.font.family.mono
font.pointSize: Appearance.font.size.smaller
renderType: TextEdit.NativeRendering
textFormat: TextEdit.PlainText
color: "#ffb0ca" // Use primary color - will be set programmatically
Component.onCompleted: {
color = Colours.palette.m3primary;
appendLog("Debug panel initialized");
}
onTextChanged: {
// Ensure color stays set when text changes
color = Colours.palette.m3primary;
if (flickable.contentHeight > flickable.height) {
flickable.contentY = flickable.contentHeight - flickable.height;
}
}
}
}
StyledScrollBar {
flickable: flickable
policy: ScrollBar.AlwaysOn
}
}
}
}
function appendLog(message: string): void {
const timestamp = new Date().toLocaleTimeString();
debugOutput.text += `[${timestamp}] ${message}\n`;
}
function log(message: string): void {
appendLog(message);
}
}

View file

@ -0,0 +1,194 @@
pragma ComponentBehavior: Bound
import "."
import ".."
import qs.components
import qs.services
import qs.config
import Quickshell
import QtQuick
import QtQuick.Layouts
Item {
id: root
required property ShellScreen screen
required property DevSession session
implicitWidth: layout.implicitWidth + Appearance.padding.larger * 4
implicitHeight: layout.implicitHeight + Appearance.padding.large * 2
ColumnLayout {
id: layout
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: Appearance.padding.larger * 2
spacing: Appearance.spacing.normal
states: State {
name: "expanded"
when: root.session.navExpanded
PropertyChanges {
layout.spacing: Appearance.spacing.small
menuIcon.opacity: 0
menuIconExpanded.opacity: 1
menuIcon.rotation: 180
menuIconExpanded.rotation: 0
}
}
transitions: Transition {
Anim {
properties: "spacing,opacity,rotation"
}
}
Item {
id: menuBtn
Layout.topMargin: Appearance.spacing.large
implicitWidth: menuIcon.implicitWidth + menuIcon.anchors.leftMargin * 2
implicitHeight: menuIcon.implicitHeight + Appearance.padding.normal * 2
StateLayer {
radius: Appearance.rounding.small
function onClicked(): void {
root.session.navExpanded = !root.session.navExpanded;
}
}
MaterialIcon {
id: menuIcon
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: Appearance.padding.large
text: "menu"
font.pointSize: Appearance.font.size.large
}
MaterialIcon {
id: menuIconExpanded
anchors.fill: menuIcon
text: "menu_open"
font.pointSize: menuIcon.font.pointSize
opacity: 0
rotation: -180
}
}
NavItem {
Layout.topMargin: Appearance.spacing.large * 2
icon: "wifi"
label: "wireless"
}
NavItem {
icon: "bug_report"
label: "debug"
}
}
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.session.navExpanded
PropertyChanges {
expandedLabel.opacity: 1
smallLabel.opacity: 0
background.implicitWidth: icon.implicitWidth + icon.anchors.leftMargin * 2 + expandedLabel.anchors.leftMargin + expandedLabel.implicitWidth
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: Qt.alpha(Colours.palette.m3secondaryContainer, item.active ? 1 : 0)
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.normal
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
}
}
}
}

View file

@ -0,0 +1,70 @@
pragma ComponentBehavior: Bound
import "."
import ".."
import qs.components
import qs.services
import qs.config
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
ClippingRectangle {
id: root
required property DevSession session
color: "transparent"
ColumnLayout {
id: layout
spacing: 0
y: -root.session.activeIndex * root.height
Pane {
index: 0
sourceComponent: DevWirelessPane {
session: root.session
}
}
Pane {
index: 1
sourceComponent: DevDebugPane {
session: root.session
}
}
Behavior on y {
Anim {}
}
}
component Pane: Item {
id: pane
required property int index
property alias sourceComponent: loader.sourceComponent
implicitWidth: root.width
implicitHeight: root.height
Loader {
id: loader
anchors.fill: parent
clip: true
asynchronous: true
active: {
if (root.session.activeIndex === pane.index)
return true;
const ly = -layout.y;
const ty = pane.index * root.height;
return ly + root.height > ty && ly < ty + root.height;
}
}
}
}

View file

@ -0,0 +1,23 @@
import QtQuick
QtObject {
readonly property list<string> panes: ["wireless", "debug"]
required property var root
property bool floating: false
property string active: panes[0]
property int activeIndex: 0
property bool navExpanded: false
component Network: QtObject {
property var active
property bool showPasswordDialog: false
property var pendingNetwork
}
readonly property Network network: Network {}
onActiveChanged: activeIndex = panes.indexOf(active)
onActiveIndexChanged: active = panes[activeIndex]
}

View file

@ -0,0 +1,62 @@
pragma Singleton
import "."
import qs.components
import qs.services
import Quickshell
import QtQuick
Singleton {
id: root
function create(parent: Item, props: var): void {
devControlCenter.createObject(parent ?? dummy, props);
}
QtObject {
id: dummy
}
Component {
id: devControlCenter
FloatingWindow {
id: win
property alias active: cc.active
property alias navExpanded: cc.navExpanded
color: Colours.tPalette.m3surface
onVisibleChanged: {
if (!visible)
destroy();
}
minimumSize.width: 1000
minimumSize.height: 600
implicitWidth: cc.implicitWidth
implicitHeight: cc.implicitHeight
title: qsTr("Dev Panel - Wireless")
DevControlCenter {
id: cc
anchors.fill: parent
screen: win.screen
floating: true
function close(): void {
win.destroy();
}
}
Behavior on color {
CAnim {}
}
}
}
}

View file

@ -0,0 +1,53 @@
import "."
import qs.components
import qs.services
import qs.config
import Quickshell
import QtQuick
StyledRect {
id: root
required property ShellScreen screen
required property DevSession session
implicitHeight: text.implicitHeight + Appearance.padding.normal
color: Colours.tPalette.m3surfaceContainer
StyledText {
id: text
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
text: qsTr("Dev Panel - %1").arg(root.session.active.slice(0, 1).toUpperCase() + root.session.active.slice(1))
font.capitalization: Font.Capitalize
font.pointSize: Appearance.font.size.larger
font.weight: 500
}
Item {
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: Appearance.padding.normal
implicitWidth: implicitHeight
implicitHeight: closeIcon.implicitHeight + Appearance.padding.small
StateLayer {
radius: Appearance.rounding.full
function onClicked(): void {
QsWindow.window.destroy();
}
}
MaterialIcon {
id: closeIcon
anchors.centerIn: parent
text: "close"
}
}
}

View file

@ -0,0 +1,68 @@
pragma ComponentBehavior: Bound
import "."
import ".."
import qs.components
import qs.components.effects
import qs.components.containers
import qs.config
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
RowLayout {
id: root
required property DevSession session
anchors.fill: parent
spacing: 0
Item {
Layout.preferredWidth: Math.floor(parent.width * 0.4)
Layout.minimumWidth: 420
Layout.fillHeight: true
// Blank placeholder for wireless list
Item {
anchors.fill: parent
anchors.margins: Appearance.padding.large + Appearance.padding.normal
anchors.leftMargin: Appearance.padding.large
anchors.rightMargin: Appearance.padding.large + Appearance.padding.normal / 2
}
InnerBorder {
leftThickness: 0
rightThickness: Appearance.padding.normal / 2
}
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
ClippingRectangle {
anchors.fill: parent
anchors.margins: Appearance.padding.normal
anchors.leftMargin: 0
anchors.rightMargin: Appearance.padding.normal / 2
radius: rightBorder.innerRadius
color: "transparent"
// Blank placeholder for settings/details area
Item {
anchors.fill: parent
anchors.margins: Appearance.padding.large * 2
}
}
InnerBorder {
id: rightBorder
leftThickness: Appearance.padding.normal / 2
}
}
}

View file

@ -3,6 +3,7 @@ import qs.components.controls
import qs.services
import qs.config
import qs.modules.controlcenter
import "../../controlcenter/dev"
import Quickshell
import Quickshell.Bluetooth
import QtQuick
@ -92,6 +93,18 @@ StyledRect {
visible: VPN.enabled
onClicked: VPN.toggle()
}
Toggle {
icon: "bug_report"
inactiveOnColour: Colours.palette.m3onSurfaceVariant
toggle: false
onClicked: {
root.visibilities.utilities = false;
DevWindowFactory.create(null, {
screen: QsWindow.window?.screen ?? null
});
}
}
}
}