mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-07 22:15:38 -05:00
qmlfmt with 4 space
This commit is contained in:
@@ -9,140 +9,142 @@ import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Column {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
property string currentSinkDisplayName: AudioService.sink ? AudioService.displayName(
|
||||
AudioService.sink) : ""
|
||||
property string currentSinkDisplayName: AudioService.sink ? AudioService.displayName(
|
||||
AudioService.sink) : ""
|
||||
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: "Output Device"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 35
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
||||
border.color: Qt.rgba(Theme.primary.r, Theme.primary.g,
|
||||
Theme.primary.b, 0.3)
|
||||
border.width: 1
|
||||
visible: AudioService.sink !== null
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: "check_circle"
|
||||
size: Theme.iconSize - 4
|
||||
color: Theme.primary
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Current: " + (root.currentSinkDisplayName || "None")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.primary
|
||||
StyledText {
|
||||
text: "Output Device"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: {
|
||||
if (!Pipewire.ready || !Pipewire.nodes || !Pipewire.nodes.values)
|
||||
return []
|
||||
|
||||
let sinks = []
|
||||
for (var i = 0; i < Pipewire.nodes.values.length; i++) {
|
||||
let node = Pipewire.nodes.values[i]
|
||||
if (!node || node.isStream)
|
||||
continue
|
||||
|
||||
if ((node.type & PwNodeType.AudioSink) === PwNodeType.AudioSink)
|
||||
sinks.push(node)
|
||||
}
|
||||
return sinks
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: deviceArea.containsMouse ? Qt.rgba(
|
||||
Theme.primary.r, Theme.primary.g,
|
||||
Theme.primary.b, 0.08) : (modelData === AudioService.sink ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08))
|
||||
border.color: modelData === AudioService.sink ? Theme.primary : "transparent"
|
||||
border.width: 1
|
||||
width: parent.width
|
||||
height: 35
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
||||
border.color: Qt.rgba(Theme.primary.r, Theme.primary.g,
|
||||
Theme.primary.b, 0.3)
|
||||
border.width: 1
|
||||
visible: AudioService.sink !== null
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: {
|
||||
if (modelData.name.includes("bluez"))
|
||||
return "headset"
|
||||
else if (modelData.name.includes("hdmi"))
|
||||
return "tv"
|
||||
else if (modelData.name.includes("usb"))
|
||||
return "headset"
|
||||
else
|
||||
return "speaker"
|
||||
}
|
||||
size: Theme.iconSize
|
||||
color: modelData === AudioService.sink ? Theme.primary : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
spacing: 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: AudioService.displayName(modelData)
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: modelData === AudioService.sink ? Theme.primary : Theme.surfaceText
|
||||
font.weight: modelData === AudioService.sink ? Font.Medium : Font.Normal
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (AudioService.subtitle(modelData.name)
|
||||
&& AudioService.subtitle(modelData.name) !== "")
|
||||
return AudioService.subtitle(
|
||||
modelData.name) + (modelData === AudioService.sink ? " • Selected" : "")
|
||||
else
|
||||
return modelData === AudioService.sink ? "Selected" : ""
|
||||
DankIcon {
|
||||
name: "check_circle"
|
||||
size: Theme.iconSize - 4
|
||||
color: Theme.primary
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.7)
|
||||
visible: text !== ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: deviceArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (modelData)
|
||||
Pipewire.preferredDefaultAudioSink = modelData
|
||||
StyledText {
|
||||
text: "Current: " + (root.currentSinkDisplayName || "None")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.primary
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: {
|
||||
if (!Pipewire.ready || !Pipewire.nodes || !Pipewire.nodes.values)
|
||||
return []
|
||||
|
||||
let sinks = []
|
||||
for (var i = 0; i < Pipewire.nodes.values.length; i++) {
|
||||
let node = Pipewire.nodes.values[i]
|
||||
if (!node || node.isStream)
|
||||
continue
|
||||
|
||||
if ((node.type & PwNodeType.AudioSink) === PwNodeType.AudioSink)
|
||||
sinks.push(node)
|
||||
}
|
||||
return sinks
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: deviceArea.containsMouse ? Qt.rgba(
|
||||
Theme.primary.r, Theme.primary.g,
|
||||
Theme.primary.b, 0.08) : (modelData === AudioService.sink ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08))
|
||||
border.color: modelData === AudioService.sink ? Theme.primary : "transparent"
|
||||
border.width: 1
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: {
|
||||
if (modelData.name.includes("bluez"))
|
||||
return "headset"
|
||||
else if (modelData.name.includes("hdmi"))
|
||||
return "tv"
|
||||
else if (modelData.name.includes("usb"))
|
||||
return "headset"
|
||||
else
|
||||
return "speaker"
|
||||
}
|
||||
size: Theme.iconSize
|
||||
color: modelData === AudioService.sink ? Theme.primary : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
spacing: 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: AudioService.displayName(modelData)
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: modelData === AudioService.sink ? Theme.primary : Theme.surfaceText
|
||||
font.weight: modelData === AudioService.sink ? Font.Medium : Font.Normal
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (AudioService.subtitle(modelData.name)
|
||||
&& AudioService.subtitle(
|
||||
modelData.name) !== "")
|
||||
return AudioService.subtitle(modelData.name)
|
||||
+ (modelData === AudioService.sink ? " • Selected" : "")
|
||||
else
|
||||
return modelData === AudioService.sink ? "Selected" : ""
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r,
|
||||
Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.7)
|
||||
visible: text !== ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: deviceArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (modelData)
|
||||
Pipewire.preferredDefaultAudioSink = modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,139 +9,141 @@ import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Column {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
property string currentSourceDisplayName: AudioService.source ? AudioService.displayName(
|
||||
AudioService.source) : ""
|
||||
property string currentSourceDisplayName: AudioService.source ? AudioService.displayName(
|
||||
AudioService.source) : ""
|
||||
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: "Input Device"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 35
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
||||
border.color: Qt.rgba(Theme.primary.r, Theme.primary.g,
|
||||
Theme.primary.b, 0.3)
|
||||
border.width: 1
|
||||
visible: AudioService.source !== null
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: "check_circle"
|
||||
size: Theme.iconSize - 4
|
||||
color: Theme.primary
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Current: " + (root.currentSourceDisplayName || "None")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.primary
|
||||
StyledText {
|
||||
text: "Input Device"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: {
|
||||
if (!Pipewire.ready || !Pipewire.nodes || !Pipewire.nodes.values)
|
||||
return []
|
||||
|
||||
let sources = []
|
||||
for (var i = 0; i < Pipewire.nodes.values.length; i++) {
|
||||
let node = Pipewire.nodes.values[i]
|
||||
if (!node || node.isStream)
|
||||
continue
|
||||
|
||||
if ((node.type & PwNodeType.AudioSource) === PwNodeType.AudioSource
|
||||
&& !node.name.includes(".monitor"))
|
||||
sources.push(node)
|
||||
}
|
||||
return sources
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: sourceArea.containsMouse ? Qt.rgba(
|
||||
Theme.primary.r, Theme.primary.g,
|
||||
Theme.primary.b, 0.08) : (modelData === AudioService.source ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08))
|
||||
border.color: modelData === AudioService.source ? Theme.primary : "transparent"
|
||||
border.width: 1
|
||||
width: parent.width
|
||||
height: 35
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
||||
border.color: Qt.rgba(Theme.primary.r, Theme.primary.g,
|
||||
Theme.primary.b, 0.3)
|
||||
border.width: 1
|
||||
visible: AudioService.source !== null
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: {
|
||||
if (modelData.name.includes("bluez"))
|
||||
return "headset_mic"
|
||||
else if (modelData.name.includes("usb"))
|
||||
return "headset_mic"
|
||||
else
|
||||
return "mic"
|
||||
}
|
||||
size: Theme.iconSize
|
||||
color: modelData === AudioService.source ? Theme.primary : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
spacing: 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: AudioService.displayName(modelData)
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: modelData === AudioService.source ? Theme.primary : Theme.surfaceText
|
||||
font.weight: modelData === AudioService.source ? Font.Medium : Font.Normal
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (AudioService.subtitle(modelData.name)
|
||||
&& AudioService.subtitle(modelData.name) !== "")
|
||||
return AudioService.subtitle(
|
||||
modelData.name) + (modelData === AudioService.source ? " • Selected" : "")
|
||||
else
|
||||
return modelData === AudioService.source ? "Selected" : ""
|
||||
DankIcon {
|
||||
name: "check_circle"
|
||||
size: Theme.iconSize - 4
|
||||
color: Theme.primary
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.7)
|
||||
visible: text !== ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: sourceArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (modelData)
|
||||
Pipewire.preferredDefaultAudioSource = modelData
|
||||
StyledText {
|
||||
text: "Current: " + (root.currentSourceDisplayName || "None")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.primary
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: {
|
||||
if (!Pipewire.ready || !Pipewire.nodes || !Pipewire.nodes.values)
|
||||
return []
|
||||
|
||||
let sources = []
|
||||
for (var i = 0; i < Pipewire.nodes.values.length; i++) {
|
||||
let node = Pipewire.nodes.values[i]
|
||||
if (!node || node.isStream)
|
||||
continue
|
||||
|
||||
if ((node.type & PwNodeType.AudioSource) === PwNodeType.AudioSource
|
||||
&& !node.name.includes(".monitor"))
|
||||
sources.push(node)
|
||||
}
|
||||
return sources
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: sourceArea.containsMouse ? Qt.rgba(
|
||||
Theme.primary.r, Theme.primary.g,
|
||||
Theme.primary.b, 0.08) : (modelData === AudioService.source ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08))
|
||||
border.color: modelData === AudioService.source ? Theme.primary : "transparent"
|
||||
border.width: 1
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: {
|
||||
if (modelData.name.includes("bluez"))
|
||||
return "headset_mic"
|
||||
else if (modelData.name.includes("usb"))
|
||||
return "headset_mic"
|
||||
else
|
||||
return "mic"
|
||||
}
|
||||
size: Theme.iconSize
|
||||
color: modelData === AudioService.source ? Theme.primary : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
spacing: 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: AudioService.displayName(modelData)
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: modelData === AudioService.source ? Theme.primary : Theme.surfaceText
|
||||
font.weight: modelData === AudioService.source ? Font.Medium : Font.Normal
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (AudioService.subtitle(modelData.name)
|
||||
&& AudioService.subtitle(
|
||||
modelData.name) !== "")
|
||||
return AudioService.subtitle(modelData.name)
|
||||
+ (modelData === AudioService.source ? " • Selected" : "")
|
||||
else
|
||||
return modelData === AudioService.source ? "Selected" : ""
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r,
|
||||
Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.7)
|
||||
visible: text !== ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: sourceArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (modelData)
|
||||
Pipewire.preferredDefaultAudioSource = modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,222 +8,232 @@ import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Column {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
property real micLevel: Math.min(
|
||||
100,
|
||||
(AudioService.source && AudioService.source.audio
|
||||
&& AudioService.source.audio.volume * 100) || 0)
|
||||
property bool micMuted: (AudioService.source && AudioService.source.audio
|
||||
&& AudioService.source.audio.muted) || false
|
||||
property real micLevel: Math.min(100,
|
||||
(AudioService.source
|
||||
&& AudioService.source.audio
|
||||
&& AudioService.source.audio.volume * 100)
|
||||
|| 0)
|
||||
property bool micMuted: (AudioService.source && AudioService.source.audio
|
||||
&& AudioService.source.audio.muted) || false
|
||||
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: "Microphone Level"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: root.micMuted ? "mic_off" : "mic"
|
||||
size: Theme.iconSize
|
||||
color: root.micMuted ? Theme.error : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (AudioService.source && AudioService.source.audio)
|
||||
AudioService.source.audio.muted = !AudioService.source.audio.muted
|
||||
}
|
||||
}
|
||||
StyledText {
|
||||
text: "Microphone Level"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
Item {
|
||||
id: micSliderContainer
|
||||
|
||||
width: parent.width - 80
|
||||
height: 32
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Rectangle {
|
||||
id: micSliderTrack
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 8
|
||||
radius: 4
|
||||
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
|
||||
Theme.surfaceVariant.b, 0.3)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Rectangle {
|
||||
id: micSliderFill
|
||||
DankIcon {
|
||||
name: root.micMuted ? "mic_off" : "mic"
|
||||
size: Theme.iconSize
|
||||
color: root.micMuted ? Theme.error : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
width: parent.width * (root.micLevel / 100)
|
||||
height: parent.height
|
||||
radius: parent.radius
|
||||
color: Theme.primary
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: Anims.durShort
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Anims.standardDecel
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (AudioService.source && AudioService.source.audio)
|
||||
AudioService.source.audio.muted = !AudioService.source.audio.muted
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: micHandle
|
||||
Item {
|
||||
id: micSliderContainer
|
||||
|
||||
width: 18
|
||||
height: 18
|
||||
radius: 9
|
||||
color: Theme.primary
|
||||
border.color: Qt.lighter(Theme.primary, 1.3)
|
||||
border.width: 2
|
||||
x: Math.max(0, Math.min(parent.width - width,
|
||||
micSliderFill.width - width / 2))
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
scale: micMouseArea.containsMouse || micMouseArea.pressed ? 1.2 : 1
|
||||
width: parent.width - 80
|
||||
height: 32
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Rectangle {
|
||||
id: micTooltip
|
||||
Rectangle {
|
||||
id: micSliderTrack
|
||||
|
||||
width: tooltipText.contentWidth + Theme.spacingS * 2
|
||||
height: tooltipText.contentHeight + Theme.spacingXS * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainer
|
||||
border.color: Theme.outline
|
||||
border.width: 1
|
||||
anchors.bottom: parent.top
|
||||
anchors.bottomMargin: Theme.spacingS
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: (micMouseArea.containsMouse && !root.micMuted)
|
||||
|| micMouseArea.isDragging
|
||||
opacity: visible ? 1 : 0
|
||||
width: parent.width
|
||||
height: 8
|
||||
radius: 4
|
||||
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
|
||||
Theme.surfaceVariant.b, 0.3)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
id: tooltipText
|
||||
Rectangle {
|
||||
id: micSliderFill
|
||||
|
||||
text: Math.round(root.micLevel) + "%"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.centerIn: parent
|
||||
width: parent.width * (root.micLevel / 100)
|
||||
height: parent.height
|
||||
radius: parent.radius
|
||||
color: Theme.primary
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: Anims.durShort
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Anims.standardDecel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: micHandle
|
||||
|
||||
width: 18
|
||||
height: 18
|
||||
radius: 9
|
||||
color: Theme.primary
|
||||
border.color: Qt.lighter(Theme.primary, 1.3)
|
||||
border.width: 2
|
||||
x: Math.max(0, Math.min(parent.width - width,
|
||||
micSliderFill.width - width / 2))
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
scale: micMouseArea.containsMouse
|
||||
|| micMouseArea.pressed ? 1.2 : 1
|
||||
|
||||
Rectangle {
|
||||
id: micTooltip
|
||||
|
||||
width: tooltipText.contentWidth + Theme.spacingS * 2
|
||||
height: tooltipText.contentHeight + Theme.spacingXS * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainer
|
||||
border.color: Theme.outline
|
||||
border.width: 1
|
||||
anchors.bottom: parent.top
|
||||
anchors.bottomMargin: Theme.spacingS
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: (micMouseArea.containsMouse && !root.micMuted)
|
||||
|| micMouseArea.isDragging
|
||||
opacity: visible ? 1 : 0
|
||||
|
||||
StyledText {
|
||||
id: tooltipText
|
||||
|
||||
text: Math.round(root.micLevel) + "%"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Anims.durShort
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Anims.standard
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
MouseArea {
|
||||
id: micMouseArea
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Anims.durShort
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Anims.standard
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
property bool isDragging: false
|
||||
|
||||
MouseArea {
|
||||
id: micMouseArea
|
||||
|
||||
property bool isDragging: false
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
preventStealing: true
|
||||
onPressed: mouse => {
|
||||
isDragging = true
|
||||
let ratio = Math.max(0, Math.min(
|
||||
1, mouse.x / micSliderTrack.width))
|
||||
let newMicLevel = Math.round(ratio * 100)
|
||||
if (AudioService.source && AudioService.source.audio) {
|
||||
AudioService.source.audio.muted = false
|
||||
AudioService.source.audio.volume = newMicLevel / 100
|
||||
}
|
||||
}
|
||||
onReleased: {
|
||||
isDragging = false
|
||||
}
|
||||
onPositionChanged: mouse => {
|
||||
if (pressed && isDragging) {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
preventStealing: true
|
||||
onPressed: mouse => {
|
||||
isDragging = true
|
||||
let ratio = Math.max(
|
||||
0, Math.min(1, mouse.x / micSliderTrack.width))
|
||||
let newMicLevel = Math.max(
|
||||
0, Math.min(100, Math.round(ratio * 100)))
|
||||
0, Math.min(1,
|
||||
mouse.x / micSliderTrack.width))
|
||||
let newMicLevel = Math.round(ratio * 100)
|
||||
if (AudioService.source
|
||||
&& AudioService.source.audio) {
|
||||
AudioService.source.audio.muted = false
|
||||
AudioService.source.audio.volume = newMicLevel / 100
|
||||
AudioService.source.audio.muted = false
|
||||
AudioService.source.audio.volume = newMicLevel / 100
|
||||
}
|
||||
}
|
||||
}
|
||||
onClicked: mouse => {
|
||||
let ratio = Math.max(0, Math.min(
|
||||
1, mouse.x / micSliderTrack.width))
|
||||
let newMicLevel = Math.round(ratio * 100)
|
||||
if (AudioService.source && AudioService.source.audio) {
|
||||
AudioService.source.audio.muted = false
|
||||
AudioService.source.audio.volume = newMicLevel / 100
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: micGlobalMouseArea
|
||||
|
||||
x: 0
|
||||
y: 0
|
||||
width: root.parent ? root.parent.width : 0
|
||||
height: root.parent ? root.parent.height : 0
|
||||
enabled: micMouseArea.isDragging
|
||||
visible: false
|
||||
preventStealing: true
|
||||
onPositionChanged: mouse => {
|
||||
if (micMouseArea.isDragging) {
|
||||
let globalPos = mapToItem(micSliderTrack,
|
||||
mouse.x, mouse.y)
|
||||
onReleased: {
|
||||
isDragging = false
|
||||
}
|
||||
onPositionChanged: mouse => {
|
||||
if (pressed && isDragging) {
|
||||
let ratio = Math.max(
|
||||
0, Math.min(
|
||||
1,
|
||||
mouse.x / micSliderTrack.width))
|
||||
let newMicLevel = Math.max(
|
||||
0, Math.min(100, Math.round(
|
||||
ratio * 100)))
|
||||
if (AudioService.source
|
||||
&& AudioService.source.audio) {
|
||||
AudioService.source.audio.muted = false
|
||||
AudioService.source.audio.volume = newMicLevel / 100
|
||||
}
|
||||
}
|
||||
}
|
||||
onClicked: mouse => {
|
||||
let ratio = Math.max(
|
||||
0,
|
||||
Math.min(1,
|
||||
globalPos.x / micSliderTrack.width))
|
||||
let newMicLevel = Math.max(
|
||||
0, Math.min(100, Math.round(ratio * 100)))
|
||||
0, Math.min(1,
|
||||
mouse.x / micSliderTrack.width))
|
||||
let newMicLevel = Math.round(ratio * 100)
|
||||
if (AudioService.source
|
||||
&& AudioService.source.audio) {
|
||||
AudioService.source.audio.muted = false
|
||||
AudioService.source.audio.volume = newMicLevel / 100
|
||||
AudioService.source.audio.muted = false
|
||||
AudioService.source.audio.volume = newMicLevel / 100
|
||||
}
|
||||
}
|
||||
}
|
||||
onReleased: {
|
||||
micMouseArea.isDragging = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
name: "mic"
|
||||
size: Theme.iconSize
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
MouseArea {
|
||||
id: micGlobalMouseArea
|
||||
|
||||
x: 0
|
||||
y: 0
|
||||
width: root.parent ? root.parent.width : 0
|
||||
height: root.parent ? root.parent.height : 0
|
||||
enabled: micMouseArea.isDragging
|
||||
visible: false
|
||||
preventStealing: true
|
||||
onPositionChanged: mouse => {
|
||||
if (micMouseArea.isDragging) {
|
||||
let globalPos = mapToItem(
|
||||
micSliderTrack, mouse.x, mouse.y)
|
||||
let ratio = Math.max(
|
||||
0, Math.min(
|
||||
1,
|
||||
globalPos.x / micSliderTrack.width))
|
||||
let newMicLevel = Math.max(
|
||||
0, Math.min(100, Math.round(
|
||||
ratio * 100)))
|
||||
if (AudioService.source
|
||||
&& AudioService.source.audio) {
|
||||
AudioService.source.audio.muted = false
|
||||
AudioService.source.audio.volume = newMicLevel / 100
|
||||
}
|
||||
}
|
||||
}
|
||||
onReleased: {
|
||||
micMouseArea.isDragging = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
name: "mic"
|
||||
size: Theme.iconSize
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,63 +4,66 @@ import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Column {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
property real volumeLevel: Math.min(
|
||||
100,
|
||||
(AudioService.sink && AudioService.sink.audio
|
||||
&& AudioService.sink.audio.volume * 100) || 0)
|
||||
property bool volumeMuted: (AudioService.sink && AudioService.sink.audio
|
||||
&& AudioService.sink.audio.muted) || false
|
||||
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: "Volume"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
DankSlider {
|
||||
id: volumeSlider
|
||||
property real volumeLevel: Math.min(
|
||||
100,
|
||||
(AudioService.sink && AudioService.sink.audio
|
||||
&& AudioService.sink.audio.volume * 100)
|
||||
|| 0)
|
||||
property bool volumeMuted: (AudioService.sink && AudioService.sink.audio
|
||||
&& AudioService.sink.audio.muted) || false
|
||||
|
||||
width: parent.width
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
leftIcon: root.volumeMuted ? "volume_off" : "volume_down"
|
||||
rightIcon: "volume_up"
|
||||
enabled: !root.volumeMuted
|
||||
showValue: true
|
||||
unit: "%"
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Connections {
|
||||
target: AudioService.sink
|
||||
&& AudioService.sink.audio ? AudioService.sink.audio : null
|
||||
function onVolumeChanged() {
|
||||
volumeSlider.value = Math.round(AudioService.sink.audio.volume * 100)
|
||||
}
|
||||
StyledText {
|
||||
text: "Volume"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (AudioService.sink && AudioService.sink.audio) {
|
||||
value = Math.round(AudioService.sink.audio.volume * 100)
|
||||
}
|
||||
DankSlider {
|
||||
id: volumeSlider
|
||||
|
||||
let leftIconItem = volumeSlider.children[0].children[0]
|
||||
if (leftIconItem) {
|
||||
let mouseArea = Qt.createQmlObject(
|
||||
'import QtQuick; import qs.Services; MouseArea { anchors.fill: parent; hoverEnabled: true; cursorShape: Qt.PointingHandCursor; onClicked: { if (AudioService.sink && AudioService.sink.audio) AudioService.sink.audio.muted = !AudioService.sink.audio.muted; } }',
|
||||
leftIconItem, "dynamicMouseArea")
|
||||
}
|
||||
width: parent.width
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
leftIcon: root.volumeMuted ? "volume_off" : "volume_down"
|
||||
rightIcon: "volume_up"
|
||||
enabled: !root.volumeMuted
|
||||
showValue: true
|
||||
unit: "%"
|
||||
|
||||
Connections {
|
||||
target: AudioService.sink
|
||||
&& AudioService.sink.audio ? AudioService.sink.audio : null
|
||||
function onVolumeChanged() {
|
||||
volumeSlider.value = Math.round(
|
||||
AudioService.sink.audio.volume * 100)
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (AudioService.sink && AudioService.sink.audio) {
|
||||
value = Math.round(AudioService.sink.audio.volume * 100)
|
||||
}
|
||||
|
||||
let leftIconItem = volumeSlider.children[0].children[0]
|
||||
if (leftIconItem) {
|
||||
let mouseArea = Qt.createQmlObject(
|
||||
'import QtQuick; import qs.Services; MouseArea { anchors.fill: parent; hoverEnabled: true; cursorShape: Qt.PointingHandCursor; onClicked: { if (AudioService.sink && AudioService.sink.audio) AudioService.sink.audio.muted = !AudioService.sink.audio.muted; } }',
|
||||
leftIconItem, "dynamicMouseArea")
|
||||
}
|
||||
}
|
||||
|
||||
onSliderValueChanged: newValue => {
|
||||
if (AudioService.sink
|
||||
&& AudioService.sink.audio) {
|
||||
AudioService.sink.audio.muted = false
|
||||
AudioService.sink.audio.volume = newValue / 100
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onSliderValueChanged: newValue => {
|
||||
if (AudioService.sink && AudioService.sink.audio) {
|
||||
AudioService.sink.audio.muted = false
|
||||
AudioService.sink.audio.volume = newValue / 100
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,119 +10,119 @@ import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: audioTab
|
||||
id: audioTab
|
||||
|
||||
property int audioSubTab: 0
|
||||
property int audioSubTab: 0
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
spacing: Theme.spacingM
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankTabBar {
|
||||
width: parent.width
|
||||
tabHeight: 40
|
||||
currentIndex: audioTab.audioSubTab
|
||||
showIcons: false
|
||||
model: [{
|
||||
"text": "Output"
|
||||
}, {
|
||||
"text": "Input"
|
||||
}]
|
||||
onTabClicked: function (index) {
|
||||
audioTab.audioSubTab = index
|
||||
}
|
||||
}
|
||||
|
||||
// Single Loader that switches between Output and Input
|
||||
Loader {
|
||||
width: parent.width
|
||||
height: parent.height - 48
|
||||
asynchronous: true
|
||||
sourceComponent: audioTab.audioSubTab === 0 ? outputTabComponent : inputTabComponent
|
||||
}
|
||||
}
|
||||
|
||||
// Output Tab Component
|
||||
Component {
|
||||
id: outputTabComponent
|
||||
DankFlickable {
|
||||
clip: true
|
||||
contentHeight: outputColumn.height
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: outputColumn
|
||||
width: parent.width
|
||||
spacing: Theme.spacingL
|
||||
|
||||
Loader {
|
||||
width: parent.width
|
||||
sourceComponent: volumeComponent
|
||||
DankTabBar {
|
||||
width: parent.width
|
||||
tabHeight: 40
|
||||
currentIndex: audioTab.audioSubTab
|
||||
showIcons: false
|
||||
model: [{
|
||||
"text": "Output"
|
||||
}, {
|
||||
"text": "Input"
|
||||
}]
|
||||
onTabClicked: function (index) {
|
||||
audioTab.audioSubTab = index
|
||||
}
|
||||
}
|
||||
|
||||
// Single Loader that switches between Output and Input
|
||||
Loader {
|
||||
width: parent.width
|
||||
sourceComponent: outputDevicesComponent
|
||||
width: parent.width
|
||||
height: parent.height - 48
|
||||
asynchronous: true
|
||||
sourceComponent: audioTab.audioSubTab === 0 ? outputTabComponent : inputTabComponent
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Input Tab Component
|
||||
Component {
|
||||
id: inputTabComponent
|
||||
DankFlickable {
|
||||
clip: true
|
||||
contentHeight: inputColumn.height
|
||||
contentWidth: width
|
||||
// Output Tab Component
|
||||
Component {
|
||||
id: outputTabComponent
|
||||
DankFlickable {
|
||||
clip: true
|
||||
contentHeight: outputColumn.height
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: inputColumn
|
||||
width: parent.width
|
||||
spacing: Theme.spacingL
|
||||
Column {
|
||||
id: outputColumn
|
||||
width: parent.width
|
||||
spacing: Theme.spacingL
|
||||
|
||||
Loader {
|
||||
width: parent.width
|
||||
sourceComponent: microphoneComponent
|
||||
Loader {
|
||||
width: parent.width
|
||||
sourceComponent: volumeComponent
|
||||
}
|
||||
|
||||
Loader {
|
||||
width: parent.width
|
||||
sourceComponent: outputDevicesComponent
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
width: parent.width
|
||||
sourceComponent: inputDevicesComponent
|
||||
// Input Tab Component
|
||||
Component {
|
||||
id: inputTabComponent
|
||||
DankFlickable {
|
||||
clip: true
|
||||
contentHeight: inputColumn.height
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: inputColumn
|
||||
width: parent.width
|
||||
spacing: Theme.spacingL
|
||||
|
||||
Loader {
|
||||
width: parent.width
|
||||
sourceComponent: microphoneComponent
|
||||
}
|
||||
|
||||
Loader {
|
||||
width: parent.width
|
||||
sourceComponent: inputDevicesComponent
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Volume Control Component
|
||||
Component {
|
||||
id: volumeComponent
|
||||
VolumeControl {
|
||||
width: parent.width
|
||||
// Volume Control Component
|
||||
Component {
|
||||
id: volumeComponent
|
||||
VolumeControl {
|
||||
width: parent.width
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Microphone Control Component
|
||||
Component {
|
||||
id: microphoneComponent
|
||||
MicrophoneControl {
|
||||
width: parent.width
|
||||
// Microphone Control Component
|
||||
Component {
|
||||
id: microphoneComponent
|
||||
MicrophoneControl {
|
||||
width: parent.width
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Output Devices Component
|
||||
Component {
|
||||
id: outputDevicesComponent
|
||||
AudioDevicesList {
|
||||
width: parent.width
|
||||
// Output Devices Component
|
||||
Component {
|
||||
id: outputDevicesComponent
|
||||
AudioDevicesList {
|
||||
width: parent.width
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Input Devices Component
|
||||
Component {
|
||||
id: inputDevicesComponent
|
||||
AudioInputDevicesList {
|
||||
width: parent.width
|
||||
// Input Devices Component
|
||||
Component {
|
||||
id: inputDevicesComponent
|
||||
AudioInputDevicesList {
|
||||
width: parent.width
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,427 +9,444 @@ import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Column {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
visible: BluetoothService.adapter && BluetoothService.adapter.enabled
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: "Available Devices"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width - scanButton.width - parent.spacing - 150 // Spacer to push button right
|
||||
height: 1
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: scanButton
|
||||
|
||||
width: Math.max(100, scanText.contentWidth + Theme.spacingL * 2)
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: scanArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.12) : Qt.rgba(Theme.primary.r,
|
||||
Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.08)
|
||||
border.color: Theme.primary
|
||||
border.width: 1
|
||||
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
DankIcon {
|
||||
name: BluetoothService.adapter
|
||||
&& BluetoothService.adapter.discovering ? "stop" : "bluetooth_searching"
|
||||
size: Theme.iconSize - 6
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: scanText
|
||||
|
||||
text: BluetoothService.adapter
|
||||
&& BluetoothService.adapter.discovering ? "Stop Scanning" : "Scan"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.primary
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: scanArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (BluetoothService.adapter)
|
||||
BluetoothService.adapter.discovering = !BluetoothService.adapter.discovering
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: noteColumn.implicitHeight + Theme.spacingM * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.08)
|
||||
border.color: Qt.rgba(Theme.warning.r, Theme.warning.g,
|
||||
Theme.warning.b, 0.2)
|
||||
border.width: 1
|
||||
|
||||
Column {
|
||||
id: noteColumn
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingM
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: "info"
|
||||
size: Theme.iconSize - 2
|
||||
color: Theme.warning
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Pairing Limitation"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.warning
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Quickshell does not support pairing devices that require pin or confirmation."
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.8)
|
||||
wrapMode: Text.WordWrap
|
||||
width: parent.width
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: {
|
||||
if (!BluetoothService.adapter || !BluetoothService.adapter.discovering
|
||||
|| !Bluetooth.devices)
|
||||
return []
|
||||
|
||||
var filtered = Bluetooth.devices.values.filter(dev => {
|
||||
return dev && !dev.paired
|
||||
&& !dev.pairing
|
||||
&& !dev.blocked
|
||||
&& (dev.signalStrength === undefined
|
||||
|| dev.signalStrength > 0)
|
||||
})
|
||||
return BluetoothService.sortDevices(filtered)
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
property bool canConnect: BluetoothService.canConnect(modelData)
|
||||
property bool isBusy: BluetoothService.isDeviceBusy(modelData)
|
||||
|
||||
width: parent.width
|
||||
height: 70
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
if (availableDeviceArea.containsMouse && !isBusy)
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g,
|
||||
Theme.primary.b, 0.08)
|
||||
|
||||
if (modelData.pairing
|
||||
|| modelData.state === BluetoothDeviceState.Connecting)
|
||||
return Qt.rgba(Theme.warning.r, Theme.warning.g,
|
||||
Theme.warning.b, 0.12)
|
||||
|
||||
if (modelData.blocked)
|
||||
return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.08)
|
||||
|
||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
|
||||
Theme.surfaceVariant.b, 0.08)
|
||||
}
|
||||
border.color: {
|
||||
if (modelData.pairing)
|
||||
return Theme.warning
|
||||
|
||||
if (modelData.blocked)
|
||||
return Theme.error
|
||||
|
||||
return Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
}
|
||||
border.width: 1
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: BluetoothService.getDeviceIcon(modelData)
|
||||
size: Theme.iconSize
|
||||
color: {
|
||||
if (modelData.pairing)
|
||||
return Theme.warning
|
||||
|
||||
if (modelData.blocked)
|
||||
return Theme.error
|
||||
|
||||
return Theme.surfaceText
|
||||
}
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
spacing: 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: modelData.name || modelData.deviceName
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: {
|
||||
if (modelData.pairing)
|
||||
return Theme.warning
|
||||
|
||||
if (modelData.blocked)
|
||||
return Theme.error
|
||||
|
||||
return Theme.surfaceText
|
||||
}
|
||||
font.weight: modelData.pairing ? Font.Medium : Font.Normal
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (modelData.pairing)
|
||||
return "Pairing..."
|
||||
|
||||
if (modelData.blocked)
|
||||
return "Blocked"
|
||||
|
||||
return BluetoothService.getSignalStrength(modelData)
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: {
|
||||
if (modelData.pairing)
|
||||
return Theme.warning
|
||||
|
||||
if (modelData.blocked)
|
||||
return Theme.error
|
||||
|
||||
return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.7)
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
name: BluetoothService.getSignalIcon(modelData)
|
||||
size: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.7)
|
||||
visible: modelData.signalStrength !== undefined
|
||||
&& modelData.signalStrength > 0 && !modelData.pairing
|
||||
&& !modelData.blocked
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: (modelData.signalStrength !== undefined
|
||||
&& modelData.signalStrength > 0) ? modelData.signalStrength + "%" : ""
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.5)
|
||||
visible: modelData.signalStrength !== undefined
|
||||
&& modelData.signalStrength > 0 && !modelData.pairing
|
||||
&& !modelData.blocked
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 80
|
||||
height: 28
|
||||
radius: Theme.cornerRadius
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: modelData.state !== BluetoothDeviceState.Connecting
|
||||
color: {
|
||||
if (!canConnect && !isBusy)
|
||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
|
||||
Theme.surfaceVariant.b, 0.3)
|
||||
|
||||
if (actionButtonArea.containsMouse && !isBusy)
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g,
|
||||
Theme.primary.b, 0.12)
|
||||
|
||||
return "transparent"
|
||||
}
|
||||
border.color: canConnect || isBusy ? Theme.primary : Qt.rgba(
|
||||
Theme.outline.r,
|
||||
Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.width: 1
|
||||
opacity: canConnect || isBusy ? 1 : 0.5
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: {
|
||||
if (modelData.pairing)
|
||||
return "Pairing..."
|
||||
|
||||
if (modelData.blocked)
|
||||
return "Blocked"
|
||||
|
||||
return "Connect"
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: canConnect || isBusy ? Theme.primary : Qt.rgba(
|
||||
Theme.surfaceText.r,
|
||||
Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.5)
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: actionButtonArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: canConnect
|
||||
&& !isBusy ? Qt.PointingHandCursor : (isBusy ? Qt.BusyCursor : Qt.ArrowCursor)
|
||||
enabled: canConnect && !isBusy
|
||||
onClicked: {
|
||||
if (modelData)
|
||||
BluetoothService.connectDeviceWithTrust(modelData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: availableDeviceArea
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: 90
|
||||
hoverEnabled: true
|
||||
cursorShape: canConnect
|
||||
&& !isBusy ? Qt.PointingHandCursor : (isBusy ? Qt.BusyCursor : Qt.ArrowCursor)
|
||||
enabled: canConnect && !isBusy
|
||||
onClicked: {
|
||||
if (modelData)
|
||||
BluetoothService.connectDeviceWithTrust(modelData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
visible: {
|
||||
if (!BluetoothService.adapter || !BluetoothService.adapter.discovering
|
||||
|| !Bluetooth.devices)
|
||||
return false
|
||||
|
||||
var availableCount = Bluetooth.devices.values.filter(dev => {
|
||||
return dev
|
||||
&& !dev.paired
|
||||
&& !dev.pairing
|
||||
&& !dev.blocked
|
||||
&& (dev.signalStrength === undefined
|
||||
|| dev.signalStrength > 0)
|
||||
}).length
|
||||
return availableCount === 0
|
||||
}
|
||||
visible: BluetoothService.adapter && BluetoothService.adapter.enabled
|
||||
|
||||
Row {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingM
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "sync"
|
||||
size: Theme.iconSizeLarge
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
RotationAnimation on rotation {
|
||||
running: true
|
||||
loops: Animation.Infinite
|
||||
from: 0
|
||||
to: 360
|
||||
duration: 2000
|
||||
StyledText {
|
||||
text: "Available Devices"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Scanning for devices..."
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
Item {
|
||||
width: parent.width - scanButton.width - parent.spacing
|
||||
- 150 // Spacer to push button right
|
||||
height: 1
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: scanButton
|
||||
|
||||
width: Math.max(100, scanText.contentWidth + Theme.spacingL * 2)
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: scanArea.containsMouse ? Qt.rgba(Theme.primary.r,
|
||||
Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.12) : Qt.rgba(
|
||||
Theme.primary.r,
|
||||
Theme.primary.g,
|
||||
Theme.primary.b, 0.08)
|
||||
border.color: Theme.primary
|
||||
border.width: 1
|
||||
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
DankIcon {
|
||||
name: BluetoothService.adapter
|
||||
&& BluetoothService.adapter.discovering ? "stop" : "bluetooth_searching"
|
||||
size: Theme.iconSize - 6
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: scanText
|
||||
|
||||
text: BluetoothService.adapter
|
||||
&& BluetoothService.adapter.discovering ? "Stop Scanning" : "Scan"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.primary
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: scanArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (BluetoothService.adapter)
|
||||
BluetoothService.adapter.discovering = !BluetoothService.adapter.discovering
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: noteColumn.implicitHeight + Theme.spacingM * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.08)
|
||||
border.color: Qt.rgba(Theme.warning.r, Theme.warning.g,
|
||||
Theme.warning.b, 0.2)
|
||||
border.width: 1
|
||||
|
||||
Column {
|
||||
id: noteColumn
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingM
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: "info"
|
||||
size: Theme.iconSize - 2
|
||||
color: Theme.warning
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Pairing Limitation"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.warning
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Quickshell does not support pairing devices that require pin or confirmation."
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.8)
|
||||
wrapMode: Text.WordWrap
|
||||
width: parent.width
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: {
|
||||
if (!BluetoothService.adapter
|
||||
|| !BluetoothService.adapter.discovering
|
||||
|| !Bluetooth.devices)
|
||||
return []
|
||||
|
||||
var filtered = Bluetooth.devices.values.filter(dev => {
|
||||
return dev
|
||||
&& !dev.paired
|
||||
&& !dev.pairing
|
||||
&& !dev.blocked
|
||||
&& (dev.signalStrength === undefined
|
||||
|| dev.signalStrength > 0)
|
||||
})
|
||||
return BluetoothService.sortDevices(filtered)
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
property bool canConnect: BluetoothService.canConnect(modelData)
|
||||
property bool isBusy: BluetoothService.isDeviceBusy(modelData)
|
||||
|
||||
width: parent.width
|
||||
height: 70
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
if (availableDeviceArea.containsMouse && !isBusy)
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g,
|
||||
Theme.primary.b, 0.08)
|
||||
|
||||
if (modelData.pairing
|
||||
|| modelData.state === BluetoothDeviceState.Connecting)
|
||||
return Qt.rgba(Theme.warning.r, Theme.warning.g,
|
||||
Theme.warning.b, 0.12)
|
||||
|
||||
if (modelData.blocked)
|
||||
return Qt.rgba(Theme.error.r, Theme.error.g,
|
||||
Theme.error.b, 0.08)
|
||||
|
||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
|
||||
Theme.surfaceVariant.b, 0.08)
|
||||
}
|
||||
border.color: {
|
||||
if (modelData.pairing)
|
||||
return Theme.warning
|
||||
|
||||
if (modelData.blocked)
|
||||
return Theme.error
|
||||
|
||||
return Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
}
|
||||
border.width: 1
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: BluetoothService.getDeviceIcon(modelData)
|
||||
size: Theme.iconSize
|
||||
color: {
|
||||
if (modelData.pairing)
|
||||
return Theme.warning
|
||||
|
||||
if (modelData.blocked)
|
||||
return Theme.error
|
||||
|
||||
return Theme.surfaceText
|
||||
}
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
spacing: 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: modelData.name || modelData.deviceName
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: {
|
||||
if (modelData.pairing)
|
||||
return Theme.warning
|
||||
|
||||
if (modelData.blocked)
|
||||
return Theme.error
|
||||
|
||||
return Theme.surfaceText
|
||||
}
|
||||
font.weight: modelData.pairing ? Font.Medium : Font.Normal
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (modelData.pairing)
|
||||
return "Pairing..."
|
||||
|
||||
if (modelData.blocked)
|
||||
return "Blocked"
|
||||
|
||||
return BluetoothService.getSignalStrength(
|
||||
modelData)
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: {
|
||||
if (modelData.pairing)
|
||||
return Theme.warning
|
||||
|
||||
if (modelData.blocked)
|
||||
return Theme.error
|
||||
|
||||
return Qt.rgba(Theme.surfaceText.r,
|
||||
Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.7)
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
name: BluetoothService.getSignalIcon(modelData)
|
||||
size: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r,
|
||||
Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.7)
|
||||
visible: modelData.signalStrength !== undefined
|
||||
&& modelData.signalStrength > 0
|
||||
&& !modelData.pairing
|
||||
&& !modelData.blocked
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: (modelData.signalStrength !== undefined
|
||||
&& modelData.signalStrength
|
||||
> 0) ? modelData.signalStrength + "%" : ""
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r,
|
||||
Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.5)
|
||||
visible: modelData.signalStrength !== undefined
|
||||
&& modelData.signalStrength > 0
|
||||
&& !modelData.pairing
|
||||
&& !modelData.blocked
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 80
|
||||
height: 28
|
||||
radius: Theme.cornerRadius
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: modelData.state !== BluetoothDeviceState.Connecting
|
||||
color: {
|
||||
if (!canConnect && !isBusy)
|
||||
return Qt.rgba(Theme.surfaceVariant.r,
|
||||
Theme.surfaceVariant.g,
|
||||
Theme.surfaceVariant.b, 0.3)
|
||||
|
||||
if (actionButtonArea.containsMouse && !isBusy)
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g,
|
||||
Theme.primary.b, 0.12)
|
||||
|
||||
return "transparent"
|
||||
}
|
||||
border.color: canConnect || isBusy ? Theme.primary : Qt.rgba(
|
||||
Theme.outline.r,
|
||||
Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.width: 1
|
||||
opacity: canConnect || isBusy ? 1 : 0.5
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: {
|
||||
if (modelData.pairing)
|
||||
return "Pairing..."
|
||||
|
||||
if (modelData.blocked)
|
||||
return "Blocked"
|
||||
|
||||
return "Connect"
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: canConnect || isBusy ? Theme.primary : Qt.rgba(
|
||||
Theme.surfaceText.r,
|
||||
Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.5)
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: actionButtonArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: canConnect
|
||||
&& !isBusy ? Qt.PointingHandCursor : (isBusy ? Qt.BusyCursor : Qt.ArrowCursor)
|
||||
enabled: canConnect && !isBusy
|
||||
onClicked: {
|
||||
if (modelData)
|
||||
BluetoothService.connectDeviceWithTrust(modelData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: availableDeviceArea
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: 90
|
||||
hoverEnabled: true
|
||||
cursorShape: canConnect
|
||||
&& !isBusy ? Qt.PointingHandCursor : (isBusy ? Qt.BusyCursor : Qt.ArrowCursor)
|
||||
enabled: canConnect && !isBusy
|
||||
onClicked: {
|
||||
if (modelData)
|
||||
BluetoothService.connectDeviceWithTrust(modelData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
visible: {
|
||||
if (!BluetoothService.adapter
|
||||
|| !BluetoothService.adapter.discovering
|
||||
|| !Bluetooth.devices)
|
||||
return false
|
||||
|
||||
var availableCount = Bluetooth.devices.values.filter(dev => {
|
||||
return dev
|
||||
&& !dev.paired
|
||||
&& !dev.pairing
|
||||
&& !dev.blocked
|
||||
&& (dev.signalStrength
|
||||
=== undefined
|
||||
|| dev.signalStrength > 0)
|
||||
}).length
|
||||
return availableCount === 0
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "sync"
|
||||
size: Theme.iconSizeLarge
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
RotationAnimation on rotation {
|
||||
running: true
|
||||
loops: Animation.Infinite
|
||||
from: 0
|
||||
to: 360
|
||||
duration: 2000
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Scanning for devices..."
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Make sure your device is in pairing mode"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.7)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Make sure your device is in pairing mode"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.7)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
}
|
||||
text: "No devices found. Put your device in pairing mode and click Start Scanning."
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.7)
|
||||
visible: {
|
||||
if (!BluetoothService.adapter || !Bluetooth.devices)
|
||||
return true
|
||||
|
||||
StyledText {
|
||||
text: "No devices found. Put your device in pairing mode and click Start Scanning."
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.7)
|
||||
visible: {
|
||||
if (!BluetoothService.adapter || !Bluetooth.devices)
|
||||
return true
|
||||
|
||||
var availableCount = Bluetooth.devices.values.filter(dev => {
|
||||
return dev
|
||||
&& !dev.paired
|
||||
&& !dev.pairing
|
||||
&& !dev.blocked
|
||||
&& (dev.signalStrength === undefined
|
||||
|| dev.signalStrength > 0)
|
||||
}).length
|
||||
return availableCount === 0 && !BluetoothService.adapter.discovering
|
||||
var availableCount = Bluetooth.devices.values.filter(dev => {
|
||||
return dev
|
||||
&& !dev.paired
|
||||
&& !dev.pairing
|
||||
&& !dev.blocked
|
||||
&& (dev.signalStrength
|
||||
=== undefined
|
||||
|| dev.signalStrength > 0)
|
||||
}).length
|
||||
return availableCount === 0 && !BluetoothService.adapter.discovering
|
||||
}
|
||||
wrapMode: Text.WordWrap
|
||||
width: parent.width
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
wrapMode: Text.WordWrap
|
||||
width: parent.width
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,199 +9,203 @@ import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
property var deviceData: null
|
||||
property bool menuVisible: false
|
||||
property var parentItem
|
||||
property var deviceData: null
|
||||
property bool menuVisible: false
|
||||
property var parentItem
|
||||
|
||||
function show(x, y) {
|
||||
const menuWidth = 160
|
||||
const menuHeight = menuColumn.implicitHeight + Theme.spacingS * 2
|
||||
let finalX = x - menuWidth / 2
|
||||
let finalY = y
|
||||
finalX = Math.max(0, Math.min(finalX, parentItem.width - menuWidth))
|
||||
finalY = Math.max(0, Math.min(finalY, parentItem.height - menuHeight))
|
||||
root.x = finalX
|
||||
root.y = finalY
|
||||
root.visible = true
|
||||
root.menuVisible = true
|
||||
}
|
||||
function show(x, y) {
|
||||
const menuWidth = 160
|
||||
const menuHeight = menuColumn.implicitHeight + Theme.spacingS * 2
|
||||
let finalX = x - menuWidth / 2
|
||||
let finalY = y
|
||||
finalX = Math.max(0, Math.min(finalX, parentItem.width - menuWidth))
|
||||
finalY = Math.max(0, Math.min(finalY, parentItem.height - menuHeight))
|
||||
root.x = finalX
|
||||
root.y = finalY
|
||||
root.visible = true
|
||||
root.menuVisible = true
|
||||
}
|
||||
|
||||
function hide() {
|
||||
root.menuVisible = false
|
||||
Qt.callLater(() => {
|
||||
root.visible = false
|
||||
})
|
||||
}
|
||||
function hide() {
|
||||
root.menuVisible = false
|
||||
Qt.callLater(() => {
|
||||
root.visible = false
|
||||
})
|
||||
}
|
||||
|
||||
visible: false
|
||||
width: 160
|
||||
height: menuColumn.implicitHeight + Theme.spacingS * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.popupBackground()
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: 1
|
||||
z: 1000
|
||||
opacity: menuVisible ? 1 : 0
|
||||
scale: menuVisible ? 1 : 0.85
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 4
|
||||
anchors.leftMargin: 2
|
||||
anchors.rightMargin: -2
|
||||
anchors.bottomMargin: -4
|
||||
radius: parent.radius
|
||||
color: Qt.rgba(0, 0, 0, 0.15)
|
||||
z: parent.z - 1
|
||||
}
|
||||
|
||||
Column {
|
||||
id: menuColumn
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingS
|
||||
spacing: 1
|
||||
visible: false
|
||||
width: 160
|
||||
height: menuColumn.implicitHeight + Theme.spacingS * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.popupBackground()
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.08)
|
||||
border.width: 1
|
||||
z: 1000
|
||||
opacity: menuVisible ? 1 : 0
|
||||
scale: menuVisible ? 1 : 0.85
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: connectArea.containsMouse ? Qt.rgba(Theme.primary.r,
|
||||
Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.12) : "transparent"
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 4
|
||||
anchors.leftMargin: 2
|
||||
anchors.rightMargin: -2
|
||||
anchors.bottomMargin: -4
|
||||
radius: parent.radius
|
||||
color: Qt.rgba(0, 0, 0, 0.15)
|
||||
z: parent.z - 1
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: root.deviceData
|
||||
&& root.deviceData.connected ? "link_off" : "link"
|
||||
size: Theme.iconSize - 2
|
||||
color: Theme.surfaceText
|
||||
opacity: 0.7
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: root.deviceData
|
||||
&& root.deviceData.connected ? "Disconnect" : "Connect"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: connectArea
|
||||
Column {
|
||||
id: menuColumn
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (root.deviceData) {
|
||||
if (root.deviceData.connected)
|
||||
root.deviceData.disconnect()
|
||||
else
|
||||
BluetoothService.connectDeviceWithTrust(root.deviceData)
|
||||
}
|
||||
root.hide()
|
||||
}
|
||||
}
|
||||
anchors.margins: Theme.spacingS
|
||||
spacing: 1
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: connectArea.containsMouse ? Qt.rgba(Theme.primary.r,
|
||||
Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.12) : "transparent"
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: root.deviceData
|
||||
&& root.deviceData.connected ? "link_off" : "link"
|
||||
size: Theme.iconSize - 2
|
||||
color: Theme.surfaceText
|
||||
opacity: 0.7
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: root.deviceData
|
||||
&& root.deviceData.connected ? "Disconnect" : "Connect"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: connectArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (root.deviceData) {
|
||||
if (root.deviceData.connected)
|
||||
root.deviceData.disconnect()
|
||||
else
|
||||
BluetoothService.connectDeviceWithTrust(
|
||||
root.deviceData)
|
||||
}
|
||||
root.hide()
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width - Theme.spacingS * 2
|
||||
height: 5
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
color: "transparent"
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: forgetArea.containsMouse ? Qt.rgba(Theme.error.r,
|
||||
Theme.error.g,
|
||||
Theme.error.b,
|
||||
0.12) : "transparent"
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: "delete"
|
||||
size: Theme.iconSize - 2
|
||||
color: forgetArea.containsMouse ? Theme.error : Theme.surfaceText
|
||||
opacity: 0.7
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Forget Device"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: forgetArea.containsMouse ? Theme.error : Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: forgetArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (root.deviceData)
|
||||
root.deviceData.forget()
|
||||
|
||||
root.hide()
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width - Theme.spacingS * 2
|
||||
height: 5
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
color: "transparent"
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
}
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: forgetArea.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g,
|
||||
Theme.error.b,
|
||||
0.12) : "transparent"
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: "delete"
|
||||
size: Theme.iconSize - 2
|
||||
color: forgetArea.containsMouse ? Theme.error : Theme.surfaceText
|
||||
opacity: 0.7
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Forget Device"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: forgetArea.containsMouse ? Theme.error : Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: forgetArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (root.deviceData)
|
||||
root.deviceData.forget()
|
||||
|
||||
root.hide()
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,64 +9,64 @@ import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
width: parent.width
|
||||
height: 60
|
||||
radius: Theme.cornerRadius
|
||||
color: bluetoothToggle.containsMouse ? Qt.rgba(
|
||||
Theme.primary.r, Theme.primary.g,
|
||||
Theme.primary.b, 0.12) : (BluetoothService.adapter
|
||||
&& BluetoothService.adapter.enabled ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.12))
|
||||
border.color: BluetoothService.adapter
|
||||
&& BluetoothService.adapter.enabled ? Theme.primary : "transparent"
|
||||
border.width: 2
|
||||
width: parent.width
|
||||
height: 60
|
||||
radius: Theme.cornerRadius
|
||||
color: bluetoothToggle.containsMouse ? Qt.rgba(
|
||||
Theme.primary.r, Theme.primary.g,
|
||||
Theme.primary.b, 0.12) : (BluetoothService.adapter
|
||||
&& BluetoothService.adapter.enabled ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.12))
|
||||
border.color: BluetoothService.adapter
|
||||
&& BluetoothService.adapter.enabled ? Theme.primary : "transparent"
|
||||
border.width: 2
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingL
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingL
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "bluetooth"
|
||||
size: Theme.iconSizeLarge
|
||||
color: BluetoothService.adapter
|
||||
&& BluetoothService.adapter.enabled ? Theme.primary : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
DankIcon {
|
||||
name: "bluetooth"
|
||||
size: Theme.iconSizeLarge
|
||||
color: BluetoothService.adapter
|
||||
&& BluetoothService.adapter.enabled ? Theme.primary : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
spacing: 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: "Bluetooth"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: BluetoothService.adapter
|
||||
&& BluetoothService.adapter.enabled ? Theme.primary : Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: BluetoothService.adapter
|
||||
&& BluetoothService.adapter.enabled ? "Enabled" : "Disabled"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.7)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
spacing: 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
MouseArea {
|
||||
id: bluetoothToggle
|
||||
|
||||
StyledText {
|
||||
text: "Bluetooth"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: BluetoothService.adapter
|
||||
&& BluetoothService.adapter.enabled ? Theme.primary : Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: BluetoothService.adapter
|
||||
&& BluetoothService.adapter.enabled ? "Enabled" : "Disabled"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.7)
|
||||
}
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (BluetoothService.adapter)
|
||||
BluetoothService.adapter.enabled = !BluetoothService.adapter.enabled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: bluetoothToggle
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (BluetoothService.adapter)
|
||||
BluetoothService.adapter.enabled = !BluetoothService.adapter.enabled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,173 +9,182 @@ import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Column {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
function findBluetoothContextMenu() {
|
||||
var p = parent
|
||||
while (p) {
|
||||
if (p.bluetoothContextMenuWindow)
|
||||
return p.bluetoothContextMenuWindow
|
||||
p = p.parent
|
||||
function findBluetoothContextMenu() {
|
||||
var p = parent
|
||||
while (p) {
|
||||
if (p.bluetoothContextMenuWindow)
|
||||
return p.bluetoothContextMenuWindow
|
||||
p = p.parent
|
||||
}
|
||||
return null
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
visible: BluetoothService.adapter && BluetoothService.adapter.enabled
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
visible: BluetoothService.adapter && BluetoothService.adapter.enabled
|
||||
|
||||
StyledText {
|
||||
text: "Paired Devices"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: BluetoothService.adapter
|
||||
&& BluetoothService.adapter.devices ? BluetoothService.adapter.devices.values.filter(
|
||||
dev => {
|
||||
return dev
|
||||
&& (dev.paired
|
||||
|| dev.trusted)
|
||||
}) : []
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 60
|
||||
radius: Theme.cornerRadius
|
||||
color: btDeviceArea.containsMouse ? Qt.rgba(
|
||||
Theme.primary.r, Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.08) : (modelData.connected ? Qt.rgba(
|
||||
Theme.primary.r,
|
||||
Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.12) : Qt.rgba(
|
||||
Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b,
|
||||
0.08))
|
||||
border.color: modelData.connected ? Theme.primary : "transparent"
|
||||
border.width: 1
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: BluetoothService.getDeviceIcon(modelData)
|
||||
size: Theme.iconSize
|
||||
color: modelData.connected ? Theme.primary : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
spacing: 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: modelData.name || modelData.deviceName
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: modelData.connected ? Theme.primary : Theme.surfaceText
|
||||
font.weight: modelData.connected ? Font.Medium : Font.Normal
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: BluetoothDeviceState.toString(modelData.state)
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.7)
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (modelData.batteryAvailable && modelData.battery > 0)
|
||||
return "• " + Math.round(modelData.battery * 100) + "%"
|
||||
|
||||
var btBattery = BatteryService.bluetoothDevices.find(dev => {
|
||||
return dev.name === (modelData.name || modelData.deviceName) || dev.name.toLowerCase().includes((modelData.name || modelData.deviceName).toLowerCase()) || (modelData.name || modelData.deviceName).toLowerCase(
|
||||
).includes(
|
||||
dev.name.toLowerCase(
|
||||
))
|
||||
})
|
||||
return btBattery ? "• " + btBattery.percentage + "%" : ""
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.7)
|
||||
visible: text.length > 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: btMenuButton
|
||||
|
||||
width: 32
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: btMenuButtonArea.containsMouse ? Qt.rgba(Theme.surfaceText.r,
|
||||
Theme.surfaceText.g,
|
||||
Theme.surfaceText.b,
|
||||
0.08) : "transparent"
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
DankIcon {
|
||||
name: "more_vert"
|
||||
size: Theme.iconSize
|
||||
color: Theme.surfaceText
|
||||
opacity: 0.6
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: btMenuButtonArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
var contextMenu = root.findBluetoothContextMenu()
|
||||
if (contextMenu) {
|
||||
contextMenu.deviceData = modelData
|
||||
let localPos = btMenuButtonArea.mapToItem(
|
||||
contextMenu.parentItem, btMenuButtonArea.width / 2,
|
||||
btMenuButtonArea.height)
|
||||
contextMenu.show(localPos.x, localPos.y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: btDeviceArea
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: 40
|
||||
hoverEnabled: true
|
||||
enabled: !BluetoothService.isDeviceBusy(modelData)
|
||||
cursorShape: enabled ? Qt.PointingHandCursor : Qt.BusyCursor
|
||||
onClicked: {
|
||||
if (modelData.connected)
|
||||
modelData.disconnect()
|
||||
else
|
||||
BluetoothService.connectDeviceWithTrust(modelData)
|
||||
}
|
||||
}
|
||||
StyledText {
|
||||
text: "Paired Devices"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: BluetoothService.adapter
|
||||
&& BluetoothService.adapter.devices ? BluetoothService.adapter.devices.values.filter(
|
||||
dev => {
|
||||
return dev
|
||||
&& (dev.paired
|
||||
|| dev.trusted)
|
||||
}) : []
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 60
|
||||
radius: Theme.cornerRadius
|
||||
color: btDeviceArea.containsMouse ? Qt.rgba(
|
||||
Theme.primary.r,
|
||||
Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.08) : (modelData.connected ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08))
|
||||
border.color: modelData.connected ? Theme.primary : "transparent"
|
||||
border.width: 1
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: BluetoothService.getDeviceIcon(modelData)
|
||||
size: Theme.iconSize
|
||||
color: modelData.connected ? Theme.primary : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
spacing: 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: modelData.name || modelData.deviceName
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: modelData.connected ? Theme.primary : Theme.surfaceText
|
||||
font.weight: modelData.connected ? Font.Medium : Font.Normal
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: BluetoothDeviceState.toString(modelData.state)
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r,
|
||||
Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.7)
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (modelData.batteryAvailable
|
||||
&& modelData.battery > 0)
|
||||
return "• " + Math.round(
|
||||
modelData.battery * 100) + "%"
|
||||
|
||||
var btBattery = BatteryService.bluetoothDevices.find(
|
||||
dev => {
|
||||
return dev.name === (modelData.name
|
||||
|| modelData.deviceName)
|
||||
|| dev.name.toLowerCase(
|
||||
).includes(
|
||||
(modelData.name
|
||||
|| modelData.deviceName).toLowerCase(
|
||||
))
|
||||
|| (modelData.name
|
||||
|| modelData.deviceName).toLowerCase(
|
||||
).includes(
|
||||
dev.name.toLowerCase())
|
||||
})
|
||||
return btBattery ? "• " + btBattery.percentage + "%" : ""
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r,
|
||||
Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.7)
|
||||
visible: text.length > 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: btMenuButton
|
||||
|
||||
width: 32
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: btMenuButtonArea.containsMouse ? Qt.rgba(
|
||||
Theme.surfaceText.r,
|
||||
Theme.surfaceText.g,
|
||||
Theme.surfaceText.b,
|
||||
0.08) : "transparent"
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
DankIcon {
|
||||
name: "more_vert"
|
||||
size: Theme.iconSize
|
||||
color: Theme.surfaceText
|
||||
opacity: 0.6
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: btMenuButtonArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
var contextMenu = root.findBluetoothContextMenu()
|
||||
if (contextMenu) {
|
||||
contextMenu.deviceData = modelData
|
||||
let localPos = btMenuButtonArea.mapToItem(
|
||||
contextMenu.parentItem,
|
||||
btMenuButtonArea.width / 2,
|
||||
btMenuButtonArea.height)
|
||||
contextMenu.show(localPos.x, localPos.y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: btDeviceArea
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: 40
|
||||
hoverEnabled: true
|
||||
enabled: !BluetoothService.isDeviceBusy(modelData)
|
||||
cursorShape: enabled ? Qt.PointingHandCursor : Qt.BusyCursor
|
||||
onClicked: {
|
||||
if (modelData.connected)
|
||||
modelData.disconnect()
|
||||
else
|
||||
BluetoothService.connectDeviceWithTrust(modelData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,79 +10,79 @@ import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: bluetoothTab
|
||||
id: bluetoothTab
|
||||
|
||||
property alias bluetoothContextMenuWindow: bluetoothContextMenuWindow
|
||||
property alias bluetoothContextMenuWindow: bluetoothContextMenuWindow
|
||||
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentHeight: mainColumn.height
|
||||
contentWidth: width
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentHeight: mainColumn.height
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
width: parent.width
|
||||
spacing: Theme.spacingL
|
||||
Column {
|
||||
id: mainColumn
|
||||
width: parent.width
|
||||
spacing: Theme.spacingL
|
||||
|
||||
Loader {
|
||||
width: parent.width
|
||||
sourceComponent: toggleComponent
|
||||
}
|
||||
Loader {
|
||||
width: parent.width
|
||||
sourceComponent: toggleComponent
|
||||
}
|
||||
|
||||
Loader {
|
||||
width: parent.width
|
||||
sourceComponent: pairedComponent
|
||||
}
|
||||
Loader {
|
||||
width: parent.width
|
||||
sourceComponent: pairedComponent
|
||||
}
|
||||
|
||||
Loader {
|
||||
width: parent.width
|
||||
sourceComponent: availableComponent
|
||||
}
|
||||
Loader {
|
||||
width: parent.width
|
||||
sourceComponent: availableComponent
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BluetoothContextMenu {
|
||||
id: bluetoothContextMenuWindow
|
||||
parentItem: bluetoothTab
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
visible: bluetoothContextMenuWindow.visible
|
||||
onClicked: {
|
||||
bluetoothContextMenuWindow.hide()
|
||||
BluetoothContextMenu {
|
||||
id: bluetoothContextMenuWindow
|
||||
parentItem: bluetoothTab
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
x: bluetoothContextMenuWindow.x
|
||||
y: bluetoothContextMenuWindow.y
|
||||
width: bluetoothContextMenuWindow.width
|
||||
height: bluetoothContextMenuWindow.height
|
||||
onClicked: {
|
||||
anchors.fill: parent
|
||||
visible: bluetoothContextMenuWindow.visible
|
||||
onClicked: {
|
||||
bluetoothContextMenuWindow.hide()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
MouseArea {
|
||||
x: bluetoothContextMenuWindow.x
|
||||
y: bluetoothContextMenuWindow.y
|
||||
width: bluetoothContextMenuWindow.width
|
||||
height: bluetoothContextMenuWindow.height
|
||||
onClicked: {
|
||||
|
||||
Component {
|
||||
id: toggleComponent
|
||||
BluetoothToggle {
|
||||
width: parent.width
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: pairedComponent
|
||||
PairedDevicesList {
|
||||
width: parent.width
|
||||
Component {
|
||||
id: toggleComponent
|
||||
BluetoothToggle {
|
||||
width: parent.width
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: availableComponent
|
||||
AvailableDevicesList {
|
||||
width: parent.width
|
||||
Component {
|
||||
id: pairedComponent
|
||||
PairedDevicesList {
|
||||
width: parent.width
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: availableComponent
|
||||
AvailableDevicesList {
|
||||
width: parent.width
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -34,12 +34,9 @@ Item {
|
||||
width: parent.width
|
||||
sourceComponent: settingsComponent
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Component {
|
||||
id: brightnessComponent
|
||||
|
||||
@@ -62,57 +59,62 @@ Item {
|
||||
visible: BrightnessService.devices.length > 1
|
||||
text: "Device"
|
||||
description: {
|
||||
const deviceInfo = BrightnessService.getCurrentDeviceInfo();
|
||||
const deviceInfo = BrightnessService.getCurrentDeviceInfo()
|
||||
if (deviceInfo && deviceInfo.class === "ddc") {
|
||||
return "DDC changes can be slow and unreliable";
|
||||
return "DDC changes can be slow and unreliable"
|
||||
}
|
||||
return "";
|
||||
return ""
|
||||
}
|
||||
currentValue: BrightnessService.currentDevice
|
||||
options: BrightnessService.devices.map(function(d) {
|
||||
return d.name;
|
||||
options: BrightnessService.devices.map(function (d) {
|
||||
return d.name
|
||||
})
|
||||
optionIcons: BrightnessService.devices.map(function(d) {
|
||||
optionIcons: BrightnessService.devices.map(function (d) {
|
||||
if (d.class === "backlight")
|
||||
return "desktop_windows";
|
||||
|
||||
return "desktop_windows"
|
||||
|
||||
if (d.class === "ddc")
|
||||
return "tv";
|
||||
return "tv"
|
||||
|
||||
if (d.name.includes("kbd"))
|
||||
return "keyboard";
|
||||
return "keyboard"
|
||||
|
||||
return "lightbulb";
|
||||
return "lightbulb"
|
||||
})
|
||||
onValueChanged: function(value) {
|
||||
BrightnessService.setCurrentDevice(value, true);
|
||||
onValueChanged: function (value) {
|
||||
BrightnessService.setCurrentDevice(value, true)
|
||||
}
|
||||
|
||||
|
||||
Connections {
|
||||
target: BrightnessService
|
||||
function onDevicesChanged() {
|
||||
if (BrightnessService.currentDevice) {
|
||||
deviceDropdown.currentValue = BrightnessService.currentDevice;
|
||||
deviceDropdown.currentValue = BrightnessService.currentDevice
|
||||
}
|
||||
|
||||
|
||||
// Check if saved device is now available
|
||||
const lastDevice = SessionData.lastBrightnessDevice || "";
|
||||
const lastDevice = SessionData.lastBrightnessDevice
|
||||
|| ""
|
||||
if (lastDevice) {
|
||||
const deviceExists = BrightnessService.devices.some(d => d.name === lastDevice);
|
||||
if (deviceExists && (!BrightnessService.currentDevice || BrightnessService.currentDevice !== lastDevice)) {
|
||||
BrightnessService.setCurrentDevice(lastDevice, false);
|
||||
const deviceExists = BrightnessService.devices.some(
|
||||
d => d.name === lastDevice)
|
||||
if (deviceExists
|
||||
&& (!BrightnessService.currentDevice
|
||||
|| BrightnessService.currentDevice !== lastDevice)) {
|
||||
BrightnessService.setCurrentDevice(lastDevice,
|
||||
false)
|
||||
}
|
||||
}
|
||||
}
|
||||
function onDeviceSwitched() {
|
||||
// Force update the description when device switches
|
||||
deviceDropdown.description = Qt.binding(function() {
|
||||
const deviceInfo = BrightnessService.getCurrentDeviceInfo();
|
||||
deviceDropdown.description = Qt.binding(function () {
|
||||
const deviceInfo = BrightnessService.getCurrentDeviceInfo()
|
||||
if (deviceInfo && deviceInfo.class === "ddc") {
|
||||
return "DDC changes can be slow and unreliable";
|
||||
return "DDC changes can be slow and unreliable"
|
||||
}
|
||||
return "";
|
||||
});
|
||||
return ""
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,31 +125,31 @@ Item {
|
||||
value: BrightnessService.brightnessLevel
|
||||
leftIcon: "brightness_low"
|
||||
rightIcon: "brightness_high"
|
||||
enabled: BrightnessService.brightnessAvailable && BrightnessService.isCurrentDeviceReady()
|
||||
enabled: BrightnessService.brightnessAvailable
|
||||
&& BrightnessService.isCurrentDeviceReady()
|
||||
opacity: BrightnessService.isCurrentDeviceReady() ? 1.0 : 0.5
|
||||
onSliderValueChanged: function(newValue) {
|
||||
brightnessDebounceTimer.pendingValue = newValue;
|
||||
brightnessDebounceTimer.restart();
|
||||
onSliderValueChanged: function (newValue) {
|
||||
brightnessDebounceTimer.pendingValue = newValue
|
||||
brightnessDebounceTimer.restart()
|
||||
}
|
||||
onSliderDragFinished: function(finalValue) {
|
||||
brightnessDebounceTimer.stop();
|
||||
BrightnessService.setBrightnessInternal(finalValue, BrightnessService.currentDevice);
|
||||
onSliderDragFinished: function (finalValue) {
|
||||
brightnessDebounceTimer.stop()
|
||||
BrightnessService.setBrightnessInternal(
|
||||
finalValue, BrightnessService.currentDevice)
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: BrightnessService
|
||||
function onBrightnessChanged() {
|
||||
brightnessSlider.value = BrightnessService.brightnessLevel;
|
||||
brightnessSlider.value = BrightnessService.brightnessLevel
|
||||
}
|
||||
|
||||
|
||||
function onDeviceSwitched() {
|
||||
brightnessSlider.value = BrightnessService.brightnessLevel;
|
||||
brightnessSlider.value = BrightnessService.brightnessLevel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Component {
|
||||
@@ -172,7 +174,11 @@ Item {
|
||||
width: (parent.width - Theme.spacingM) / 2
|
||||
height: 80
|
||||
radius: Theme.cornerRadius
|
||||
color: BrightnessService.nightModeActive ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : (nightModeToggle.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08))
|
||||
color: BrightnessService.nightModeActive ? Qt.rgba(
|
||||
Theme.primary.r,
|
||||
Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.12) : (nightModeToggle.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08))
|
||||
border.color: BrightnessService.nightModeActive ? Theme.primary : "transparent"
|
||||
border.width: BrightnessService.nightModeActive ? 1 : 0
|
||||
|
||||
@@ -194,7 +200,6 @@ Item {
|
||||
font.weight: Font.Medium
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
@@ -204,17 +209,20 @@ Item {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
BrightnessService.toggleNightMode();
|
||||
BrightnessService.toggleNightMode()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: (parent.width - Theme.spacingM) / 2
|
||||
height: 80
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.isLightMode ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : (lightModeToggle.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08))
|
||||
color: Theme.isLightMode ? Qt.rgba(
|
||||
Theme.primary.r,
|
||||
Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.12) : (lightModeToggle.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08))
|
||||
border.color: Theme.isLightMode ? Theme.primary : "transparent"
|
||||
border.width: Theme.isLightMode ? 1 : 0
|
||||
|
||||
@@ -236,7 +244,6 @@ Item {
|
||||
font.weight: Font.Medium
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
@@ -246,7 +253,7 @@ Item {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
Theme.toggleLightMode();
|
||||
Theme.toggleLightMode()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,15 +262,10 @@ Item {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
brightnessDebounceTimer: Timer {
|
||||
@@ -271,13 +273,13 @@ Item {
|
||||
|
||||
interval: {
|
||||
// Use longer interval for DDC devices since ddcutil is slow
|
||||
const deviceInfo = BrightnessService.getCurrentDeviceInfo();
|
||||
return (deviceInfo && deviceInfo.class === "ddc") ? 100 : 50;
|
||||
const deviceInfo = BrightnessService.getCurrentDeviceInfo()
|
||||
return (deviceInfo && deviceInfo.class === "ddc") ? 100 : 50
|
||||
}
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
BrightnessService.setBrightnessInternal(pendingValue, BrightnessService.currentDevice);
|
||||
BrightnessService.setBrightnessInternal(
|
||||
pendingValue, BrightnessService.currentDevice)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,117 +8,120 @@ import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
id: ethernetCard
|
||||
id: ethernetCard
|
||||
|
||||
width: parent.width
|
||||
height: 80
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
if (ethernetPreferenceArea.containsMouse && NetworkService.ethernetConnected
|
||||
&& NetworkService.wifiEnabled
|
||||
&& NetworkService.networkStatus !== "ethernet")
|
||||
return Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g,
|
||||
Theme.surfaceContainer.b, 0.8)
|
||||
width: parent.width
|
||||
height: 80
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
if (ethernetPreferenceArea.containsMouse
|
||||
&& NetworkService.ethernetConnected
|
||||
&& NetworkService.wifiEnabled
|
||||
&& NetworkService.networkStatus !== "ethernet")
|
||||
return Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g,
|
||||
Theme.surfaceContainer.b, 0.8)
|
||||
|
||||
return Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g,
|
||||
Theme.surfaceContainer.b, 0.5)
|
||||
}
|
||||
border.color: NetworkService.networkStatus === "ethernet" ? Theme.primary : Qt.rgba(
|
||||
Theme.outline.r,
|
||||
Theme.outline.g,
|
||||
Theme.outline.b,
|
||||
0.12)
|
||||
border.width: NetworkService.networkStatus === "ethernet" ? 2 : 1
|
||||
return Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g,
|
||||
Theme.surfaceContainer.b, 0.5)
|
||||
}
|
||||
border.color: NetworkService.networkStatus
|
||||
=== "ethernet" ? Theme.primary : Qt.rgba(Theme.outline.r,
|
||||
Theme.outline.g,
|
||||
Theme.outline.b,
|
||||
0.12)
|
||||
border.width: NetworkService.networkStatus === "ethernet" ? 2 : 1
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
spacing: Theme.spacingM
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "lan"
|
||||
size: Theme.iconSize
|
||||
color: NetworkService.networkStatus === "ethernet" ? Theme.primary : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: "Ethernet"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: NetworkService.networkStatus
|
||||
=== "ethernet" ? Theme.primary : Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: NetworkService.ethernetConnected ? (NetworkService.ethernetIP
|
||||
|| "Connected") : "Disconnected"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.7)
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
name: "lan"
|
||||
size: Theme.iconSize
|
||||
color: NetworkService.networkStatus === "ethernet" ? Theme.primary : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
id: ethernetLoadingSpinner
|
||||
|
||||
name: "refresh"
|
||||
size: Theme.iconSize - 4
|
||||
color: Theme.primary
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: NetworkService.changingPreference
|
||||
&& NetworkService.targetPreference === "ethernet"
|
||||
z: 10
|
||||
|
||||
RotationAnimation {
|
||||
target: ethernetLoadingSpinner
|
||||
property: "rotation"
|
||||
running: ethernetLoadingSpinner.visible
|
||||
from: 0
|
||||
to: 360
|
||||
duration: 1000
|
||||
loops: Animation.Infinite
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 2
|
||||
MouseArea {
|
||||
id: ethernetPreferenceArea
|
||||
|
||||
StyledText {
|
||||
text: "Ethernet"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: NetworkService.networkStatus === "ethernet" ? Theme.primary : Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: (NetworkService.ethernetConnected
|
||||
&& NetworkService.wifiEnabled
|
||||
&& NetworkService.networkStatus
|
||||
!== "ethernet") ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
enabled: NetworkService.ethernetConnected && NetworkService.wifiEnabled
|
||||
&& NetworkService.networkStatus !== "ethernet"
|
||||
&& !NetworkService.changingNetworkPreference
|
||||
onClicked: {
|
||||
if (NetworkService.ethernetConnected
|
||||
&& NetworkService.wifiEnabled) {
|
||||
|
||||
StyledText {
|
||||
text: NetworkService.ethernetConnected ? (NetworkService.ethernetIP
|
||||
|| "Connected") : "Disconnected"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.7)
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
if (NetworkService.networkStatus !== "ethernet")
|
||||
NetworkService.setNetworkPreference("ethernet")
|
||||
else
|
||||
NetworkService.setNetworkPreference("auto")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
id: ethernetLoadingSpinner
|
||||
|
||||
name: "refresh"
|
||||
size: Theme.iconSize - 4
|
||||
color: Theme.primary
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: NetworkService.changingPreference
|
||||
&& NetworkService.targetPreference === "ethernet"
|
||||
z: 10
|
||||
|
||||
RotationAnimation {
|
||||
target: ethernetLoadingSpinner
|
||||
property: "rotation"
|
||||
running: ethernetLoadingSpinner.visible
|
||||
from: 0
|
||||
to: 360
|
||||
duration: 1000
|
||||
loops: Animation.Infinite
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MouseArea {
|
||||
id: ethernetPreferenceArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: (NetworkService.ethernetConnected && NetworkService.wifiEnabled
|
||||
&& NetworkService.networkStatus
|
||||
!== "ethernet") ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
enabled: NetworkService.ethernetConnected && NetworkService.wifiEnabled
|
||||
&& NetworkService.networkStatus !== "ethernet"
|
||||
&& !NetworkService.changingNetworkPreference
|
||||
onClicked: {
|
||||
if (NetworkService.ethernetConnected && NetworkService.wifiEnabled) {
|
||||
|
||||
if (NetworkService.networkStatus !== "ethernet")
|
||||
NetworkService.setNetworkPreference("ethernet")
|
||||
else
|
||||
NetworkService.setNetworkPreference("auto")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,159 +8,163 @@ import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
id: wifiCard
|
||||
id: wifiCard
|
||||
|
||||
property var refreshTimer
|
||||
property var refreshTimer
|
||||
|
||||
width: parent.width
|
||||
height: 80
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
if (wifiPreferenceArea.containsMouse && NetworkService.ethernetConnected
|
||||
&& NetworkService.wifiEnabled
|
||||
&& NetworkService.networkStatus !== "wifi")
|
||||
return Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g,
|
||||
Theme.surfaceContainer.b, 0.8)
|
||||
width: parent.width
|
||||
height: 80
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
if (wifiPreferenceArea.containsMouse && NetworkService.ethernetConnected
|
||||
&& NetworkService.wifiEnabled
|
||||
&& NetworkService.networkStatus !== "wifi")
|
||||
return Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g,
|
||||
Theme.surfaceContainer.b, 0.8)
|
||||
|
||||
return Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g,
|
||||
Theme.surfaceContainer.b, 0.5)
|
||||
}
|
||||
border.color: NetworkService.networkStatus === "wifi" ? Theme.primary : Qt.rgba(
|
||||
Theme.outline.r,
|
||||
Theme.outline.g,
|
||||
Theme.outline.b,
|
||||
0.12)
|
||||
border.width: NetworkService.networkStatus === "wifi" ? 2 : 1
|
||||
visible: NetworkService.wifiAvailable
|
||||
return Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g,
|
||||
Theme.surfaceContainer.b, 0.5)
|
||||
}
|
||||
border.color: NetworkService.networkStatus === "wifi" ? Theme.primary : Qt.rgba(
|
||||
Theme.outline.r,
|
||||
Theme.outline.g,
|
||||
Theme.outline.b,
|
||||
0.12)
|
||||
border.width: NetworkService.networkStatus === "wifi" ? 2 : 1
|
||||
visible: NetworkService.wifiAvailable
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: wifiToggle.left
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
spacing: Theme.spacingM
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: wifiToggle.left
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: NetworkService.wifiSignalIcon
|
||||
size: Theme.iconSize
|
||||
color: NetworkService.networkStatus === "wifi" ? Theme.primary : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (!NetworkService.wifiEnabled)
|
||||
return "WiFi is off"
|
||||
else if (NetworkService.wifiEnabled
|
||||
&& NetworkService.currentWifiSSID)
|
||||
return NetworkService.currentWifiSSID || "Connected"
|
||||
else
|
||||
return "Not Connected"
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: NetworkService.networkStatus === "wifi" ? Theme.primary : Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (!NetworkService.wifiEnabled)
|
||||
return "Turn on WiFi to see networks"
|
||||
else if (NetworkService.wifiEnabled
|
||||
&& NetworkService.currentWifiSSID)
|
||||
return NetworkService.wifiIP || "Connected"
|
||||
else
|
||||
return "Select a network below"
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.7)
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
name: NetworkService.wifiSignalIcon
|
||||
size: Theme.iconSize
|
||||
color: NetworkService.networkStatus === "wifi" ? Theme.primary : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
id: wifiLoadingSpinner
|
||||
|
||||
Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 2
|
||||
name: "refresh"
|
||||
size: Theme.iconSize - 4
|
||||
color: Theme.primary
|
||||
anchors.right: wifiToggle.left
|
||||
anchors.rightMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: NetworkService.changingPreference
|
||||
&& NetworkService.targetPreference === "wifi"
|
||||
z: 10
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (!NetworkService.wifiEnabled)
|
||||
return "WiFi is off"
|
||||
else if (NetworkService.wifiEnabled && NetworkService.currentWifiSSID)
|
||||
return NetworkService.currentWifiSSID || "Connected"
|
||||
else
|
||||
return "Not Connected"
|
||||
RotationAnimation {
|
||||
target: wifiLoadingSpinner
|
||||
property: "rotation"
|
||||
running: wifiLoadingSpinner.visible
|
||||
from: 0
|
||||
to: 360
|
||||
duration: 1000
|
||||
loops: Animation.Infinite
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: NetworkService.networkStatus === "wifi" ? Theme.primary : Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (!NetworkService.wifiEnabled)
|
||||
return "Turn on WiFi to see networks"
|
||||
else if (NetworkService.wifiEnabled && NetworkService.currentWifiSSID)
|
||||
return NetworkService.wifiIP || "Connected"
|
||||
else
|
||||
return "Select a network below"
|
||||
DankToggle {
|
||||
id: wifiToggle
|
||||
|
||||
checked: NetworkService.wifiEnabled
|
||||
enabled: true
|
||||
toggling: NetworkService.wifiToggling
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onClicked: {
|
||||
if (NetworkService.wifiEnabled) {
|
||||
NetworkService.currentWifiSSID = ""
|
||||
NetworkService.wifiSignalStrength = 100
|
||||
NetworkService.wifiNetworks = []
|
||||
NetworkService.savedWifiNetworks = []
|
||||
NetworkService.connectionStatus = ""
|
||||
NetworkService.connectingSSID = ""
|
||||
NetworkService.isScanning = false
|
||||
NetworkService.refreshNetworkStatus()
|
||||
}
|
||||
NetworkService.toggleWifiRadio()
|
||||
if (refreshTimer)
|
||||
refreshTimer.triggered = true
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.7)
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
id: wifiLoadingSpinner
|
||||
MouseArea {
|
||||
id: wifiPreferenceArea
|
||||
|
||||
name: "refresh"
|
||||
size: Theme.iconSize - 4
|
||||
color: Theme.primary
|
||||
anchors.right: wifiToggle.left
|
||||
anchors.rightMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: NetworkService.changingPreference
|
||||
&& NetworkService.targetPreference === "wifi"
|
||||
z: 10
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: 60 // Exclude toggle area
|
||||
hoverEnabled: true
|
||||
cursorShape: (NetworkService.ethernetConnected
|
||||
&& NetworkService.wifiEnabled
|
||||
&& NetworkService.networkStatus
|
||||
!== "wifi") ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
enabled: NetworkService.ethernetConnected && NetworkService.wifiEnabled
|
||||
&& NetworkService.networkStatus !== "wifi"
|
||||
&& !NetworkService.changingNetworkPreference
|
||||
onClicked: {
|
||||
if (NetworkService.ethernetConnected
|
||||
&& NetworkService.wifiEnabled) {
|
||||
|
||||
RotationAnimation {
|
||||
target: wifiLoadingSpinner
|
||||
property: "rotation"
|
||||
running: wifiLoadingSpinner.visible
|
||||
from: 0
|
||||
to: 360
|
||||
duration: 1000
|
||||
loops: Animation.Infinite
|
||||
if (NetworkService.networkStatus !== "wifi")
|
||||
NetworkService.setNetworkPreference("wifi")
|
||||
else
|
||||
NetworkService.setNetworkPreference("auto")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
id: wifiToggle
|
||||
|
||||
checked: NetworkService.wifiEnabled
|
||||
enabled: true
|
||||
toggling: NetworkService.wifiToggling
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onClicked: {
|
||||
if (NetworkService.wifiEnabled) {
|
||||
NetworkService.currentWifiSSID = ""
|
||||
NetworkService.wifiSignalStrength = 100
|
||||
NetworkService.wifiNetworks = []
|
||||
NetworkService.savedWifiNetworks = []
|
||||
NetworkService.connectionStatus = ""
|
||||
NetworkService.connectingSSID = ""
|
||||
NetworkService.isScanning = false
|
||||
NetworkService.refreshNetworkStatus()
|
||||
}
|
||||
NetworkService.toggleWifiRadio()
|
||||
if (refreshTimer)
|
||||
refreshTimer.triggered = true
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: wifiPreferenceArea
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: 60 // Exclude toggle area
|
||||
hoverEnabled: true
|
||||
cursorShape: (NetworkService.ethernetConnected && NetworkService.wifiEnabled
|
||||
&& NetworkService.networkStatus
|
||||
!== "wifi") ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
enabled: NetworkService.ethernetConnected && NetworkService.wifiEnabled
|
||||
&& NetworkService.networkStatus !== "wifi"
|
||||
&& !NetworkService.changingNetworkPreference
|
||||
onClicked: {
|
||||
if (NetworkService.ethernetConnected && NetworkService.wifiEnabled) {
|
||||
|
||||
if (NetworkService.networkStatus !== "wifi")
|
||||
NetworkService.setNetworkPreference("wifi")
|
||||
else
|
||||
NetworkService.setNetworkPreference("auto")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,289 +8,293 @@ import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
id: wifiContextMenuWindow
|
||||
id: wifiContextMenuWindow
|
||||
|
||||
property var networkData: null
|
||||
property bool menuVisible: false
|
||||
property var parentItem
|
||||
property var wifiPasswordModalRef
|
||||
property var networkInfoModalRef
|
||||
property var networkData: null
|
||||
property bool menuVisible: false
|
||||
property var parentItem
|
||||
property var wifiPasswordModalRef
|
||||
property var networkInfoModalRef
|
||||
|
||||
function show(x, y) {
|
||||
const menuWidth = 160
|
||||
wifiContextMenuWindow.visible = true
|
||||
Qt.callLater(() => {
|
||||
const menuHeight = wifiMenuColumn.implicitHeight + Theme.spacingS * 2
|
||||
let finalX = x - menuWidth / 2
|
||||
let finalY = y + 4
|
||||
finalX = Math.max(
|
||||
Theme.spacingS,
|
||||
Math.min(finalX,
|
||||
parentItem.width - menuWidth - Theme.spacingS))
|
||||
finalY = Math.max(
|
||||
Theme.spacingS,
|
||||
Math.min(finalY,
|
||||
parentItem.height - menuHeight - Theme.spacingS))
|
||||
if (finalY + menuHeight > parentItem.height - Theme.spacingS) {
|
||||
finalY = y - menuHeight - 4
|
||||
finalY = Math.max(Theme.spacingS, finalY)
|
||||
}
|
||||
wifiContextMenuWindow.x = finalX
|
||||
wifiContextMenuWindow.y = finalY
|
||||
wifiContextMenuWindow.menuVisible = true
|
||||
})
|
||||
}
|
||||
function show(x, y) {
|
||||
const menuWidth = 160
|
||||
wifiContextMenuWindow.visible = true
|
||||
Qt.callLater(() => {
|
||||
const menuHeight = wifiMenuColumn.implicitHeight + Theme.spacingS * 2
|
||||
let finalX = x - menuWidth / 2
|
||||
let finalY = y + 4
|
||||
finalX = Math.max(
|
||||
Theme.spacingS, Math.min(
|
||||
finalX,
|
||||
parentItem.width - menuWidth - Theme.spacingS))
|
||||
finalY = Math.max(
|
||||
Theme.spacingS, Math.min(
|
||||
finalY,
|
||||
parentItem.height - menuHeight - Theme.spacingS))
|
||||
if (finalY + menuHeight > parentItem.height - Theme.spacingS) {
|
||||
finalY = y - menuHeight - 4
|
||||
finalY = Math.max(Theme.spacingS, finalY)
|
||||
}
|
||||
wifiContextMenuWindow.x = finalX
|
||||
wifiContextMenuWindow.y = finalY
|
||||
wifiContextMenuWindow.menuVisible = true
|
||||
})
|
||||
}
|
||||
|
||||
function hide() {
|
||||
wifiContextMenuWindow.menuVisible = false
|
||||
Qt.callLater(() => {
|
||||
wifiContextMenuWindow.visible = false
|
||||
})
|
||||
}
|
||||
function hide() {
|
||||
wifiContextMenuWindow.menuVisible = false
|
||||
Qt.callLater(() => {
|
||||
wifiContextMenuWindow.visible = false
|
||||
})
|
||||
}
|
||||
|
||||
visible: false
|
||||
width: 160
|
||||
height: wifiMenuColumn.implicitHeight + Theme.spacingS * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.popupBackground()
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: 1
|
||||
z: 1000
|
||||
opacity: menuVisible ? 1 : 0
|
||||
scale: menuVisible ? 1 : 0.85
|
||||
Component.onCompleted: {
|
||||
menuVisible = false
|
||||
visible = false
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 4
|
||||
anchors.leftMargin: 2
|
||||
anchors.rightMargin: -2
|
||||
anchors.bottomMargin: -4
|
||||
radius: parent.radius
|
||||
color: Qt.rgba(0, 0, 0, 0.15)
|
||||
z: parent.z - 1
|
||||
}
|
||||
|
||||
Column {
|
||||
id: wifiMenuColumn
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingS
|
||||
spacing: 1
|
||||
visible: false
|
||||
width: 160
|
||||
height: wifiMenuColumn.implicitHeight + Theme.spacingS * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.popupBackground()
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.08)
|
||||
border.width: 1
|
||||
z: 1000
|
||||
opacity: menuVisible ? 1 : 0
|
||||
scale: menuVisible ? 1 : 0.85
|
||||
Component.onCompleted: {
|
||||
menuVisible = false
|
||||
visible = false
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: connectWifiArea.containsMouse ? Qt.rgba(Theme.primary.r,
|
||||
Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.12) : "transparent"
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 4
|
||||
anchors.leftMargin: 2
|
||||
anchors.rightMargin: -2
|
||||
anchors.bottomMargin: -4
|
||||
radius: parent.radius
|
||||
color: Qt.rgba(0, 0, 0, 0.15)
|
||||
z: parent.z - 1
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: wifiContextMenuWindow.networkData
|
||||
&& wifiContextMenuWindow.networkData.connected ? "wifi_off" : "wifi"
|
||||
size: Theme.iconSize - 2
|
||||
color: Theme.surfaceText
|
||||
opacity: 0.7
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: wifiContextMenuWindow.networkData
|
||||
&& wifiContextMenuWindow.networkData.connected ? "Disconnect" : "Connect"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: connectWifiArea
|
||||
Column {
|
||||
id: wifiMenuColumn
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (wifiContextMenuWindow.networkData) {
|
||||
if (wifiContextMenuWindow.networkData.connected) {
|
||||
NetworkService.disconnectWifi()
|
||||
} else {
|
||||
if (wifiContextMenuWindow.networkData.saved) {
|
||||
NetworkService.connectToWifi(
|
||||
wifiContextMenuWindow.networkData.ssid)
|
||||
} else if (wifiContextMenuWindow.networkData.secured) {
|
||||
if (wifiPasswordModalRef) {
|
||||
wifiPasswordModalRef.show(wifiContextMenuWindow.networkData.ssid)
|
||||
anchors.margins: Theme.spacingS
|
||||
spacing: 1
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: connectWifiArea.containsMouse ? Qt.rgba(Theme.primary.r,
|
||||
Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.12) : "transparent"
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: wifiContextMenuWindow.networkData
|
||||
&& wifiContextMenuWindow.networkData.connected ? "wifi_off" : "wifi"
|
||||
size: Theme.iconSize - 2
|
||||
color: Theme.surfaceText
|
||||
opacity: 0.7
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: wifiContextMenuWindow.networkData
|
||||
&& wifiContextMenuWindow.networkData.connected ? "Disconnect" : "Connect"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
} else {
|
||||
NetworkService.connectToWifi(
|
||||
wifiContextMenuWindow.networkData.ssid)
|
||||
}
|
||||
}
|
||||
}
|
||||
wifiContextMenuWindow.hide()
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
MouseArea {
|
||||
id: connectWifiArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (wifiContextMenuWindow.networkData) {
|
||||
if (wifiContextMenuWindow.networkData.connected) {
|
||||
NetworkService.disconnectWifi()
|
||||
} else {
|
||||
if (wifiContextMenuWindow.networkData.saved) {
|
||||
NetworkService.connectToWifi(
|
||||
wifiContextMenuWindow.networkData.ssid)
|
||||
} else if (wifiContextMenuWindow.networkData.secured) {
|
||||
if (wifiPasswordModalRef) {
|
||||
wifiPasswordModalRef.show(
|
||||
wifiContextMenuWindow.networkData.ssid)
|
||||
}
|
||||
} else {
|
||||
NetworkService.connectToWifi(
|
||||
wifiContextMenuWindow.networkData.ssid)
|
||||
}
|
||||
}
|
||||
}
|
||||
wifiContextMenuWindow.hide()
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width - Theme.spacingS * 2
|
||||
height: 5
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
color: "transparent"
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: forgetWifiArea.containsMouse ? Qt.rgba(Theme.error.r,
|
||||
Theme.error.g,
|
||||
Theme.error.b,
|
||||
0.12) : "transparent"
|
||||
visible: wifiContextMenuWindow.networkData
|
||||
&& (wifiContextMenuWindow.networkData.saved
|
||||
|| wifiContextMenuWindow.networkData.connected)
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: "delete"
|
||||
size: Theme.iconSize - 2
|
||||
color: forgetWifiArea.containsMouse ? Theme.error : Theme.surfaceText
|
||||
opacity: 0.7
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Forget Network"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: forgetWifiArea.containsMouse ? Theme.error : Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: forgetWifiArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (wifiContextMenuWindow.networkData)
|
||||
NetworkService.forgetWifiNetwork(
|
||||
wifiContextMenuWindow.networkData.ssid)
|
||||
|
||||
wifiContextMenuWindow.hide()
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: infoWifiArea.containsMouse ? Qt.rgba(Theme.primary.r,
|
||||
Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.12) : "transparent"
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: "info"
|
||||
size: Theme.iconSize - 2
|
||||
color: Theme.surfaceText
|
||||
opacity: 0.7
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Network Info"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: infoWifiArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (wifiContextMenuWindow.networkData
|
||||
&& networkInfoModalRef)
|
||||
networkInfoModalRef.showNetworkInfo(
|
||||
wifiContextMenuWindow.networkData.ssid,
|
||||
wifiContextMenuWindow.networkData)
|
||||
|
||||
wifiContextMenuWindow.hide()
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width - Theme.spacingS * 2
|
||||
height: 5
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
color: "transparent"
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
}
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: forgetWifiArea.containsMouse ? Qt.rgba(Theme.error.r,
|
||||
Theme.error.g,
|
||||
Theme.error.b,
|
||||
0.12) : "transparent"
|
||||
visible: wifiContextMenuWindow.networkData
|
||||
&& (wifiContextMenuWindow.networkData.saved
|
||||
|| wifiContextMenuWindow.networkData.connected)
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: "delete"
|
||||
size: Theme.iconSize - 2
|
||||
color: forgetWifiArea.containsMouse ? Theme.error : Theme.surfaceText
|
||||
opacity: 0.7
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Forget Network"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: forgetWifiArea.containsMouse ? Theme.error : Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: forgetWifiArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (wifiContextMenuWindow.networkData)
|
||||
NetworkService.forgetWifiNetwork(
|
||||
wifiContextMenuWindow.networkData.ssid)
|
||||
|
||||
wifiContextMenuWindow.hide()
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: infoWifiArea.containsMouse ? Qt.rgba(Theme.primary.r,
|
||||
Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.12) : "transparent"
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: "info"
|
||||
size: Theme.iconSize - 2
|
||||
color: Theme.surfaceText
|
||||
opacity: 0.7
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Network Info"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: infoWifiArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (wifiContextMenuWindow.networkData && networkInfoModalRef)
|
||||
networkInfoModalRef.showNetworkInfo(
|
||||
wifiContextMenuWindow.networkData.ssid,
|
||||
wifiContextMenuWindow.networkData)
|
||||
|
||||
wifiContextMenuWindow.hide()
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,299 +8,303 @@ import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Column {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
property var wifiContextMenuWindow
|
||||
property var sortedWifiNetworks
|
||||
property var wifiPasswordModalRef
|
||||
property var wifiContextMenuWindow
|
||||
property var sortedWifiNetworks
|
||||
property var wifiPasswordModalRef
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 100
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
visible: NetworkService.wifiEnabled
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 100
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
visible: NetworkService.wifiEnabled
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: "Available Networks"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Item {
|
||||
width: parent.width - 170
|
||||
height: 1
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 28
|
||||
height: 28
|
||||
radius: 14
|
||||
color: refreshAreaSpan.containsMouse ? Qt.rgba(
|
||||
Theme.primary.r,
|
||||
Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.12) : NetworkService.isScanning ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.06) : "transparent"
|
||||
|
||||
DankIcon {
|
||||
id: refreshIconSpan
|
||||
|
||||
anchors.centerIn: parent
|
||||
name: "refresh"
|
||||
size: Theme.iconSize - 6
|
||||
color: refreshAreaSpan.containsMouse ? Theme.primary : Theme.surfaceText
|
||||
rotation: NetworkService.isScanning ? refreshIconSpan.rotation : 0
|
||||
|
||||
RotationAnimation {
|
||||
target: refreshIconSpan
|
||||
property: "rotation"
|
||||
running: NetworkService.isScanning
|
||||
from: 0
|
||||
to: 360
|
||||
duration: 1000
|
||||
loops: Animation.Infinite
|
||||
StyledText {
|
||||
text: "Available Networks"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Behavior on rotation {
|
||||
RotationAnimation {
|
||||
duration: 200
|
||||
easing.type: Easing.OutQuad
|
||||
}
|
||||
Item {
|
||||
width: parent.width - 170
|
||||
height: 1
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: refreshAreaSpan
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (!NetworkService.isScanning) {
|
||||
refreshIconSpan.rotation += 30
|
||||
NetworkService.scanWifi()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Flickable {
|
||||
width: parent.width
|
||||
height: parent.height - 40
|
||||
clip: true
|
||||
contentWidth: width
|
||||
contentHeight: spanningNetworksColumn.height
|
||||
boundsBehavior: Flickable.DragAndOvershootBounds
|
||||
// Qt 6.9+ scrolling: flickDeceleration/maximumFlickVelocity only affect touch now
|
||||
flickDeceleration: 1500
|
||||
maximumFlickVelocity: 2000
|
||||
|
||||
// Custom wheel handler for Qt 6.9+ responsive mouse wheel scrolling
|
||||
WheelHandler {
|
||||
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
|
||||
onWheel: event => {
|
||||
let delta = event.pixelDelta.y
|
||||
!== 0 ? event.pixelDelta.y * 1.8 : event.angleDelta.y / 120 * 60
|
||||
let newY = parent.contentY - delta
|
||||
newY = Math.max(0,
|
||||
Math.min(parent.contentHeight - parent.height,
|
||||
newY))
|
||||
parent.contentY = newY
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: spanningNetworksColumn
|
||||
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
Repeater {
|
||||
model: NetworkService.wifiAvailable
|
||||
&& NetworkService.wifiEnabled ? sortedWifiNetworks : []
|
||||
|
||||
Rectangle {
|
||||
width: spanningNetworksColumn.width
|
||||
height: 38
|
||||
radius: Theme.cornerRadius
|
||||
color: networkArea2.containsMouse ? Qt.rgba(
|
||||
Theme.primary.r,
|
||||
Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.08) : modelData.connected ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||
border.color: modelData.connected ? Theme.primary : "transparent"
|
||||
border.width: modelData.connected ? 1 : 0
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingXS
|
||||
anchors.rightMargin: Theme.spacingM // Extra right margin for scrollbar
|
||||
width: 28
|
||||
height: 28
|
||||
radius: 14
|
||||
color: refreshAreaSpan.containsMouse ? Qt.rgba(
|
||||
Theme.primary.r,
|
||||
Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.12) : NetworkService.isScanning ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.06) : "transparent"
|
||||
|
||||
DankIcon {
|
||||
id: signalIcon2
|
||||
id: refreshIconSpan
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
name: NetworkService.wifiSignalIcon
|
||||
size: Theme.iconSize - 2
|
||||
color: modelData.connected ? Theme.primary : Theme.surfaceText
|
||||
anchors.centerIn: parent
|
||||
name: "refresh"
|
||||
size: Theme.iconSize - 6
|
||||
color: refreshAreaSpan.containsMouse ? Theme.primary : Theme.surfaceText
|
||||
rotation: NetworkService.isScanning ? refreshIconSpan.rotation : 0
|
||||
|
||||
RotationAnimation {
|
||||
target: refreshIconSpan
|
||||
property: "rotation"
|
||||
running: NetworkService.isScanning
|
||||
from: 0
|
||||
to: 360
|
||||
duration: 1000
|
||||
loops: Animation.Infinite
|
||||
}
|
||||
|
||||
Behavior on rotation {
|
||||
RotationAnimation {
|
||||
duration: 200
|
||||
easing.type: Easing.OutQuad
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.left: signalIcon2.right
|
||||
anchors.leftMargin: Theme.spacingXS
|
||||
anchors.right: rightIcons2.left
|
||||
anchors.rightMargin: Theme.spacingXS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 2
|
||||
MouseArea {
|
||||
id: refreshAreaSpan
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: modelData.ssid
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: modelData.connected ? Theme.primary : Theme.surfaceText
|
||||
font.weight: modelData.connected ? Font.Medium : Font.Normal
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: {
|
||||
if (modelData.connected)
|
||||
return "Connected"
|
||||
|
||||
if (NetworkService.connectionStatus === "connecting"
|
||||
&& NetworkService.connectingSSID === modelData.ssid)
|
||||
return "Connecting..."
|
||||
|
||||
if (NetworkService.connectionStatus === "invalid_password"
|
||||
&& NetworkService.connectingSSID === modelData.ssid)
|
||||
return "Invalid password"
|
||||
|
||||
if (modelData.saved)
|
||||
return "Saved" + (modelData.secured ? " • Secured" : " • Open")
|
||||
|
||||
return modelData.secured ? "Secured" : "Open"
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (!NetworkService.isScanning) {
|
||||
refreshIconSpan.rotation += 30
|
||||
NetworkService.scanWifi()
|
||||
}
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall - 1
|
||||
color: {
|
||||
if (NetworkService.connectionStatus === "connecting"
|
||||
&& NetworkService.connectingSSID === modelData.ssid)
|
||||
return Theme.primary
|
||||
|
||||
if (NetworkService.connectionStatus === "invalid_password"
|
||||
&& NetworkService.connectingSSID === modelData.ssid)
|
||||
return Theme.error
|
||||
|
||||
return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.7)
|
||||
}
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: rightIcons2
|
||||
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
DankIcon {
|
||||
name: "lock"
|
||||
size: Theme.iconSize - 8
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.6)
|
||||
visible: modelData.secured
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: wifiMenuButton
|
||||
|
||||
width: 24
|
||||
height: 24
|
||||
radius: 12
|
||||
color: wifiMenuButtonArea.containsMouse ? Qt.rgba(
|
||||
Theme.surfaceText.r,
|
||||
Theme.surfaceText.g,
|
||||
Theme.surfaceText.b,
|
||||
0.08) : "transparent"
|
||||
|
||||
DankIcon {
|
||||
name: "more_vert"
|
||||
size: Theme.iconSize - 8
|
||||
color: Theme.surfaceText
|
||||
opacity: 0.6
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: wifiMenuButtonArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
wifiContextMenuWindow.networkData = modelData
|
||||
let buttonCenter = wifiMenuButtonArea.width / 2
|
||||
let buttonBottom = wifiMenuButtonArea.height
|
||||
let globalPos = wifiMenuButtonArea.mapToItem(
|
||||
wifiContextMenuWindow.parentItem, buttonCenter,
|
||||
buttonBottom)
|
||||
Qt.callLater(() => {
|
||||
wifiContextMenuWindow.show(globalPos.x,
|
||||
globalPos.y)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: networkArea2
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: 32 // Exclude menu button area
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (modelData.connected)
|
||||
return
|
||||
|
||||
if (modelData.saved) {
|
||||
NetworkService.connectToWifi(modelData.ssid)
|
||||
} else if (modelData.secured) {
|
||||
if (wifiPasswordModalRef) {
|
||||
wifiPasswordModalRef.show(modelData.ssid)
|
||||
}
|
||||
} else {
|
||||
NetworkService.connectToWifi(modelData.ssid)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
policy: ScrollBar.AsNeeded
|
||||
Flickable {
|
||||
width: parent.width
|
||||
height: parent.height - 40
|
||||
clip: true
|
||||
contentWidth: width
|
||||
contentHeight: spanningNetworksColumn.height
|
||||
boundsBehavior: Flickable.DragAndOvershootBounds
|
||||
// Qt 6.9+ scrolling: flickDeceleration/maximumFlickVelocity only affect touch now
|
||||
flickDeceleration: 1500
|
||||
maximumFlickVelocity: 2000
|
||||
|
||||
// Custom wheel handler for Qt 6.9+ responsive mouse wheel scrolling
|
||||
WheelHandler {
|
||||
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
|
||||
onWheel: event => {
|
||||
let delta = event.pixelDelta.y
|
||||
!== 0 ? event.pixelDelta.y * 1.8 : event.angleDelta.y / 120 * 60
|
||||
let newY = parent.contentY - delta
|
||||
newY = Math.max(
|
||||
0, Math.min(parent.contentHeight - parent.height,
|
||||
newY))
|
||||
parent.contentY = newY
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: spanningNetworksColumn
|
||||
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
Repeater {
|
||||
model: NetworkService.wifiAvailable
|
||||
&& NetworkService.wifiEnabled ? sortedWifiNetworks : []
|
||||
|
||||
Rectangle {
|
||||
width: spanningNetworksColumn.width
|
||||
height: 38
|
||||
radius: Theme.cornerRadius
|
||||
color: networkArea2.containsMouse ? Qt.rgba(
|
||||
Theme.primary.r,
|
||||
Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.08) : modelData.connected ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||
border.color: modelData.connected ? Theme.primary : "transparent"
|
||||
border.width: modelData.connected ? 1 : 0
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingXS
|
||||
anchors.rightMargin: Theme.spacingM // Extra right margin for scrollbar
|
||||
|
||||
DankIcon {
|
||||
id: signalIcon2
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
name: NetworkService.wifiSignalIcon
|
||||
size: Theme.iconSize - 2
|
||||
color: modelData.connected ? Theme.primary : Theme.surfaceText
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.left: signalIcon2.right
|
||||
anchors.leftMargin: Theme.spacingXS
|
||||
anchors.right: rightIcons2.left
|
||||
anchors.rightMargin: Theme.spacingXS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: modelData.ssid
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: modelData.connected ? Theme.primary : Theme.surfaceText
|
||||
font.weight: modelData.connected ? Font.Medium : Font.Normal
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: {
|
||||
if (modelData.connected)
|
||||
return "Connected"
|
||||
|
||||
if (NetworkService.connectionStatus === "connecting"
|
||||
&& NetworkService.connectingSSID === modelData.ssid)
|
||||
return "Connecting..."
|
||||
|
||||
if (NetworkService.connectionStatus === "invalid_password"
|
||||
&& NetworkService.connectingSSID === modelData.ssid)
|
||||
return "Invalid password"
|
||||
|
||||
if (modelData.saved)
|
||||
return "Saved"
|
||||
+ (modelData.secured ? " • Secured" : " • Open")
|
||||
|
||||
return modelData.secured ? "Secured" : "Open"
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall - 1
|
||||
color: {
|
||||
if (NetworkService.connectionStatus === "connecting"
|
||||
&& NetworkService.connectingSSID === modelData.ssid)
|
||||
return Theme.primary
|
||||
|
||||
if (NetworkService.connectionStatus === "invalid_password"
|
||||
&& NetworkService.connectingSSID === modelData.ssid)
|
||||
return Theme.error
|
||||
|
||||
return Qt.rgba(Theme.surfaceText.r,
|
||||
Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.7)
|
||||
}
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: rightIcons2
|
||||
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
DankIcon {
|
||||
name: "lock"
|
||||
size: Theme.iconSize - 8
|
||||
color: Qt.rgba(Theme.surfaceText.r,
|
||||
Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.6)
|
||||
visible: modelData.secured
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: wifiMenuButton
|
||||
|
||||
width: 24
|
||||
height: 24
|
||||
radius: 12
|
||||
color: wifiMenuButtonArea.containsMouse ? Qt.rgba(
|
||||
Theme.surfaceText.r,
|
||||
Theme.surfaceText.g,
|
||||
Theme.surfaceText.b,
|
||||
0.08) : "transparent"
|
||||
|
||||
DankIcon {
|
||||
name: "more_vert"
|
||||
size: Theme.iconSize - 8
|
||||
color: Theme.surfaceText
|
||||
opacity: 0.6
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: wifiMenuButtonArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
wifiContextMenuWindow.networkData = modelData
|
||||
let buttonCenter = wifiMenuButtonArea.width / 2
|
||||
let buttonBottom = wifiMenuButtonArea.height
|
||||
let globalPos = wifiMenuButtonArea.mapToItem(
|
||||
wifiContextMenuWindow.parentItem,
|
||||
buttonCenter, buttonBottom)
|
||||
Qt.callLater(() => {
|
||||
wifiContextMenuWindow.show(
|
||||
globalPos.x,
|
||||
globalPos.y)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: networkArea2
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: 32 // Exclude menu button area
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (modelData.connected)
|
||||
return
|
||||
|
||||
if (modelData.saved) {
|
||||
NetworkService.connectToWifi(modelData.ssid)
|
||||
} else if (modelData.secured) {
|
||||
if (wifiPasswordModalRef) {
|
||||
wifiPasswordModalRef.show(modelData.ssid)
|
||||
}
|
||||
} else {
|
||||
NetworkService.connectToWifi(modelData.ssid)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
policy: ScrollBar.AsNeeded
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,251 +9,256 @@ import qs.Widgets
|
||||
import qs.Modules.ControlCenter.Network
|
||||
|
||||
Item {
|
||||
id: networkTab
|
||||
id: networkTab
|
||||
|
||||
property var wifiPasswordModalRef: {
|
||||
wifiPasswordModalLoader.active = true
|
||||
return wifiPasswordModalLoader.item
|
||||
}
|
||||
property var networkInfoModalRef: {
|
||||
networkInfoModalLoader.active = true
|
||||
return networkInfoModalLoader.item
|
||||
}
|
||||
|
||||
property var sortedWifiNetworks: {
|
||||
if (!NetworkService.wifiAvailable || !NetworkService.wifiEnabled) {
|
||||
return []
|
||||
property var wifiPasswordModalRef: {
|
||||
wifiPasswordModalLoader.active = true
|
||||
return wifiPasswordModalLoader.item
|
||||
}
|
||||
property var networkInfoModalRef: {
|
||||
networkInfoModalLoader.active = true
|
||||
return networkInfoModalLoader.item
|
||||
}
|
||||
|
||||
var allNetworks = NetworkService.wifiNetworks
|
||||
var savedNetworks = NetworkService.savedWifiNetworks
|
||||
var currentSSID = NetworkService.currentWifiSSID
|
||||
var signalStrength = NetworkService.wifiSignalStrengthStr
|
||||
var refreshTrigger = forceRefresh
|
||||
property var sortedWifiNetworks: {
|
||||
if (!NetworkService.wifiAvailable || !NetworkService.wifiEnabled) {
|
||||
return []
|
||||
}
|
||||
|
||||
// Force recalculation
|
||||
var networks = [...allNetworks]
|
||||
var allNetworks = NetworkService.wifiNetworks
|
||||
var savedNetworks = NetworkService.savedWifiNetworks
|
||||
var currentSSID = NetworkService.currentWifiSSID
|
||||
var signalStrength = NetworkService.wifiSignalStrengthStr
|
||||
var refreshTrigger = forceRefresh
|
||||
|
||||
networks.forEach(function (network) {
|
||||
network.connected = (network.ssid === currentSSID)
|
||||
network.saved = savedNetworks.some(function (saved) {
|
||||
return saved.ssid === network.ssid
|
||||
})
|
||||
if (network.connected && signalStrength) {
|
||||
network.signalStrength = signalStrength
|
||||
}
|
||||
})
|
||||
// Force recalculation
|
||||
var networks = [...allNetworks]
|
||||
|
||||
networks.sort(function (a, b) {
|
||||
if (a.connected && !b.connected)
|
||||
return -1
|
||||
if (!a.connected && b.connected)
|
||||
return 1
|
||||
return b.signal - a.signal
|
||||
})
|
||||
networks.forEach(function (network) {
|
||||
network.connected = (network.ssid === currentSSID)
|
||||
network.saved = savedNetworks.some(function (saved) {
|
||||
return saved.ssid === network.ssid
|
||||
})
|
||||
if (network.connected && signalStrength) {
|
||||
network.signalStrength = signalStrength
|
||||
}
|
||||
})
|
||||
|
||||
return networks
|
||||
}
|
||||
networks.sort(function (a, b) {
|
||||
if (a.connected && !b.connected)
|
||||
return -1
|
||||
if (!a.connected && b.connected)
|
||||
return 1
|
||||
return b.signal - a.signal
|
||||
})
|
||||
|
||||
property int forceRefresh: 0
|
||||
|
||||
Connections {
|
||||
target: NetworkService
|
||||
function onNetworksUpdated() {
|
||||
forceRefresh++
|
||||
return networks
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
NetworkService.addRef()
|
||||
if (NetworkService.wifiEnabled)
|
||||
NetworkService.scanWifi()
|
||||
}
|
||||
property int forceRefresh: 0
|
||||
|
||||
Component.onDestruction: {
|
||||
NetworkService.removeRef()
|
||||
}
|
||||
Connections {
|
||||
target: NetworkService
|
||||
function onNetworksUpdated() {
|
||||
forceRefresh++
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.fill: parent
|
||||
spacing: Theme.spacingM
|
||||
Component.onCompleted: {
|
||||
NetworkService.addRef()
|
||||
if (NetworkService.wifiEnabled)
|
||||
NetworkService.scanWifi()
|
||||
}
|
||||
|
||||
Column {
|
||||
width: (parent.width - Theme.spacingM) / 2
|
||||
height: parent.height
|
||||
spacing: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
Component.onDestruction: {
|
||||
NetworkService.removeRef()
|
||||
}
|
||||
|
||||
Flickable {
|
||||
width: parent.width
|
||||
height: parent.height - 30
|
||||
clip: true
|
||||
contentWidth: width
|
||||
contentHeight: wifiContent.height
|
||||
boundsBehavior: Flickable.DragAndOvershootBounds
|
||||
// Qt 6.9+ scrolling: flickDeceleration/maximumFlickVelocity only affect touch now
|
||||
flickDeceleration: 1500
|
||||
maximumFlickVelocity: 2000
|
||||
Row {
|
||||
anchors.fill: parent
|
||||
spacing: Theme.spacingM
|
||||
|
||||
// Custom wheel handler for Qt 6.9+ responsive mouse wheel scrolling
|
||||
WheelHandler {
|
||||
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
|
||||
onWheel: event => {
|
||||
let delta = event.pixelDelta.y
|
||||
!== 0 ? event.pixelDelta.y * 1.8 : event.angleDelta.y / 120 * 60
|
||||
let newY = parent.contentY - delta
|
||||
newY = Math.max(
|
||||
0, Math.min(parent.contentHeight - parent.height, newY))
|
||||
parent.contentY = newY
|
||||
event.accepted = true
|
||||
}
|
||||
Column {
|
||||
width: (parent.width - Theme.spacingM) / 2
|
||||
height: parent.height
|
||||
spacing: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Flickable {
|
||||
width: parent.width
|
||||
height: parent.height - 30
|
||||
clip: true
|
||||
contentWidth: width
|
||||
contentHeight: wifiContent.height
|
||||
boundsBehavior: Flickable.DragAndOvershootBounds
|
||||
// Qt 6.9+ scrolling: flickDeceleration/maximumFlickVelocity only affect touch now
|
||||
flickDeceleration: 1500
|
||||
maximumFlickVelocity: 2000
|
||||
|
||||
// Custom wheel handler for Qt 6.9+ responsive mouse wheel scrolling
|
||||
WheelHandler {
|
||||
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
|
||||
onWheel: event => {
|
||||
let delta = event.pixelDelta.y
|
||||
!== 0 ? event.pixelDelta.y * 1.8 : event.angleDelta.y / 120 * 60
|
||||
let newY = parent.contentY - delta
|
||||
newY = Math.max(
|
||||
0, Math.min(
|
||||
parent.contentHeight - parent.height,
|
||||
newY))
|
||||
parent.contentY = newY
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: wifiContent
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
WiFiCard {}
|
||||
}
|
||||
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
policy: ScrollBar.AsNeeded
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: wifiContent
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
width: (parent.width - Theme.spacingM) / 2
|
||||
height: parent.height
|
||||
spacing: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
WiFiCard {}
|
||||
}
|
||||
Flickable {
|
||||
width: parent.width
|
||||
height: parent.height - 30
|
||||
clip: true
|
||||
contentWidth: width
|
||||
contentHeight: ethernetContent.height
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
// Qt 6.9+ scrolling: flickDeceleration/maximumFlickVelocity only affect touch now
|
||||
flickDeceleration: 1500
|
||||
maximumFlickVelocity: 2000
|
||||
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
policy: ScrollBar.AsNeeded
|
||||
// Custom wheel handler for Qt 6.9+ responsive mouse wheel scrolling
|
||||
WheelHandler {
|
||||
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
|
||||
onWheel: event => {
|
||||
let delta = event.pixelDelta.y
|
||||
!== 0 ? event.pixelDelta.y * 1.8 : event.angleDelta.y / 120 * 60
|
||||
let newY = parent.contentY - delta
|
||||
newY = Math.max(
|
||||
0, Math.min(
|
||||
parent.contentHeight - parent.height,
|
||||
newY))
|
||||
parent.contentY = newY
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: ethernetContent
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
EthernetCard {}
|
||||
}
|
||||
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
policy: ScrollBar.AsNeeded
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: (parent.width - Theme.spacingM) / 2
|
||||
height: parent.height
|
||||
spacing: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Flickable {
|
||||
width: parent.width
|
||||
height: parent.height - 30
|
||||
clip: true
|
||||
contentWidth: width
|
||||
contentHeight: ethernetContent.height
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
// Qt 6.9+ scrolling: flickDeceleration/maximumFlickVelocity only affect touch now
|
||||
flickDeceleration: 1500
|
||||
maximumFlickVelocity: 2000
|
||||
|
||||
// Custom wheel handler for Qt 6.9+ responsive mouse wheel scrolling
|
||||
WheelHandler {
|
||||
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
|
||||
onWheel: event => {
|
||||
let delta = event.pixelDelta.y
|
||||
!== 0 ? event.pixelDelta.y * 1.8 : event.angleDelta.y / 120 * 60
|
||||
let newY = parent.contentY - delta
|
||||
newY = Math.max(
|
||||
0, Math.min(parent.contentHeight - parent.height, newY))
|
||||
parent.contentY = newY
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 100
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
color: "transparent"
|
||||
visible: !NetworkService.wifiEnabled
|
||||
|
||||
Column {
|
||||
id: ethernetContent
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingM
|
||||
|
||||
EthernetCard {}
|
||||
DankIcon {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
name: "wifi_off"
|
||||
size: 48
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.3)
|
||||
}
|
||||
|
||||
StyledText {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: "WiFi is turned off"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.6)
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
StyledText {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: "Turn on WiFi to see networks"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.4)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
policy: ScrollBar.AsNeeded
|
||||
WiFiNetworksList {
|
||||
wifiContextMenuWindow: wifiContextMenuWindow
|
||||
sortedWifiNetworks: networkTab.sortedWifiNetworks
|
||||
wifiPasswordModalRef: networkTab.wifiPasswordModalRef
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: NetworkService
|
||||
function onWifiEnabledChanged() {
|
||||
if (NetworkService.wifiEnabled && visible) {
|
||||
// Trigger a scan when WiFi is enabled
|
||||
NetworkService.scanWifi()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 100
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
color: "transparent"
|
||||
visible: !NetworkService.wifiEnabled
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
name: "wifi_off"
|
||||
size: 48
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.3)
|
||||
}
|
||||
|
||||
StyledText {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: "WiFi is turned off"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.6)
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
StyledText {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: "Turn on WiFi to see networks"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||
Theme.surfaceText.b, 0.4)
|
||||
}
|
||||
onVisibleChanged: {
|
||||
if (visible && NetworkService.wifiEnabled
|
||||
&& NetworkService.wifiNetworks.length === 0) {
|
||||
// Scan when tab becomes visible if we don't have networks cached
|
||||
NetworkService.scanWifi()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WiFiNetworksList {
|
||||
wifiContextMenuWindow: wifiContextMenuWindow
|
||||
sortedWifiNetworks: networkTab.sortedWifiNetworks
|
||||
wifiPasswordModalRef: networkTab.wifiPasswordModalRef
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: NetworkService
|
||||
function onWifiEnabledChanged() {
|
||||
if (NetworkService.wifiEnabled && visible) {
|
||||
// Trigger a scan when WiFi is enabled
|
||||
NetworkService.scanWifi()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible && NetworkService.wifiEnabled && NetworkService.wifiNetworks.length === 0) {
|
||||
// Scan when tab becomes visible if we don't have networks cached
|
||||
NetworkService.scanWifi()
|
||||
}
|
||||
}
|
||||
|
||||
WiFiContextMenu {
|
||||
id: wifiContextMenuWindow
|
||||
parentItem: networkTab
|
||||
wifiPasswordModalRef: networkTab.wifiPasswordModalRef
|
||||
networkInfoModalRef: networkTab.networkInfoModalRef
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
visible: wifiContextMenuWindow.visible
|
||||
onClicked: {
|
||||
wifiContextMenuWindow.hide()
|
||||
WiFiContextMenu {
|
||||
id: wifiContextMenuWindow
|
||||
parentItem: networkTab
|
||||
wifiPasswordModalRef: networkTab.wifiPasswordModalRef
|
||||
networkInfoModalRef: networkTab.networkInfoModalRef
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
x: wifiContextMenuWindow.x
|
||||
y: wifiContextMenuWindow.y
|
||||
width: wifiContextMenuWindow.width
|
||||
height: wifiContextMenuWindow.height
|
||||
onClicked: {
|
||||
anchors.fill: parent
|
||||
visible: wifiContextMenuWindow.visible
|
||||
onClicked: {
|
||||
wifiContextMenuWindow.hide()
|
||||
}
|
||||
|
||||
}
|
||||
MouseArea {
|
||||
x: wifiContextMenuWindow.x
|
||||
y: wifiContextMenuWindow.y
|
||||
width: wifiContextMenuWindow.width
|
||||
height: wifiContextMenuWindow.height
|
||||
onClicked: {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,292 +8,305 @@ import qs.Common
|
||||
import qs.Widgets
|
||||
|
||||
PanelWindow {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
property bool powerMenuVisible: false
|
||||
signal powerActionRequested(string action, string title, string message)
|
||||
property bool powerMenuVisible: false
|
||||
signal powerActionRequested(string action, string title, string message)
|
||||
|
||||
visible: powerMenuVisible
|
||||
implicitWidth: 400
|
||||
implicitHeight: 320
|
||||
WlrLayershell.layer: WlrLayershell.Overlay
|
||||
WlrLayershell.exclusiveZone: -1
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
color: "transparent"
|
||||
visible: powerMenuVisible
|
||||
implicitWidth: 400
|
||||
implicitHeight: 320
|
||||
WlrLayershell.layer: WlrLayershell.Overlay
|
||||
WlrLayershell.exclusiveZone: -1
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
color: "transparent"
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
left: true
|
||||
right: true
|
||||
bottom: true
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
powerMenuVisible = false
|
||||
anchors {
|
||||
top: true
|
||||
left: true
|
||||
right: true
|
||||
bottom: true
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: Math.min(320, parent.width - Theme.spacingL * 2)
|
||||
height: 320 // Fixed height to prevent cropping
|
||||
x: Math.max(Theme.spacingL, parent.width - width - Theme.spacingL)
|
||||
y: Theme.barHeight + Theme.spacingXS
|
||||
color: Theme.popupBackground()
|
||||
radius: Theme.cornerRadius
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.08)
|
||||
border.width: 1
|
||||
opacity: powerMenuVisible ? 1 : 0
|
||||
scale: powerMenuVisible ? 1 : 0.85
|
||||
|
||||
MouseArea {
|
||||
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
|
||||
StyledText {
|
||||
text: "Power Options"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width - 150
|
||||
height: 1
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
iconName: "close"
|
||||
iconSize: Theme.iconSize - 4
|
||||
iconColor: Theme.surfaceText
|
||||
hoverColor: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12)
|
||||
onClicked: {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
powerMenuVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: logoutArea.containsMouse ? Qt.rgba(Theme.primary.r,
|
||||
Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.08) : Qt.rgba(
|
||||
Theme.surfaceVariant.r,
|
||||
Theme.surfaceVariant.g,
|
||||
Theme.surfaceVariant.b, 0.08)
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "logout"
|
||||
size: Theme.iconSize
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Log Out"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: logoutArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
powerMenuVisible = false
|
||||
root.powerActionRequested("logout", "Log Out", "Are you sure you want to log out?")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: suspendArea.containsMouse ? Qt.rgba(Theme.primary.r,
|
||||
Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.08) : Qt.rgba(
|
||||
Theme.surfaceVariant.r,
|
||||
Theme.surfaceVariant.g,
|
||||
Theme.surfaceVariant.b, 0.08)
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "bedtime"
|
||||
size: Theme.iconSize
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Suspend"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: suspendArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
powerMenuVisible = false
|
||||
root.powerActionRequested("suspend", "Suspend", "Are you sure you want to suspend the system?")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: rebootArea.containsMouse ? Qt.rgba(Theme.warning.r,
|
||||
Theme.warning.g,
|
||||
Theme.warning.b,
|
||||
0.08) : Qt.rgba(
|
||||
Theme.surfaceVariant.r,
|
||||
Theme.surfaceVariant.g,
|
||||
Theme.surfaceVariant.b, 0.08)
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "restart_alt"
|
||||
size: Theme.iconSize
|
||||
color: rebootArea.containsMouse ? Theme.warning : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Reboot"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: rebootArea.containsMouse ? Theme.warning : Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: rebootArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
powerMenuVisible = false
|
||||
root.powerActionRequested("reboot", "Reboot", "Are you sure you want to reboot the system?")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: powerOffArea.containsMouse ? Qt.rgba(Theme.error.r,
|
||||
Theme.error.g,
|
||||
Theme.error.b,
|
||||
0.08) : Qt.rgba(
|
||||
Theme.surfaceVariant.r,
|
||||
Theme.surfaceVariant.g,
|
||||
Theme.surfaceVariant.b, 0.08)
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "power_settings_new"
|
||||
size: Theme.iconSize
|
||||
color: powerOffArea.containsMouse ? Theme.error : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Power Off"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: powerOffArea.containsMouse ? Theme.error : Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: powerOffArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
powerMenuVisible = false
|
||||
root.powerActionRequested("poweroff", "Power Off", "Are you sure you want to power off the system?")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
width: Math.min(320, parent.width - Theme.spacingL * 2)
|
||||
height: 320 // Fixed height to prevent cropping
|
||||
x: Math.max(Theme.spacingL, parent.width - width - Theme.spacingL)
|
||||
y: Theme.barHeight + Theme.spacingXS
|
||||
color: Theme.popupBackground()
|
||||
radius: Theme.cornerRadius
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.08)
|
||||
border.width: 1
|
||||
opacity: powerMenuVisible ? 1 : 0
|
||||
scale: powerMenuVisible ? 1 : 0.85
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
MouseArea {
|
||||
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
|
||||
StyledText {
|
||||
text: "Power Options"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width - 150
|
||||
height: 1
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
iconName: "close"
|
||||
iconSize: Theme.iconSize - 4
|
||||
iconColor: Theme.surfaceText
|
||||
hoverColor: Qt.rgba(Theme.error.r, Theme.error.g,
|
||||
Theme.error.b, 0.12)
|
||||
onClicked: {
|
||||
powerMenuVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: logoutArea.containsMouse ? Qt.rgba(Theme.primary.r,
|
||||
Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.08) : Qt.rgba(
|
||||
Theme.surfaceVariant.r,
|
||||
Theme.surfaceVariant.g,
|
||||
Theme.surfaceVariant.b,
|
||||
0.08)
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "logout"
|
||||
size: Theme.iconSize
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Log Out"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: logoutArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
powerMenuVisible = false
|
||||
root.powerActionRequested(
|
||||
"logout", "Log Out",
|
||||
"Are you sure you want to log out?")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: suspendArea.containsMouse ? Qt.rgba(Theme.primary.r,
|
||||
Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.08) : Qt.rgba(
|
||||
Theme.surfaceVariant.r,
|
||||
Theme.surfaceVariant.g,
|
||||
Theme.surfaceVariant.b,
|
||||
0.08)
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "bedtime"
|
||||
size: Theme.iconSize
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Suspend"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: suspendArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
powerMenuVisible = false
|
||||
root.powerActionRequested(
|
||||
"suspend", "Suspend",
|
||||
"Are you sure you want to suspend the system?")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: rebootArea.containsMouse ? Qt.rgba(Theme.warning.r,
|
||||
Theme.warning.g,
|
||||
Theme.warning.b,
|
||||
0.08) : Qt.rgba(
|
||||
Theme.surfaceVariant.r,
|
||||
Theme.surfaceVariant.g,
|
||||
Theme.surfaceVariant.b,
|
||||
0.08)
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "restart_alt"
|
||||
size: Theme.iconSize
|
||||
color: rebootArea.containsMouse ? Theme.warning : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Reboot"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: rebootArea.containsMouse ? Theme.warning : Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: rebootArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
powerMenuVisible = false
|
||||
root.powerActionRequested(
|
||||
"reboot", "Reboot",
|
||||
"Are you sure you want to reboot the system?")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: powerOffArea.containsMouse ? Qt.rgba(Theme.error.r,
|
||||
Theme.error.g,
|
||||
Theme.error.b,
|
||||
0.08) : Qt.rgba(
|
||||
Theme.surfaceVariant.r,
|
||||
Theme.surfaceVariant.g,
|
||||
Theme.surfaceVariant.b,
|
||||
0.08)
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "power_settings_new"
|
||||
size: Theme.iconSize
|
||||
color: powerOffArea.containsMouse ? Theme.error : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Power Off"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: powerOffArea.containsMouse ? Theme.error : Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: powerOffArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
powerMenuVisible = false
|
||||
root.powerActionRequested(
|
||||
"poweroff", "Power Off",
|
||||
"Are you sure you want to power off the system?")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user