refactor: ToggleButton Tooltips and DeviceList
This commit is contained in:
parent
ff4e9bbdfd
commit
ef46a02b2f
13 changed files with 914 additions and 927 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
import ".."
|
import ".."
|
||||||
import qs.components
|
import qs.components
|
||||||
|
import qs.components.controls
|
||||||
import qs.components.effects
|
import qs.components.effects
|
||||||
import qs.services
|
import qs.services
|
||||||
import qs.config
|
import qs.config
|
||||||
|
|
@ -13,12 +14,31 @@ StyledRect {
|
||||||
property string icon
|
property string icon
|
||||||
property string label
|
property string label
|
||||||
property string accent: "Secondary"
|
property string accent: "Secondary"
|
||||||
|
property real iconSize: Appearance.font.size.large
|
||||||
|
property real horizontalPadding: Appearance.padding.large
|
||||||
|
property real verticalPadding: Appearance.padding.normal
|
||||||
|
property string tooltip: ""
|
||||||
|
|
||||||
|
property bool hovered: false
|
||||||
signal clicked
|
signal clicked
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
hovered = toggleStateLayer.containsMouse;
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: toggleStateLayer
|
||||||
|
function onContainsMouseChanged() {
|
||||||
|
const newHovered = toggleStateLayer.containsMouse;
|
||||||
|
if (hovered !== newHovered) {
|
||||||
|
hovered = newHovered;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Layout.preferredWidth: implicitWidth + (toggleStateLayer.pressed ? Appearance.padding.normal * 2 : toggled ? Appearance.padding.small * 2 : 0)
|
Layout.preferredWidth: implicitWidth + (toggleStateLayer.pressed ? Appearance.padding.normal * 2 : toggled ? Appearance.padding.small * 2 : 0)
|
||||||
implicitWidth: toggleBtnInner.implicitWidth + Appearance.padding.large * 2
|
implicitWidth: toggleBtnInner.implicitWidth + horizontalPadding * 2
|
||||||
implicitHeight: toggleBtnIcon.implicitHeight + Appearance.padding.normal * 2
|
implicitHeight: toggleBtnIcon.implicitHeight + verticalPadding * 2
|
||||||
|
|
||||||
radius: toggled || toggleStateLayer.pressed ? Appearance.rounding.small : Math.min(width, height) / 2 * Math.min(1, Appearance.rounding.scale)
|
radius: toggled || toggleStateLayer.pressed ? Appearance.rounding.small : Math.min(width, height) / 2 * Math.min(1, Appearance.rounding.scale)
|
||||||
color: toggled ? Colours.palette[`m3${accent.toLowerCase()}`] : Colours.palette[`m3${accent.toLowerCase()}Container`]
|
color: toggled ? Colours.palette[`m3${accent.toLowerCase()}`] : Colours.palette[`m3${accent.toLowerCase()}Container`]
|
||||||
|
|
@ -46,7 +66,7 @@ StyledRect {
|
||||||
fill: root.toggled ? 1 : 0
|
fill: root.toggled ? 1 : 0
|
||||||
text: root.icon
|
text: root.icon
|
||||||
color: root.toggled ? Colours.palette[`m3on${root.accent}`] : Colours.palette[`m3on${root.accent}Container`]
|
color: root.toggled ? Colours.palette[`m3on${root.accent}`] : Colours.palette[`m3on${root.accent}Container`]
|
||||||
font.pointSize: Appearance.font.size.large
|
font.pointSize: root.iconSize
|
||||||
|
|
||||||
Behavior on fill {
|
Behavior on fill {
|
||||||
Anim {}
|
Anim {}
|
||||||
|
|
@ -78,5 +98,30 @@ StyledRect {
|
||||||
easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial
|
easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tooltip - positioned absolutely, doesn't affect layout
|
||||||
|
Loader {
|
||||||
|
id: tooltipLoader
|
||||||
|
active: root.tooltip !== ""
|
||||||
|
asynchronous: true
|
||||||
|
z: 10000
|
||||||
|
width: 0
|
||||||
|
height: 0
|
||||||
|
sourceComponent: Component {
|
||||||
|
Tooltip {
|
||||||
|
target: root
|
||||||
|
text: root.tooltip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Completely remove from layout
|
||||||
|
Layout.fillWidth: false
|
||||||
|
Layout.fillHeight: false
|
||||||
|
Layout.preferredWidth: 0
|
||||||
|
Layout.preferredHeight: 0
|
||||||
|
Layout.maximumWidth: 0
|
||||||
|
Layout.maximumHeight: 0
|
||||||
|
Layout.minimumWidth: 0
|
||||||
|
Layout.minimumHeight: 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
170
components/controls/Tooltip.qml
Normal file
170
components/controls/Tooltip.qml
Normal file
|
|
@ -0,0 +1,170 @@
|
||||||
|
import ".."
|
||||||
|
import qs.components.effects
|
||||||
|
import qs.services
|
||||||
|
import qs.config
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
Popup {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property Item target
|
||||||
|
required property string text
|
||||||
|
property int delay: 500
|
||||||
|
property int timeout: 0
|
||||||
|
|
||||||
|
property bool tooltipVisible: false
|
||||||
|
property Timer showTimer: Timer {
|
||||||
|
interval: root.delay
|
||||||
|
onTriggered: root.tooltipVisible = true
|
||||||
|
}
|
||||||
|
property Timer hideTimer: Timer {
|
||||||
|
interval: root.timeout
|
||||||
|
onTriggered: root.tooltipVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Popup properties - doesn't affect layout
|
||||||
|
parent: {
|
||||||
|
let p = target;
|
||||||
|
// Walk up to find the root Item (usually has anchors.fill: parent)
|
||||||
|
while (p && p.parent) {
|
||||||
|
const parentItem = p.parent;
|
||||||
|
// Check if this looks like a root pane Item
|
||||||
|
if (parentItem && parentItem.anchors && parentItem.anchors.fill !== undefined) {
|
||||||
|
return parentItem;
|
||||||
|
}
|
||||||
|
p = parentItem;
|
||||||
|
}
|
||||||
|
// Fallback
|
||||||
|
return target.parent?.parent?.parent ?? target.parent?.parent ?? target.parent ?? target;
|
||||||
|
}
|
||||||
|
|
||||||
|
visible: tooltipVisible
|
||||||
|
modal: false
|
||||||
|
closePolicy: Popup.NoAutoClose
|
||||||
|
padding: 0
|
||||||
|
margins: 0
|
||||||
|
|
||||||
|
// Update position when target moves or tooltip becomes visible
|
||||||
|
onTooltipVisibleChanged: {
|
||||||
|
if (tooltipVisible) {
|
||||||
|
Qt.callLater(updatePosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Connections {
|
||||||
|
target: root.target
|
||||||
|
function onXChanged() { if (root.tooltipVisible) root.updatePosition(); }
|
||||||
|
function onYChanged() { if (root.tooltipVisible) root.updatePosition(); }
|
||||||
|
function onWidthChanged() { if (root.tooltipVisible) root.updatePosition(); }
|
||||||
|
function onHeightChanged() { if (root.tooltipVisible) root.updatePosition(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePosition() {
|
||||||
|
if (!target || !parent) return;
|
||||||
|
|
||||||
|
// Wait for tooltipRect to have its size calculated
|
||||||
|
Qt.callLater(() => {
|
||||||
|
if (!target || !parent || !tooltipRect) return;
|
||||||
|
|
||||||
|
// Get target position in parent's coordinate system
|
||||||
|
const targetPos = target.mapToItem(parent, 0, 0);
|
||||||
|
const targetCenterX = targetPos.x + target.width / 2;
|
||||||
|
|
||||||
|
// Get tooltip size (use width/height if available, otherwise implicit)
|
||||||
|
const tooltipWidth = tooltipRect.width > 0 ? tooltipRect.width : tooltipRect.implicitWidth;
|
||||||
|
const tooltipHeight = tooltipRect.height > 0 ? tooltipRect.height : tooltipRect.implicitHeight;
|
||||||
|
|
||||||
|
// Center tooltip horizontally on target
|
||||||
|
let newX = targetCenterX - tooltipWidth / 2;
|
||||||
|
|
||||||
|
// Position tooltip above target
|
||||||
|
let newY = targetPos.y - tooltipHeight - Appearance.spacing.small;
|
||||||
|
|
||||||
|
// Keep within bounds
|
||||||
|
const padding = Appearance.padding.normal;
|
||||||
|
if (newX < padding) {
|
||||||
|
newX = padding;
|
||||||
|
} else if (newX + tooltipWidth > (parent.width - padding)) {
|
||||||
|
newX = parent.width - tooltipWidth - padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update popup position
|
||||||
|
x = newX;
|
||||||
|
y = newY;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
enter: Transition {
|
||||||
|
Anim {
|
||||||
|
property: "opacity"
|
||||||
|
from: 0
|
||||||
|
to: 1
|
||||||
|
duration: Appearance.anim.durations.expressiveFastSpatial
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exit: Transition {
|
||||||
|
Anim {
|
||||||
|
property: "opacity"
|
||||||
|
from: 1
|
||||||
|
to: 0
|
||||||
|
duration: Appearance.anim.durations.expressiveFastSpatial
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Monitor hover state
|
||||||
|
Connections {
|
||||||
|
target: root.target
|
||||||
|
function onHoveredChanged() {
|
||||||
|
if (target.hovered) {
|
||||||
|
showTimer.start();
|
||||||
|
if (timeout > 0) {
|
||||||
|
hideTimer.stop();
|
||||||
|
hideTimer.start();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showTimer.stop();
|
||||||
|
hideTimer.stop();
|
||||||
|
tooltipVisible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: StyledRect {
|
||||||
|
id: tooltipRect
|
||||||
|
|
||||||
|
implicitWidth: tooltipText.implicitWidth + Appearance.padding.normal * 2
|
||||||
|
implicitHeight: tooltipText.implicitHeight + Appearance.padding.smaller * 2
|
||||||
|
|
||||||
|
color: Colours.palette.m3surfaceContainerHighest
|
||||||
|
radius: Appearance.rounding.small
|
||||||
|
|
||||||
|
// Add elevation for depth
|
||||||
|
Elevation {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: parent.radius
|
||||||
|
z: -1
|
||||||
|
level: 3
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: tooltipText
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
text: root.text
|
||||||
|
color: Colours.palette.m3onSurface
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
if (tooltipVisible) {
|
||||||
|
updatePosition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -24,8 +24,23 @@ SplitPaneWithDetails {
|
||||||
}
|
}
|
||||||
|
|
||||||
leftContent: Component {
|
leftContent: Component {
|
||||||
DeviceList {
|
StyledFlickable {
|
||||||
session: root.session
|
id: leftFlickable
|
||||||
|
|
||||||
|
flickableDirection: Flickable.VerticalFlick
|
||||||
|
contentHeight: deviceList.height
|
||||||
|
|
||||||
|
StyledScrollBar.vertical: StyledScrollBar {
|
||||||
|
flickable: leftFlickable
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceList {
|
||||||
|
id: deviceList
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
session: root.session
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,404 +20,427 @@ StyledFlickable {
|
||||||
readonly property BluetoothDevice device: session.bt.active
|
readonly property BluetoothDevice device: session.bt.active
|
||||||
|
|
||||||
flickableDirection: Flickable.VerticalFlick
|
flickableDirection: Flickable.VerticalFlick
|
||||||
contentHeight: layoutWrapper.height
|
contentHeight: detailsWrapper.height
|
||||||
|
|
||||||
StyledScrollBar.vertical: StyledScrollBar {
|
StyledScrollBar.vertical: StyledScrollBar {
|
||||||
flickable: root
|
flickable: root
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: layoutWrapper
|
id: detailsWrapper
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
implicitHeight: details.implicitHeight
|
||||||
|
|
||||||
|
DeviceDetails {
|
||||||
|
id: details
|
||||||
|
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
implicitHeight: layout.height
|
|
||||||
|
|
||||||
ColumnLayout {
|
session: root.session
|
||||||
id: layout
|
device: root.device
|
||||||
|
|
||||||
anchors.left: parent.left
|
headerComponent: Component {
|
||||||
anchors.right: parent.right
|
SettingsHeader {
|
||||||
anchors.top: parent.top
|
icon: Icons.getBluetoothIcon(root.device?.icon ?? "")
|
||||||
spacing: Appearance.spacing.normal
|
title: root.device?.name ?? ""
|
||||||
|
|
||||||
SettingsHeader {
|
|
||||||
icon: Icons.getBluetoothIcon(root.device?.icon ?? "")
|
|
||||||
title: root.device?.name ?? ""
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
Layout.topMargin: Appearance.spacing.large
|
|
||||||
text: qsTr("Connection status")
|
|
||||||
font.pointSize: Appearance.font.size.larger
|
|
||||||
font.weight: 500
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: qsTr("Connection settings for this device")
|
|
||||||
color: Colours.palette.m3outline
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledRect {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
implicitHeight: deviceStatus.implicitHeight + Appearance.padding.large * 2
|
|
||||||
|
|
||||||
radius: Appearance.rounding.normal
|
|
||||||
color: Colours.tPalette.m3surfaceContainer
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
id: deviceStatus
|
|
||||||
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.margins: Appearance.padding.large
|
|
||||||
|
|
||||||
spacing: Appearance.spacing.larger
|
|
||||||
|
|
||||||
Toggle {
|
|
||||||
label: qsTr("Connected")
|
|
||||||
checked: root.device?.connected ?? false
|
|
||||||
toggle.onToggled: root.device.connected = checked
|
|
||||||
}
|
|
||||||
|
|
||||||
Toggle {
|
|
||||||
label: qsTr("Paired")
|
|
||||||
checked: root.device?.paired ?? false
|
|
||||||
toggle.onToggled: {
|
|
||||||
if (root.device.paired)
|
|
||||||
root.device.forget();
|
|
||||||
else
|
|
||||||
root.device.pair();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Toggle {
|
|
||||||
label: qsTr("Blocked")
|
|
||||||
checked: root.device?.blocked ?? false
|
|
||||||
toggle.onToggled: root.device.blocked = checked
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
sections: [
|
||||||
Layout.topMargin: Appearance.spacing.large
|
Component {
|
||||||
text: qsTr("Device properties")
|
ColumnLayout {
|
||||||
font.pointSize: Appearance.font.size.larger
|
spacing: Appearance.spacing.normal
|
||||||
font.weight: 500
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: qsTr("Additional settings")
|
Layout.topMargin: Appearance.spacing.large
|
||||||
color: Colours.palette.m3outline
|
text: qsTr("Connection status")
|
||||||
}
|
font.pointSize: Appearance.font.size.larger
|
||||||
|
font.weight: 500
|
||||||
StyledRect {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
implicitHeight: deviceProps.implicitHeight + Appearance.padding.large * 2
|
|
||||||
|
|
||||||
radius: Appearance.rounding.normal
|
|
||||||
color: Colours.tPalette.m3surfaceContainer
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
id: deviceProps
|
|
||||||
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.margins: Appearance.padding.large
|
|
||||||
|
|
||||||
spacing: Appearance.spacing.larger
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
spacing: Appearance.spacing.small
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: renameDevice
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.rightMargin: Appearance.spacing.small
|
|
||||||
|
|
||||||
implicitHeight: renameLabel.implicitHeight + deviceNameEdit.implicitHeight
|
|
||||||
|
|
||||||
states: State {
|
|
||||||
name: "editingDeviceName"
|
|
||||||
when: root.session.bt.editingDeviceName
|
|
||||||
|
|
||||||
AnchorChanges {
|
|
||||||
target: deviceNameEdit
|
|
||||||
anchors.top: renameDevice.top
|
|
||||||
}
|
|
||||||
PropertyChanges {
|
|
||||||
renameDevice.implicitHeight: deviceNameEdit.implicitHeight
|
|
||||||
renameLabel.opacity: 0
|
|
||||||
deviceNameEdit.padding: Appearance.padding.normal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
transitions: Transition {
|
|
||||||
AnchorAnimation {
|
|
||||||
duration: Appearance.anim.durations.normal
|
|
||||||
easing.type: Easing.BezierSpline
|
|
||||||
easing.bezierCurve: Appearance.anim.curves.standard
|
|
||||||
}
|
|
||||||
Anim {
|
|
||||||
properties: "implicitHeight,opacity,padding"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
id: renameLabel
|
|
||||||
|
|
||||||
anchors.left: parent.left
|
|
||||||
|
|
||||||
text: qsTr("Device name")
|
|
||||||
color: Colours.palette.m3outline
|
|
||||||
font.pointSize: Appearance.font.size.small
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledTextField {
|
|
||||||
id: deviceNameEdit
|
|
||||||
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.top: renameLabel.bottom
|
|
||||||
anchors.leftMargin: root.session.bt.editingDeviceName ? 0 : -Appearance.padding.normal
|
|
||||||
|
|
||||||
text: root.device?.name ?? ""
|
|
||||||
readOnly: !root.session.bt.editingDeviceName
|
|
||||||
onAccepted: {
|
|
||||||
root.session.bt.editingDeviceName = false;
|
|
||||||
root.device.name = text;
|
|
||||||
}
|
|
||||||
|
|
||||||
leftPadding: Appearance.padding.normal
|
|
||||||
rightPadding: Appearance.padding.normal
|
|
||||||
|
|
||||||
background: StyledRect {
|
|
||||||
radius: Appearance.rounding.small
|
|
||||||
border.width: 2
|
|
||||||
border.color: Colours.palette.m3primary
|
|
||||||
opacity: root.session.bt.editingDeviceName ? 1 : 0
|
|
||||||
|
|
||||||
Behavior on border.color {
|
|
||||||
CAnim {}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on opacity {
|
|
||||||
Anim {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on anchors.leftMargin {
|
|
||||||
Anim {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledRect {
|
StyledText {
|
||||||
implicitWidth: implicitHeight
|
text: qsTr("Connection settings for this device")
|
||||||
implicitHeight: cancelEditIcon.implicitHeight + Appearance.padding.smaller * 2
|
color: Colours.palette.m3outline
|
||||||
|
|
||||||
radius: Appearance.rounding.small
|
|
||||||
color: Colours.palette.m3secondaryContainer
|
|
||||||
opacity: root.session.bt.editingDeviceName ? 1 : 0
|
|
||||||
scale: root.session.bt.editingDeviceName ? 1 : 0.5
|
|
||||||
|
|
||||||
StateLayer {
|
|
||||||
color: Colours.palette.m3onSecondaryContainer
|
|
||||||
disabled: !root.session.bt.editingDeviceName
|
|
||||||
|
|
||||||
function onClicked(): void {
|
|
||||||
root.session.bt.editingDeviceName = false;
|
|
||||||
deviceNameEdit.text = Qt.binding(() => root.device?.name ?? "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MaterialIcon {
|
|
||||||
id: cancelEditIcon
|
|
||||||
|
|
||||||
anchors.centerIn: parent
|
|
||||||
animate: true
|
|
||||||
text: "cancel"
|
|
||||||
color: Colours.palette.m3onSecondaryContainer
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on opacity {
|
|
||||||
Anim {}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on scale {
|
|
||||||
Anim {
|
|
||||||
duration: Appearance.anim.durations.expressiveFastSpatial
|
|
||||||
easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledRect {
|
|
||||||
implicitWidth: implicitHeight
|
|
||||||
implicitHeight: editIcon.implicitHeight + Appearance.padding.smaller * 2
|
|
||||||
|
|
||||||
radius: root.session.bt.editingDeviceName ? Appearance.rounding.small : implicitHeight / 2 * Math.min(1, Appearance.rounding.scale)
|
|
||||||
color: Qt.alpha(Colours.palette.m3primary, root.session.bt.editingDeviceName ? 1 : 0)
|
|
||||||
|
|
||||||
StateLayer {
|
|
||||||
color: root.session.bt.editingDeviceName ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface
|
|
||||||
|
|
||||||
function onClicked(): void {
|
|
||||||
root.session.bt.editingDeviceName = !root.session.bt.editingDeviceName;
|
|
||||||
if (root.session.bt.editingDeviceName)
|
|
||||||
deviceNameEdit.forceActiveFocus();
|
|
||||||
else
|
|
||||||
deviceNameEdit.accepted();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MaterialIcon {
|
|
||||||
id: editIcon
|
|
||||||
|
|
||||||
anchors.centerIn: parent
|
|
||||||
animate: true
|
|
||||||
text: root.session.bt.editingDeviceName ? "check_circle" : "edit"
|
|
||||||
color: root.session.bt.editingDeviceName ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on radius {
|
|
||||||
Anim {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Toggle {
|
|
||||||
label: qsTr("Trusted")
|
|
||||||
checked: root.device?.trusted ?? false
|
|
||||||
toggle.onToggled: root.device.trusted = checked
|
|
||||||
}
|
|
||||||
|
|
||||||
Toggle {
|
|
||||||
label: qsTr("Wake allowed")
|
|
||||||
checked: root.device?.wakeAllowed ?? false
|
|
||||||
toggle.onToggled: root.device.wakeAllowed = checked
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
Layout.topMargin: Appearance.spacing.large
|
|
||||||
text: qsTr("Device information")
|
|
||||||
font.pointSize: Appearance.font.size.larger
|
|
||||||
font.weight: 500
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: qsTr("Information about this device")
|
|
||||||
color: Colours.palette.m3outline
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledRect {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
implicitHeight: deviceInfo.implicitHeight + Appearance.padding.large * 2
|
|
||||||
|
|
||||||
radius: Appearance.rounding.normal
|
|
||||||
color: Colours.tPalette.m3surfaceContainer
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
id: deviceInfo
|
|
||||||
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.margins: Appearance.padding.large
|
|
||||||
|
|
||||||
spacing: Appearance.spacing.small / 2
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: root.device?.batteryAvailable ? qsTr("Device battery (%1%)").arg(root.device.battery * 100) : qsTr("Battery unavailable")
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
Layout.topMargin: Appearance.spacing.small / 2
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: Appearance.padding.smaller
|
|
||||||
spacing: Appearance.spacing.small / 2
|
|
||||||
|
|
||||||
StyledRect {
|
|
||||||
Layout.fillHeight: true
|
|
||||||
implicitWidth: root.device?.batteryAvailable ? parent.width * root.device.battery : 0
|
|
||||||
radius: Appearance.rounding.full
|
|
||||||
color: Colours.palette.m3primary
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledRect {
|
StyledRect {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
implicitHeight: deviceStatus.implicitHeight + Appearance.padding.large * 2
|
||||||
radius: Appearance.rounding.full
|
|
||||||
color: Colours.palette.m3secondaryContainer
|
|
||||||
|
|
||||||
StyledRect {
|
radius: Appearance.rounding.normal
|
||||||
|
color: Colours.tPalette.m3surfaceContainer
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: deviceStatus
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: parent.top
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.bottom: parent.bottom
|
anchors.margins: Appearance.padding.large
|
||||||
anchors.margins: parent.height * 0.25
|
|
||||||
|
|
||||||
implicitWidth: height
|
spacing: Appearance.spacing.larger
|
||||||
radius: Appearance.rounding.full
|
|
||||||
color: Colours.palette.m3primary
|
Toggle {
|
||||||
|
label: qsTr("Connected")
|
||||||
|
checked: root.device?.connected ?? false
|
||||||
|
toggle.onToggled: root.device.connected = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle {
|
||||||
|
label: qsTr("Paired")
|
||||||
|
checked: root.device?.paired ?? false
|
||||||
|
toggle.onToggled: {
|
||||||
|
if (root.device.paired)
|
||||||
|
root.device.forget();
|
||||||
|
else
|
||||||
|
root.device.pair();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle {
|
||||||
|
label: qsTr("Blocked")
|
||||||
|
checked: root.device?.blocked ?? false
|
||||||
|
toggle.onToggled: root.device.blocked = checked
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
Component {
|
||||||
|
ColumnLayout {
|
||||||
|
spacing: Appearance.spacing.normal
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
Layout.topMargin: Appearance.spacing.normal
|
Layout.topMargin: Appearance.spacing.large
|
||||||
text: qsTr("Dbus path")
|
text: qsTr("Device properties")
|
||||||
|
font.pointSize: Appearance.font.size.larger
|
||||||
|
font.weight: 500
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: qsTr("Additional settings")
|
||||||
|
color: Colours.palette.m3outline
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
implicitHeight: deviceProps.implicitHeight + Appearance.padding.large * 2
|
||||||
|
|
||||||
|
radius: Appearance.rounding.normal
|
||||||
|
color: Colours.tPalette.m3surfaceContainer
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: deviceProps
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.margins: Appearance.padding.large
|
||||||
|
|
||||||
|
spacing: Appearance.spacing.larger
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: renameDevice
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.rightMargin: Appearance.spacing.small
|
||||||
|
|
||||||
|
implicitHeight: renameLabel.implicitHeight + deviceNameEdit.implicitHeight
|
||||||
|
|
||||||
|
states: State {
|
||||||
|
name: "editingDeviceName"
|
||||||
|
when: root.session.bt.editingDeviceName
|
||||||
|
|
||||||
|
AnchorChanges {
|
||||||
|
target: deviceNameEdit
|
||||||
|
anchors.top: renameDevice.top
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
renameDevice.implicitHeight: deviceNameEdit.implicitHeight
|
||||||
|
renameLabel.opacity: 0
|
||||||
|
deviceNameEdit.padding: Appearance.padding.normal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
transitions: Transition {
|
||||||
|
AnchorAnimation {
|
||||||
|
duration: Appearance.anim.durations.normal
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.standard
|
||||||
|
}
|
||||||
|
Anim {
|
||||||
|
properties: "implicitHeight,opacity,padding"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: renameLabel
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
|
||||||
|
text: qsTr("Device name")
|
||||||
|
color: Colours.palette.m3outline
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledTextField {
|
||||||
|
id: deviceNameEdit
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: renameLabel.bottom
|
||||||
|
anchors.leftMargin: root.session.bt.editingDeviceName ? 0 : -Appearance.padding.normal
|
||||||
|
|
||||||
|
text: root.device?.name ?? ""
|
||||||
|
readOnly: !root.session.bt.editingDeviceName
|
||||||
|
onAccepted: {
|
||||||
|
root.session.bt.editingDeviceName = false;
|
||||||
|
root.device.name = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
leftPadding: Appearance.padding.normal
|
||||||
|
rightPadding: Appearance.padding.normal
|
||||||
|
|
||||||
|
background: StyledRect {
|
||||||
|
radius: Appearance.rounding.small
|
||||||
|
border.width: 2
|
||||||
|
border.color: Colours.palette.m3primary
|
||||||
|
opacity: root.session.bt.editingDeviceName ? 1 : 0
|
||||||
|
|
||||||
|
Behavior on border.color {
|
||||||
|
CAnim {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on anchors.leftMargin {
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
implicitWidth: implicitHeight
|
||||||
|
implicitHeight: cancelEditIcon.implicitHeight + Appearance.padding.smaller * 2
|
||||||
|
|
||||||
|
radius: Appearance.rounding.small
|
||||||
|
color: Colours.palette.m3secondaryContainer
|
||||||
|
opacity: root.session.bt.editingDeviceName ? 1 : 0
|
||||||
|
scale: root.session.bt.editingDeviceName ? 1 : 0.5
|
||||||
|
|
||||||
|
StateLayer {
|
||||||
|
color: Colours.palette.m3onSecondaryContainer
|
||||||
|
disabled: !root.session.bt.editingDeviceName
|
||||||
|
|
||||||
|
function onClicked(): void {
|
||||||
|
root.session.bt.editingDeviceName = false;
|
||||||
|
deviceNameEdit.text = Qt.binding(() => root.device?.name ?? "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
id: cancelEditIcon
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
animate: true
|
||||||
|
text: "cancel"
|
||||||
|
color: Colours.palette.m3onSecondaryContainer
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
duration: Appearance.anim.durations.expressiveFastSpatial
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
implicitWidth: implicitHeight
|
||||||
|
implicitHeight: editIcon.implicitHeight + Appearance.padding.smaller * 2
|
||||||
|
|
||||||
|
radius: root.session.bt.editingDeviceName ? Appearance.rounding.small : implicitHeight / 2 * Math.min(1, Appearance.rounding.scale)
|
||||||
|
color: Qt.alpha(Colours.palette.m3primary, root.session.bt.editingDeviceName ? 1 : 0)
|
||||||
|
|
||||||
|
StateLayer {
|
||||||
|
color: root.session.bt.editingDeviceName ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface
|
||||||
|
|
||||||
|
function onClicked(): void {
|
||||||
|
root.session.bt.editingDeviceName = !root.session.bt.editingDeviceName;
|
||||||
|
if (root.session.bt.editingDeviceName)
|
||||||
|
deviceNameEdit.forceActiveFocus();
|
||||||
|
else
|
||||||
|
deviceNameEdit.accepted();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
id: editIcon
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
animate: true
|
||||||
|
text: root.session.bt.editingDeviceName ? "check_circle" : "edit"
|
||||||
|
color: root.session.bt.editingDeviceName ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on radius {
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle {
|
||||||
|
label: qsTr("Trusted")
|
||||||
|
checked: root.device?.trusted ?? false
|
||||||
|
toggle.onToggled: root.device.trusted = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle {
|
||||||
|
label: qsTr("Wake allowed")
|
||||||
|
checked: root.device?.wakeAllowed ?? false
|
||||||
|
toggle.onToggled: root.device.wakeAllowed = checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
Component {
|
||||||
|
ColumnLayout {
|
||||||
|
spacing: Appearance.spacing.normal
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: root.device?.dbusPath ?? ""
|
Layout.topMargin: Appearance.spacing.large
|
||||||
color: Colours.palette.m3outline
|
text: qsTr("Device information")
|
||||||
font.pointSize: Appearance.font.size.small
|
font.pointSize: Appearance.font.size.larger
|
||||||
}
|
font.weight: 500
|
||||||
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
Layout.topMargin: Appearance.spacing.normal
|
text: qsTr("Information about this device")
|
||||||
text: qsTr("MAC address")
|
color: Colours.palette.m3outline
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledRect {
|
||||||
text: root.device?.address ?? ""
|
Layout.fillWidth: true
|
||||||
color: Colours.palette.m3outline
|
implicitHeight: deviceInfo.implicitHeight + Appearance.padding.large * 2
|
||||||
font.pointSize: Appearance.font.size.small
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
radius: Appearance.rounding.normal
|
||||||
Layout.topMargin: Appearance.spacing.normal
|
color: Colours.tPalette.m3surfaceContainer
|
||||||
text: qsTr("Bonded")
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
ColumnLayout {
|
||||||
text: root.device?.bonded ? qsTr("Yes") : qsTr("No")
|
id: deviceInfo
|
||||||
color: Colours.palette.m3outline
|
|
||||||
font.pointSize: Appearance.font.size.small
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
anchors.left: parent.left
|
||||||
Layout.topMargin: Appearance.spacing.normal
|
anchors.right: parent.right
|
||||||
text: qsTr("System name")
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
anchors.margins: Appearance.padding.large
|
||||||
|
|
||||||
StyledText {
|
spacing: Appearance.spacing.small / 2
|
||||||
text: root.device?.deviceName ?? ""
|
|
||||||
color: Colours.palette.m3outline
|
StyledText {
|
||||||
font.pointSize: Appearance.font.size.small
|
text: root.device?.batteryAvailable ? qsTr("Device battery (%1%)").arg(root.device.battery * 100) : qsTr("Battery unavailable")
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.topMargin: Appearance.spacing.small / 2
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: Appearance.padding.smaller
|
||||||
|
spacing: Appearance.spacing.small / 2
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
implicitWidth: root.device?.batteryAvailable ? parent.width * root.device.battery : 0
|
||||||
|
radius: Appearance.rounding.full
|
||||||
|
color: Colours.palette.m3primary
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
radius: Appearance.rounding.full
|
||||||
|
color: Colours.palette.m3secondaryContainer
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.margins: parent.height * 0.25
|
||||||
|
|
||||||
|
implicitWidth: height
|
||||||
|
radius: Appearance.rounding.full
|
||||||
|
color: Colours.palette.m3primary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
Layout.topMargin: Appearance.spacing.normal
|
||||||
|
text: qsTr("Dbus path")
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: root.device?.dbusPath ?? ""
|
||||||
|
color: Colours.palette.m3outline
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
Layout.topMargin: Appearance.spacing.normal
|
||||||
|
text: qsTr("MAC address")
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: root.device?.address ?? ""
|
||||||
|
color: Colours.palette.m3outline
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
Layout.topMargin: Appearance.spacing.normal
|
||||||
|
text: qsTr("Bonded")
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: root.device?.bonded ? qsTr("Yes") : qsTr("No")
|
||||||
|
color: Colours.palette.m3outline
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
Layout.topMargin: Appearance.spacing.normal
|
||||||
|
text: qsTr("System name")
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: root.device?.deviceName ?? ""
|
||||||
|
color: Colours.palette.m3outline
|
||||||
|
font.pointSize: Appearance.font.size.small
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FAB Menu (positioned absolutely relative to flickable)
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.right: fabRoot.right
|
anchors.right: fabRoot.right
|
||||||
anchors.bottom: fabRoot.top
|
anchors.bottom: fabRoot.top
|
||||||
|
|
|
||||||
|
|
@ -48,8 +48,12 @@ DeviceList {
|
||||||
toggled: Bluetooth.defaultAdapter?.enabled ?? false
|
toggled: Bluetooth.defaultAdapter?.enabled ?? false
|
||||||
icon: "power"
|
icon: "power"
|
||||||
accent: "Tertiary"
|
accent: "Tertiary"
|
||||||
|
iconSize: Appearance.font.size.normal
|
||||||
|
horizontalPadding: Appearance.padding.normal
|
||||||
|
verticalPadding: Appearance.padding.smaller
|
||||||
|
tooltip: qsTr("Toggle Bluetooth")
|
||||||
|
|
||||||
function onClicked(): void {
|
onClicked: {
|
||||||
const adapter = Bluetooth.defaultAdapter;
|
const adapter = Bluetooth.defaultAdapter;
|
||||||
if (adapter)
|
if (adapter)
|
||||||
adapter.enabled = !adapter.enabled;
|
adapter.enabled = !adapter.enabled;
|
||||||
|
|
@ -60,8 +64,12 @@ DeviceList {
|
||||||
toggled: Bluetooth.defaultAdapter?.discoverable ?? false
|
toggled: Bluetooth.defaultAdapter?.discoverable ?? false
|
||||||
icon: root.smallDiscoverable ? "group_search" : ""
|
icon: root.smallDiscoverable ? "group_search" : ""
|
||||||
label: root.smallDiscoverable ? "" : qsTr("Discoverable")
|
label: root.smallDiscoverable ? "" : qsTr("Discoverable")
|
||||||
|
iconSize: Appearance.font.size.normal
|
||||||
|
horizontalPadding: Appearance.padding.normal
|
||||||
|
verticalPadding: Appearance.padding.smaller
|
||||||
|
tooltip: qsTr("Make discoverable")
|
||||||
|
|
||||||
function onClicked(): void {
|
onClicked: {
|
||||||
const adapter = Bluetooth.defaultAdapter;
|
const adapter = Bluetooth.defaultAdapter;
|
||||||
if (adapter)
|
if (adapter)
|
||||||
adapter.discoverable = !adapter.discoverable;
|
adapter.discoverable = !adapter.discoverable;
|
||||||
|
|
@ -72,20 +80,44 @@ DeviceList {
|
||||||
toggled: Bluetooth.defaultAdapter?.pairable ?? false
|
toggled: Bluetooth.defaultAdapter?.pairable ?? false
|
||||||
icon: "missing_controller"
|
icon: "missing_controller"
|
||||||
label: root.smallPairable ? "" : qsTr("Pairable")
|
label: root.smallPairable ? "" : qsTr("Pairable")
|
||||||
|
iconSize: Appearance.font.size.normal
|
||||||
|
horizontalPadding: Appearance.padding.normal
|
||||||
|
verticalPadding: Appearance.padding.smaller
|
||||||
|
tooltip: qsTr("Make pairable")
|
||||||
|
|
||||||
function onClicked(): void {
|
onClicked: {
|
||||||
const adapter = Bluetooth.defaultAdapter;
|
const adapter = Bluetooth.defaultAdapter;
|
||||||
if (adapter)
|
if (adapter)
|
||||||
adapter.pairable = !adapter.pairable;
|
adapter.pairable = !adapter.pairable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ToggleButton {
|
||||||
|
toggled: Bluetooth.defaultAdapter?.discovering ?? false
|
||||||
|
icon: "bluetooth_searching"
|
||||||
|
accent: "Secondary"
|
||||||
|
iconSize: Appearance.font.size.normal
|
||||||
|
horizontalPadding: Appearance.padding.normal
|
||||||
|
verticalPadding: Appearance.padding.smaller
|
||||||
|
tooltip: qsTr("Scan for devices")
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
const adapter = Bluetooth.defaultAdapter;
|
||||||
|
if (adapter)
|
||||||
|
adapter.discovering = !adapter.discovering;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ToggleButton {
|
ToggleButton {
|
||||||
toggled: !root.session.bt.active
|
toggled: !root.session.bt.active
|
||||||
icon: "settings"
|
icon: "settings"
|
||||||
accent: "Primary"
|
accent: "Primary"
|
||||||
|
iconSize: Appearance.font.size.normal
|
||||||
|
horizontalPadding: Appearance.padding.normal
|
||||||
|
verticalPadding: Appearance.padding.smaller
|
||||||
|
tooltip: qsTr("Bluetooth settings")
|
||||||
|
|
||||||
function onClicked(): void {
|
onClicked: {
|
||||||
if (root.session.bt.active)
|
if (root.session.bt.active)
|
||||||
root.session.bt.active = null;
|
root.session.bt.active = null;
|
||||||
else {
|
else {
|
||||||
|
|
@ -96,47 +128,6 @@ DeviceList {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
titleSuffix: Component {
|
|
||||||
RowLayout {
|
|
||||||
spacing: Appearance.spacing.normal
|
|
||||||
|
|
||||||
Item {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledRect {
|
|
||||||
implicitWidth: implicitHeight
|
|
||||||
implicitHeight: scanIcon.implicitHeight + Appearance.padding.normal * 2
|
|
||||||
|
|
||||||
radius: Bluetooth.defaultAdapter?.discovering ? Appearance.rounding.normal : implicitHeight / 2 * Math.min(1, Appearance.rounding.scale)
|
|
||||||
color: Bluetooth.defaultAdapter?.discovering ? Colours.palette.m3secondary : Colours.palette.m3secondaryContainer
|
|
||||||
|
|
||||||
StateLayer {
|
|
||||||
color: Bluetooth.defaultAdapter?.discovering ? Colours.palette.m3onSecondary : Colours.palette.m3onSecondaryContainer
|
|
||||||
|
|
||||||
function onClicked(): void {
|
|
||||||
const adapter = Bluetooth.defaultAdapter;
|
|
||||||
if (adapter)
|
|
||||||
adapter.discovering = !adapter.discovering;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MaterialIcon {
|
|
||||||
id: scanIcon
|
|
||||||
|
|
||||||
anchors.centerIn: parent
|
|
||||||
animate: true
|
|
||||||
text: "bluetooth_searching"
|
|
||||||
color: Bluetooth.defaultAdapter?.discovering ? Colours.palette.m3onSecondary : Colours.palette.m3onSecondaryContainer
|
|
||||||
fill: Bluetooth.defaultAdapter?.discovering ? 1 : 0
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on radius {
|
|
||||||
Anim {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delegate: Component {
|
delegate: Component {
|
||||||
StyledRect {
|
StyledRect {
|
||||||
|
|
@ -146,8 +137,7 @@ DeviceList {
|
||||||
readonly property bool loading: modelData && (modelData.state === BluetoothDeviceState.Connecting || modelData.state === BluetoothDeviceState.Disconnecting)
|
readonly property bool loading: modelData && (modelData.state === BluetoothDeviceState.Connecting || modelData.state === BluetoothDeviceState.Disconnecting)
|
||||||
readonly property bool connected: modelData && modelData.state === BluetoothDeviceState.Connected
|
readonly property bool connected: modelData && modelData.state === BluetoothDeviceState.Connected
|
||||||
|
|
||||||
anchors.left: parent.left
|
width: ListView.view ? ListView.view.width : undefined
|
||||||
anchors.right: parent.right
|
|
||||||
implicitHeight: deviceInner.implicitHeight + Appearance.padding.normal * 2
|
implicitHeight: deviceInner.implicitHeight + Appearance.padding.normal * 2
|
||||||
|
|
||||||
color: Qt.alpha(Colours.tPalette.m3surfaceContainer, root.activeItem === modelData ? Colours.tPalette.m3surfaceContainer.a : 0)
|
color: Qt.alpha(Colours.tPalette.m3surfaceContainer, root.activeItem === modelData ? Colours.tPalette.m3surfaceContainer.a : 0)
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,8 @@ Item {
|
||||||
model: root.sections
|
model: root.sections
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
|
required property Component modelData
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
sourceComponent: modelData
|
sourceComponent: modelData
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import qs.components.controls
|
||||||
import qs.components.containers
|
import qs.components.containers
|
||||||
import qs.services
|
import qs.services
|
||||||
import qs.config
|
import qs.config
|
||||||
|
import Quickshell
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
|
@ -55,6 +56,7 @@ ColumnLayout {
|
||||||
property var activeItem: null
|
property var activeItem: null
|
||||||
property Component headerComponent: null
|
property Component headerComponent: null
|
||||||
property Component titleSuffix: null
|
property Component titleSuffix: null
|
||||||
|
property bool showHeader: true
|
||||||
|
|
||||||
signal itemSelected(var item)
|
signal itemSelected(var item)
|
||||||
|
|
||||||
|
|
@ -66,7 +68,7 @@ ColumnLayout {
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
sourceComponent: root.headerComponent
|
sourceComponent: root.headerComponent
|
||||||
visible: root.headerComponent !== null
|
visible: root.headerComponent !== null && root.showHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// Title and description row
|
// Title and description row
|
||||||
|
|
@ -109,17 +111,15 @@ ColumnLayout {
|
||||||
id: view
|
id: view
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
// Use contentHeight to show all items without estimation
|
||||||
|
implicitHeight: contentHeight
|
||||||
|
|
||||||
model: root.model
|
model: root.model
|
||||||
delegate: root.delegate
|
delegate: root.delegate
|
||||||
|
|
||||||
spacing: Appearance.spacing.small / 2
|
spacing: Appearance.spacing.small / 2
|
||||||
clip: true
|
interactive: false // Disable individual scrolling - parent pane handles it
|
||||||
|
clip: false // Don't clip - let parent handle scrolling
|
||||||
StyledScrollBar.vertical: StyledScrollBar {
|
|
||||||
flickable: view
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -183,6 +183,10 @@ Item {
|
||||||
toggled: !root.session.launcher.active
|
toggled: !root.session.launcher.active
|
||||||
icon: "settings"
|
icon: "settings"
|
||||||
accent: "Primary"
|
accent: "Primary"
|
||||||
|
iconSize: Appearance.font.size.normal
|
||||||
|
horizontalPadding: Appearance.padding.normal
|
||||||
|
verticalPadding: Appearance.padding.smaller
|
||||||
|
tooltip: qsTr("Launcher settings")
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (root.session.launcher.active) {
|
if (root.session.launcher.active) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
pragma ComponentBehavior: Bound
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
import ".."
|
import ".."
|
||||||
|
import "../components"
|
||||||
import qs.components
|
import qs.components
|
||||||
import qs.components.controls
|
import qs.components.controls
|
||||||
import qs.components.effects
|
import qs.components.effects
|
||||||
|
|
@ -10,99 +11,108 @@ import qs.config
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
Item {
|
DeviceDetails {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property Session session
|
required property Session session
|
||||||
readonly property var device: session.ethernet.active
|
readonly property var ethernetDevice: session.ethernet.active
|
||||||
|
|
||||||
implicitWidth: layout.implicitWidth
|
device: ethernetDevice
|
||||||
implicitHeight: layout.implicitHeight
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (device && device.interface) {
|
if (ethernetDevice && ethernetDevice.interface) {
|
||||||
Nmcli.getEthernetDeviceDetails(device.interface, () => {});
|
Nmcli.getEthernetDeviceDetails(ethernetDevice.interface, () => {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onDeviceChanged: {
|
onEthernetDeviceChanged: {
|
||||||
if (device && device.interface) {
|
if (ethernetDevice && ethernetDevice.interface) {
|
||||||
Nmcli.getEthernetDeviceDetails(device.interface, () => {});
|
Nmcli.getEthernetDeviceDetails(ethernetDevice.interface, () => {});
|
||||||
} else {
|
} else {
|
||||||
Nmcli.ethernetDeviceDetails = null;
|
Nmcli.ethernetDeviceDetails = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
headerComponent: Component {
|
||||||
id: layout
|
ConnectionHeader {
|
||||||
|
icon: "cable"
|
||||||
|
title: root.ethernetDevice?.interface ?? qsTr("Unknown")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
anchors.left: parent.left
|
sections: [
|
||||||
anchors.right: parent.right
|
Component {
|
||||||
anchors.top: parent.top
|
ColumnLayout {
|
||||||
spacing: Appearance.spacing.normal
|
spacing: Appearance.spacing.normal
|
||||||
|
|
||||||
ConnectionHeader {
|
SectionHeader {
|
||||||
icon: "cable"
|
title: qsTr("Connection status")
|
||||||
title: root.device?.interface ?? qsTr("Unknown")
|
description: qsTr("Connection settings for this device")
|
||||||
}
|
}
|
||||||
|
|
||||||
SectionHeader {
|
SectionContainer {
|
||||||
title: qsTr("Connection status")
|
ToggleRow {
|
||||||
description: qsTr("Connection settings for this device")
|
label: qsTr("Connected")
|
||||||
}
|
checked: root.ethernetDevice?.connected ?? false
|
||||||
|
toggle.onToggled: {
|
||||||
SectionContainer {
|
if (checked) {
|
||||||
ToggleRow {
|
Nmcli.connectEthernet(root.ethernetDevice?.connection || "", root.ethernetDevice?.interface || "", () => {});
|
||||||
label: qsTr("Connected")
|
} else {
|
||||||
checked: root.device?.connected ?? false
|
if (root.ethernetDevice?.connection) {
|
||||||
toggle.onToggled: {
|
Nmcli.disconnectEthernet(root.ethernetDevice.connection, () => {});
|
||||||
if (checked) {
|
}
|
||||||
Nmcli.connectEthernet(root.device?.connection || "", root.device?.interface || "", () => {});
|
|
||||||
} else {
|
|
||||||
if (root.device?.connection) {
|
|
||||||
Nmcli.disconnectEthernet(root.device.connection, () => {});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
Component {
|
||||||
|
ColumnLayout {
|
||||||
|
spacing: Appearance.spacing.normal
|
||||||
|
|
||||||
SectionHeader {
|
SectionHeader {
|
||||||
title: qsTr("Device properties")
|
title: qsTr("Device properties")
|
||||||
description: qsTr("Additional information")
|
description: qsTr("Additional information")
|
||||||
}
|
|
||||||
|
|
||||||
SectionContainer {
|
|
||||||
contentSpacing: Appearance.spacing.small / 2
|
|
||||||
|
|
||||||
PropertyRow {
|
|
||||||
label: qsTr("Interface")
|
|
||||||
value: root.device?.interface ?? qsTr("Unknown")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyRow {
|
SectionContainer {
|
||||||
showTopMargin: true
|
contentSpacing: Appearance.spacing.small / 2
|
||||||
label: qsTr("Connection")
|
|
||||||
value: root.device?.connection || qsTr("Not connected")
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyRow {
|
PropertyRow {
|
||||||
showTopMargin: true
|
label: qsTr("Interface")
|
||||||
label: qsTr("State")
|
value: root.ethernetDevice?.interface ?? qsTr("Unknown")
|
||||||
value: root.device?.state ?? qsTr("Unknown")
|
}
|
||||||
|
|
||||||
|
PropertyRow {
|
||||||
|
showTopMargin: true
|
||||||
|
label: qsTr("Connection")
|
||||||
|
value: root.ethernetDevice?.connection || qsTr("Not connected")
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyRow {
|
||||||
|
showTopMargin: true
|
||||||
|
label: qsTr("State")
|
||||||
|
value: root.ethernetDevice?.state ?? qsTr("Unknown")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
Component {
|
||||||
|
ColumnLayout {
|
||||||
|
spacing: Appearance.spacing.normal
|
||||||
|
|
||||||
SectionHeader {
|
SectionHeader {
|
||||||
title: qsTr("Connection information")
|
title: qsTr("Connection information")
|
||||||
description: qsTr("Network connection details")
|
description: qsTr("Network connection details")
|
||||||
}
|
}
|
||||||
|
|
||||||
SectionContainer {
|
SectionContainer {
|
||||||
ConnectionInfoSection {
|
ConnectionInfoSection {
|
||||||
deviceDetails: Nmcli.ethernetDeviceDetails
|
deviceDetails: Nmcli.ethernetDeviceDetails
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -39,6 +39,9 @@ DeviceList {
|
||||||
toggled: !root.session.ethernet.active
|
toggled: !root.session.ethernet.active
|
||||||
icon: "settings"
|
icon: "settings"
|
||||||
accent: "Primary"
|
accent: "Primary"
|
||||||
|
iconSize: Appearance.font.size.normal
|
||||||
|
horizontalPadding: Appearance.padding.normal
|
||||||
|
verticalPadding: Appearance.padding.smaller
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (root.session.ethernet.active)
|
if (root.session.ethernet.active)
|
||||||
|
|
@ -55,8 +58,7 @@ DeviceList {
|
||||||
StyledRect {
|
StyledRect {
|
||||||
required property var modelData
|
required property var modelData
|
||||||
|
|
||||||
anchors.left: parent.left
|
width: ListView.view ? ListView.view.width : undefined
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
color: Qt.alpha(Colours.tPalette.m3surfaceContainer, root.activeItem === modelData ? Colours.tPalette.m3surfaceContainer.a : 0)
|
color: Qt.alpha(Colours.tPalette.m3surfaceContainer, root.activeItem === modelData ? Colours.tPalette.m3surfaceContainer.a : 0)
|
||||||
radius: Appearance.rounding.normal
|
radius: Appearance.rounding.normal
|
||||||
|
|
|
||||||
|
|
@ -28,23 +28,22 @@ Item {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
leftContent: Component {
|
leftContent: Component {
|
||||||
|
StyledFlickable {
|
||||||
|
id: leftFlickable
|
||||||
|
|
||||||
StyledFlickable {
|
flickableDirection: Flickable.VerticalFlick
|
||||||
id: leftFlickable
|
contentHeight: leftContent.height
|
||||||
|
|
||||||
flickableDirection: Flickable.VerticalFlick
|
StyledScrollBar.vertical: StyledScrollBar {
|
||||||
contentHeight: leftContent.height
|
flickable: leftFlickable
|
||||||
|
}
|
||||||
|
|
||||||
StyledScrollBar.vertical: StyledScrollBar {
|
ColumnLayout {
|
||||||
flickable: leftFlickable
|
id: leftContent
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
anchors.left: parent.left
|
||||||
id: leftContent
|
anchors.right: parent.right
|
||||||
|
spacing: Appearance.spacing.normal
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
spacing: Appearance.spacing.normal
|
|
||||||
|
|
||||||
// Network header above the collapsible sections
|
// Network header above the collapsible sections
|
||||||
RowLayout {
|
RowLayout {
|
||||||
|
|
@ -65,6 +64,10 @@ Item {
|
||||||
toggled: Nmcli.wifiEnabled
|
toggled: Nmcli.wifiEnabled
|
||||||
icon: "wifi"
|
icon: "wifi"
|
||||||
accent: "Tertiary"
|
accent: "Tertiary"
|
||||||
|
iconSize: Appearance.font.size.normal
|
||||||
|
horizontalPadding: Appearance.padding.normal
|
||||||
|
verticalPadding: Appearance.padding.smaller
|
||||||
|
tooltip: qsTr("Toggle WiFi")
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
Nmcli.toggleWifi(null);
|
Nmcli.toggleWifi(null);
|
||||||
|
|
@ -75,6 +78,10 @@ Item {
|
||||||
toggled: Nmcli.scanning
|
toggled: Nmcli.scanning
|
||||||
icon: "wifi_find"
|
icon: "wifi_find"
|
||||||
accent: "Secondary"
|
accent: "Secondary"
|
||||||
|
iconSize: Appearance.font.size.normal
|
||||||
|
horizontalPadding: Appearance.padding.normal
|
||||||
|
verticalPadding: Appearance.padding.smaller
|
||||||
|
tooltip: qsTr("Scan for networks")
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
Nmcli.rescanWifi();
|
Nmcli.rescanWifi();
|
||||||
|
|
@ -85,6 +92,10 @@ Item {
|
||||||
toggled: !root.session.ethernet.active && !root.session.network.active
|
toggled: !root.session.ethernet.active && !root.session.network.active
|
||||||
icon: "settings"
|
icon: "settings"
|
||||||
accent: "Primary"
|
accent: "Primary"
|
||||||
|
iconSize: Appearance.font.size.normal
|
||||||
|
horizontalPadding: Appearance.padding.normal
|
||||||
|
verticalPadding: Appearance.padding.smaller
|
||||||
|
tooltip: qsTr("Network settings")
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (root.session.ethernet.active || root.session.network.active) {
|
if (root.session.ethernet.active || root.session.network.active) {
|
||||||
|
|
@ -109,127 +120,12 @@ Item {
|
||||||
title: qsTr("Ethernet")
|
title: qsTr("Ethernet")
|
||||||
expanded: true
|
expanded: true
|
||||||
|
|
||||||
ColumnLayout {
|
Loader {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
spacing: Appearance.spacing.small
|
sourceComponent: Component {
|
||||||
|
EthernetList {
|
||||||
RowLayout {
|
session: root.session
|
||||||
Layout.fillWidth: true
|
showHeader: false
|
||||||
spacing: Appearance.spacing.small
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: qsTr("Devices (%1)").arg(Nmcli.ethernetDevices.length)
|
|
||||||
font.pointSize: Appearance.font.size.normal
|
|
||||||
font.weight: 500
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
text: qsTr("All available ethernet devices")
|
|
||||||
color: Colours.palette.m3outline
|
|
||||||
}
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
id: ethernetRepeater
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
model: Nmcli.ethernetDevices
|
|
||||||
|
|
||||||
delegate: StyledRect {
|
|
||||||
required property var modelData
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
color: Qt.alpha(Colours.tPalette.m3surfaceContainer, root.session.ethernet.active === modelData ? Colours.tPalette.m3surfaceContainer.a : 0)
|
|
||||||
radius: Appearance.rounding.normal
|
|
||||||
|
|
||||||
StateLayer {
|
|
||||||
function onClicked(): void {
|
|
||||||
root.session.network.active = null;
|
|
||||||
root.session.ethernet.active = modelData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
id: rowLayout
|
|
||||||
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.margins: Appearance.padding.normal
|
|
||||||
|
|
||||||
spacing: Appearance.spacing.normal
|
|
||||||
|
|
||||||
StyledRect {
|
|
||||||
implicitWidth: implicitHeight
|
|
||||||
implicitHeight: icon.implicitHeight + Appearance.padding.normal * 2
|
|
||||||
|
|
||||||
radius: Appearance.rounding.normal
|
|
||||||
color: modelData.connected ? Colours.palette.m3primaryContainer : Colours.tPalette.m3surfaceContainerHigh
|
|
||||||
|
|
||||||
MaterialIcon {
|
|
||||||
id: icon
|
|
||||||
|
|
||||||
anchors.centerIn: parent
|
|
||||||
text: "cable"
|
|
||||||
font.pointSize: Appearance.font.size.large
|
|
||||||
fill: modelData.connected ? 1 : 0
|
|
||||||
color: modelData.connected ? Colours.palette.m3onPrimaryContainer : Colours.palette.m3onSurface
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
elide: Text.ElideRight
|
|
||||||
maximumLineCount: 1
|
|
||||||
|
|
||||||
text: modelData.interface || qsTr("Unknown")
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
text: modelData.connected ? qsTr("Connected") : qsTr("Disconnected")
|
|
||||||
color: modelData.connected ? Colours.palette.m3primary : Colours.palette.m3outline
|
|
||||||
font.pointSize: Appearance.font.size.small
|
|
||||||
font.weight: modelData.connected ? 500 : 400
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledRect {
|
|
||||||
implicitWidth: implicitHeight
|
|
||||||
implicitHeight: connectIcon.implicitHeight + Appearance.padding.smaller * 2
|
|
||||||
|
|
||||||
radius: Appearance.rounding.full
|
|
||||||
color: Qt.alpha(Colours.palette.m3primaryContainer, modelData.connected ? 1 : 0)
|
|
||||||
|
|
||||||
StateLayer {
|
|
||||||
function onClicked(): void {
|
|
||||||
if (modelData.connected && modelData.connection) {
|
|
||||||
Nmcli.disconnectEthernet(modelData.connection, () => {});
|
|
||||||
} else {
|
|
||||||
Nmcli.connectEthernet(modelData.connection || "", modelData.interface || "", () => {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MaterialIcon {
|
|
||||||
id: connectIcon
|
|
||||||
|
|
||||||
anchors.centerIn: parent
|
|
||||||
text: modelData.connected ? "link_off" : "link"
|
|
||||||
color: modelData.connected ? Colours.palette.m3onPrimaryContainer : Colours.palette.m3onSurface
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
implicitHeight: rowLayout.implicitHeight + Appearance.padding.normal * 2
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -242,195 +138,12 @@ Item {
|
||||||
title: qsTr("Wireless")
|
title: qsTr("Wireless")
|
||||||
expanded: true
|
expanded: true
|
||||||
|
|
||||||
ColumnLayout {
|
Loader {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
spacing: Appearance.spacing.small
|
sourceComponent: Component {
|
||||||
|
WirelessList {
|
||||||
RowLayout {
|
session: root.session
|
||||||
Layout.fillWidth: true
|
showHeader: false
|
||||||
spacing: Appearance.spacing.small
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: qsTr("Networks (%1)").arg(Nmcli.networks.length)
|
|
||||||
font.pointSize: Appearance.font.size.normal
|
|
||||||
font.weight: 500
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
visible: Nmcli.scanning
|
|
||||||
text: qsTr("Scanning...")
|
|
||||||
color: Colours.palette.m3primary
|
|
||||||
font.pointSize: Appearance.font.size.small
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
text: qsTr("All available WiFi networks")
|
|
||||||
color: Colours.palette.m3outline
|
|
||||||
}
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
id: wirelessRepeater
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
model: ScriptModel {
|
|
||||||
values: [...Nmcli.networks].sort((a, b) => {
|
|
||||||
// Put active/connected network first
|
|
||||||
if (a.active !== b.active)
|
|
||||||
return b.active - a.active;
|
|
||||||
// Then sort by signal strength
|
|
||||||
return b.strength - a.strength;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
delegate: StyledRect {
|
|
||||||
required property var modelData
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
color: Qt.alpha(Colours.tPalette.m3surfaceContainer, (modelData && root.session.network.active === modelData) ? Colours.tPalette.m3surfaceContainer.a : 0)
|
|
||||||
radius: Appearance.rounding.normal
|
|
||||||
|
|
||||||
StateLayer {
|
|
||||||
function onClicked(): void {
|
|
||||||
if (!modelData) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
root.session.ethernet.active = null;
|
|
||||||
root.session.network.active = modelData;
|
|
||||||
// Check if we need to refresh saved connections when selecting a network
|
|
||||||
if (modelData.ssid) {
|
|
||||||
checkSavedProfileForNetwork(modelData.ssid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
id: wirelessRowLayout
|
|
||||||
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.margins: Appearance.padding.normal
|
|
||||||
|
|
||||||
spacing: Appearance.spacing.normal
|
|
||||||
|
|
||||||
StyledRect {
|
|
||||||
implicitWidth: implicitHeight
|
|
||||||
implicitHeight: wirelessIcon.implicitHeight + Appearance.padding.normal * 2
|
|
||||||
|
|
||||||
radius: Appearance.rounding.normal
|
|
||||||
color: (modelData && modelData.active) ? Colours.palette.m3primaryContainer : Colours.tPalette.m3surfaceContainerHigh
|
|
||||||
|
|
||||||
MaterialIcon {
|
|
||||||
id: wirelessIcon
|
|
||||||
|
|
||||||
anchors.centerIn: parent
|
|
||||||
text: Icons.getNetworkIcon(modelData && modelData.strength !== undefined ? modelData.strength : 0)
|
|
||||||
font.pointSize: Appearance.font.size.large
|
|
||||||
fill: (modelData && modelData.active) ? 1 : 0
|
|
||||||
color: (modelData && modelData.active) ? Colours.palette.m3onPrimaryContainer : Colours.palette.m3onSurface
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledRect {
|
|
||||||
id: lockBadge
|
|
||||||
|
|
||||||
visible: modelData && modelData.isSecure
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.margins: -Appearance.padding.smaller / 2
|
|
||||||
|
|
||||||
implicitWidth: lockIconSize + Appearance.padding.smaller
|
|
||||||
implicitHeight: lockIconSize + Appearance.padding.smaller
|
|
||||||
radius: Appearance.rounding.full
|
|
||||||
color: Colours.palette.m3secondaryContainer
|
|
||||||
|
|
||||||
readonly property real lockIconSize: lockIcon.implicitWidth
|
|
||||||
|
|
||||||
Elevation {
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: parent.radius
|
|
||||||
z: -1
|
|
||||||
level: 2
|
|
||||||
}
|
|
||||||
|
|
||||||
MaterialIcon {
|
|
||||||
id: lockIcon
|
|
||||||
|
|
||||||
anchors.centerIn: parent
|
|
||||||
text: "lock"
|
|
||||||
font.pointSize: Appearance.font.size.small
|
|
||||||
fill: 1
|
|
||||||
color: Colours.palette.m3onSurface
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
elide: Text.ElideRight
|
|
||||||
maximumLineCount: 1
|
|
||||||
|
|
||||||
text: (modelData && modelData.ssid) ? modelData.ssid : qsTr("Unknown")
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
spacing: Appearance.spacing.smaller
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
text: {
|
|
||||||
if (!modelData) return qsTr("Open");
|
|
||||||
if (modelData.active) return qsTr("Connected");
|
|
||||||
if (modelData.isSecure && modelData.security && modelData.security.length > 0) {
|
|
||||||
return modelData.security;
|
|
||||||
}
|
|
||||||
if (modelData.isSecure) return qsTr("Secured");
|
|
||||||
return qsTr("Open");
|
|
||||||
}
|
|
||||||
color: (modelData && modelData.active) ? Colours.palette.m3primary : Colours.palette.m3outline
|
|
||||||
font.pointSize: Appearance.font.size.small
|
|
||||||
font.weight: (modelData && modelData.active) ? 500 : 400
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledRect {
|
|
||||||
implicitWidth: implicitHeight
|
|
||||||
implicitHeight: wirelessConnectIcon.implicitHeight + Appearance.padding.smaller * 2
|
|
||||||
|
|
||||||
radius: Appearance.rounding.full
|
|
||||||
color: Qt.alpha(Colours.palette.m3primaryContainer, (modelData && modelData.active) ? 1 : 0)
|
|
||||||
|
|
||||||
StateLayer {
|
|
||||||
function onClicked(): void {
|
|
||||||
if (modelData && modelData.active) {
|
|
||||||
Nmcli.disconnectFromNetwork();
|
|
||||||
} else if (modelData) {
|
|
||||||
NetworkConnection.handleConnect(modelData, root.session, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MaterialIcon {
|
|
||||||
id: wirelessConnectIcon
|
|
||||||
|
|
||||||
anchors.centerIn: parent
|
|
||||||
text: (modelData && modelData.active) ? "link_off" : "link"
|
|
||||||
color: (modelData && modelData.active) ? Colours.palette.m3onPrimaryContainer : Colours.palette.m3onSurface
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
implicitHeight: wirelessRowLayout.implicitHeight + Appearance.padding.normal * 2
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -443,16 +156,17 @@ Item {
|
||||||
Item {
|
Item {
|
||||||
id: rightPaneItem
|
id: rightPaneItem
|
||||||
|
|
||||||
// Right pane - networking details/settings
|
|
||||||
property var ethernetPane: root.session.ethernet.active
|
property var ethernetPane: root.session.ethernet.active
|
||||||
property var wirelessPane: root.session.network.active
|
property var wirelessPane: root.session.network.active
|
||||||
property var pane: ethernetPane || wirelessPane
|
property var pane: ethernetPane || wirelessPane
|
||||||
property string paneId: ethernetPane ? ("eth:" + (ethernetPane.interface || "")) : (wirelessPane ? ("wifi:" + (wirelessPane.ssid || wirelessPane.bssid || "")) : "settings")
|
property string paneId: ethernetPane ? ("eth:" + (ethernetPane.interface || "")) : (wirelessPane ? ("wifi:" + (wirelessPane.ssid || wirelessPane.bssid || "")) : "settings")
|
||||||
property Component targetComponent: settings
|
property Component targetComponent: settingsComponent
|
||||||
property Component nextComponent: settings
|
property Component nextComponent: settingsComponent
|
||||||
|
|
||||||
function getComponentForPane() {
|
function getComponentForPane() {
|
||||||
return pane ? (ethernetPane ? ethernetDetails : wirelessDetails) : settings;
|
if (ethernetPane) return ethernetDetailsComponent;
|
||||||
|
if (wirelessPane) return wirelessDetailsComponent;
|
||||||
|
return settingsComponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
|
|
@ -507,7 +221,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: settings
|
id: settingsComponent
|
||||||
|
|
||||||
StyledFlickable {
|
StyledFlickable {
|
||||||
id: settingsFlickable
|
id: settingsFlickable
|
||||||
|
|
@ -530,7 +244,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: ethernetDetails
|
id: ethernetDetailsComponent
|
||||||
|
|
||||||
StyledFlickable {
|
StyledFlickable {
|
||||||
id: ethernetFlickable
|
id: ethernetFlickable
|
||||||
|
|
@ -553,7 +267,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: wirelessDetails
|
id: wirelessDetailsComponent
|
||||||
|
|
||||||
StyledFlickable {
|
StyledFlickable {
|
||||||
id: wirelessFlickable
|
id: wirelessFlickable
|
||||||
|
|
@ -580,11 +294,4 @@ Item {
|
||||||
session: root.session
|
session: root.session
|
||||||
z: 1000
|
z: 1000
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkSavedProfileForNetwork(ssid: string): void {
|
|
||||||
if (ssid && ssid.length > 0) {
|
|
||||||
Nmcli.loadSavedConnections(() => {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
pragma ComponentBehavior: Bound
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
import ".."
|
import ".."
|
||||||
|
import "../components"
|
||||||
import "."
|
import "."
|
||||||
import qs.components
|
import qs.components
|
||||||
import qs.components.controls
|
import qs.components.controls
|
||||||
|
|
@ -12,14 +13,13 @@ import qs.utils
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
Item {
|
DeviceDetails {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property Session session
|
required property Session session
|
||||||
readonly property var network: session.network.active
|
readonly property var network: session.network.active
|
||||||
|
|
||||||
implicitWidth: layout.implicitWidth
|
device: network
|
||||||
implicitHeight: layout.implicitHeight
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
updateDeviceDetails();
|
updateDeviceDetails();
|
||||||
|
|
@ -102,110 +102,120 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
headerComponent: Component {
|
||||||
id: layout
|
ConnectionHeader {
|
||||||
|
icon: root.network?.isSecure ? "lock" : "wifi"
|
||||||
anchors.left: parent.left
|
title: root.network?.ssid ?? qsTr("Unknown")
|
||||||
anchors.right: parent.right
|
}
|
||||||
anchors.top: parent.top
|
|
||||||
spacing: Appearance.spacing.normal
|
|
||||||
|
|
||||||
ConnectionHeader {
|
|
||||||
icon: root.network?.isSecure ? "lock" : "wifi"
|
|
||||||
title: root.network?.ssid ?? qsTr("Unknown")
|
|
||||||
}
|
|
||||||
|
|
||||||
SectionHeader {
|
|
||||||
title: qsTr("Connection status")
|
|
||||||
description: qsTr("Connection settings for this network")
|
|
||||||
}
|
|
||||||
|
|
||||||
SectionContainer {
|
|
||||||
ToggleRow {
|
|
||||||
label: qsTr("Connected")
|
|
||||||
checked: root.network?.active ?? false
|
|
||||||
toggle.onToggled: {
|
|
||||||
if (checked) {
|
|
||||||
NetworkConnection.handleConnect(root.network, root.session, null);
|
|
||||||
} else {
|
|
||||||
Nmcli.disconnectFromNetwork();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TextButton {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: Appearance.spacing.normal
|
|
||||||
Layout.minimumHeight: Appearance.font.size.normal + Appearance.padding.normal * 2
|
|
||||||
visible: {
|
|
||||||
if (!root.network || !root.network.ssid) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return Nmcli.hasSavedProfile(root.network.ssid);
|
|
||||||
}
|
|
||||||
inactiveColour: Colours.palette.m3secondaryContainer
|
|
||||||
inactiveOnColour: Colours.palette.m3onSecondaryContainer
|
|
||||||
text: qsTr("Forget Network")
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
if (root.network && root.network.ssid) {
|
|
||||||
if (root.network.active) {
|
|
||||||
Nmcli.disconnectFromNetwork();
|
|
||||||
}
|
|
||||||
Nmcli.forgetNetwork(root.network.ssid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SectionHeader {
|
|
||||||
title: qsTr("Network properties")
|
|
||||||
description: qsTr("Additional information")
|
|
||||||
}
|
|
||||||
|
|
||||||
SectionContainer {
|
|
||||||
contentSpacing: Appearance.spacing.small / 2
|
|
||||||
|
|
||||||
PropertyRow {
|
|
||||||
label: qsTr("SSID")
|
|
||||||
value: root.network?.ssid ?? qsTr("Unknown")
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyRow {
|
|
||||||
showTopMargin: true
|
|
||||||
label: qsTr("BSSID")
|
|
||||||
value: root.network?.bssid ?? qsTr("Unknown")
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyRow {
|
|
||||||
showTopMargin: true
|
|
||||||
label: qsTr("Signal strength")
|
|
||||||
value: root.network ? qsTr("%1%").arg(root.network.strength) : qsTr("N/A")
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyRow {
|
|
||||||
showTopMargin: true
|
|
||||||
label: qsTr("Frequency")
|
|
||||||
value: root.network ? qsTr("%1 MHz").arg(root.network.frequency) : qsTr("N/A")
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyRow {
|
|
||||||
showTopMargin: true
|
|
||||||
label: qsTr("Security")
|
|
||||||
value: root.network ? (root.network.isSecure ? root.network.security : qsTr("Open")) : qsTr("N/A")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SectionHeader {
|
|
||||||
title: qsTr("Connection information")
|
|
||||||
description: qsTr("Network connection details")
|
|
||||||
}
|
|
||||||
|
|
||||||
SectionContainer {
|
|
||||||
ConnectionInfoSection {
|
|
||||||
deviceDetails: Nmcli.wirelessDeviceDetails
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sections: [
|
||||||
|
Component {
|
||||||
|
ColumnLayout {
|
||||||
|
spacing: Appearance.spacing.normal
|
||||||
|
|
||||||
|
SectionHeader {
|
||||||
|
title: qsTr("Connection status")
|
||||||
|
description: qsTr("Connection settings for this network")
|
||||||
|
}
|
||||||
|
|
||||||
|
SectionContainer {
|
||||||
|
ToggleRow {
|
||||||
|
label: qsTr("Connected")
|
||||||
|
checked: root.network?.active ?? false
|
||||||
|
toggle.onToggled: {
|
||||||
|
if (checked) {
|
||||||
|
NetworkConnection.handleConnect(root.network, root.session, null);
|
||||||
|
} else {
|
||||||
|
Nmcli.disconnectFromNetwork();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextButton {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: Appearance.spacing.normal
|
||||||
|
Layout.minimumHeight: Appearance.font.size.normal + Appearance.padding.normal * 2
|
||||||
|
visible: {
|
||||||
|
if (!root.network || !root.network.ssid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Nmcli.hasSavedProfile(root.network.ssid);
|
||||||
|
}
|
||||||
|
inactiveColour: Colours.palette.m3secondaryContainer
|
||||||
|
inactiveOnColour: Colours.palette.m3onSecondaryContainer
|
||||||
|
text: qsTr("Forget Network")
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
if (root.network && root.network.ssid) {
|
||||||
|
if (root.network.active) {
|
||||||
|
Nmcli.disconnectFromNetwork();
|
||||||
|
}
|
||||||
|
Nmcli.forgetNetwork(root.network.ssid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Component {
|
||||||
|
ColumnLayout {
|
||||||
|
spacing: Appearance.spacing.normal
|
||||||
|
|
||||||
|
SectionHeader {
|
||||||
|
title: qsTr("Network properties")
|
||||||
|
description: qsTr("Additional information")
|
||||||
|
}
|
||||||
|
|
||||||
|
SectionContainer {
|
||||||
|
contentSpacing: Appearance.spacing.small / 2
|
||||||
|
|
||||||
|
PropertyRow {
|
||||||
|
label: qsTr("SSID")
|
||||||
|
value: root.network?.ssid ?? qsTr("Unknown")
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyRow {
|
||||||
|
showTopMargin: true
|
||||||
|
label: qsTr("BSSID")
|
||||||
|
value: root.network?.bssid ?? qsTr("Unknown")
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyRow {
|
||||||
|
showTopMargin: true
|
||||||
|
label: qsTr("Signal strength")
|
||||||
|
value: root.network ? qsTr("%1%").arg(root.network.strength) : qsTr("N/A")
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyRow {
|
||||||
|
showTopMargin: true
|
||||||
|
label: qsTr("Frequency")
|
||||||
|
value: root.network ? qsTr("%1 MHz").arg(root.network.frequency) : qsTr("N/A")
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyRow {
|
||||||
|
showTopMargin: true
|
||||||
|
label: qsTr("Security")
|
||||||
|
value: root.network ? (root.network.isSecure ? root.network.security : qsTr("Open")) : qsTr("N/A")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Component {
|
||||||
|
ColumnLayout {
|
||||||
|
spacing: Appearance.spacing.normal
|
||||||
|
|
||||||
|
SectionHeader {
|
||||||
|
title: qsTr("Connection information")
|
||||||
|
description: qsTr("Network connection details")
|
||||||
|
}
|
||||||
|
|
||||||
|
SectionContainer {
|
||||||
|
ConnectionInfoSection {
|
||||||
|
deviceDetails: Nmcli.wirelessDeviceDetails
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import qs.components.containers
|
||||||
import qs.services
|
import qs.services
|
||||||
import qs.config
|
import qs.config
|
||||||
import qs.utils
|
import qs.utils
|
||||||
|
import Quickshell
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
|
@ -58,6 +59,9 @@ DeviceList {
|
||||||
toggled: Nmcli.wifiEnabled
|
toggled: Nmcli.wifiEnabled
|
||||||
icon: "wifi"
|
icon: "wifi"
|
||||||
accent: "Tertiary"
|
accent: "Tertiary"
|
||||||
|
iconSize: Appearance.font.size.normal
|
||||||
|
horizontalPadding: Appearance.padding.normal
|
||||||
|
verticalPadding: Appearance.padding.smaller
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
Nmcli.toggleWifi(null);
|
Nmcli.toggleWifi(null);
|
||||||
|
|
@ -68,6 +72,9 @@ DeviceList {
|
||||||
toggled: Nmcli.scanning
|
toggled: Nmcli.scanning
|
||||||
icon: "wifi_find"
|
icon: "wifi_find"
|
||||||
accent: "Secondary"
|
accent: "Secondary"
|
||||||
|
iconSize: Appearance.font.size.normal
|
||||||
|
horizontalPadding: Appearance.padding.normal
|
||||||
|
verticalPadding: Appearance.padding.smaller
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
Nmcli.rescanWifi();
|
Nmcli.rescanWifi();
|
||||||
|
|
@ -78,6 +85,9 @@ DeviceList {
|
||||||
toggled: !root.session.network.active
|
toggled: !root.session.network.active
|
||||||
icon: "settings"
|
icon: "settings"
|
||||||
accent: "Primary"
|
accent: "Primary"
|
||||||
|
iconSize: Appearance.font.size.normal
|
||||||
|
horizontalPadding: Appearance.padding.normal
|
||||||
|
verticalPadding: Appearance.padding.smaller
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (root.session.network.active)
|
if (root.session.network.active)
|
||||||
|
|
@ -94,8 +104,7 @@ DeviceList {
|
||||||
StyledRect {
|
StyledRect {
|
||||||
required property var modelData
|
required property var modelData
|
||||||
|
|
||||||
anchors.left: parent.left
|
width: ListView.view ? ListView.view.width : undefined
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
color: Qt.alpha(Colours.tPalette.m3surfaceContainer, root.activeItem === modelData ? Colours.tPalette.m3surfaceContainer.a : 0)
|
color: Qt.alpha(Colours.tPalette.m3surfaceContainer, root.activeItem === modelData ? Colours.tPalette.m3surfaceContainer.a : 0)
|
||||||
radius: Appearance.rounding.normal
|
radius: Appearance.rounding.normal
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue