1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-04-03 20:32:07 -04:00
Files
DankMaterialShell/quickshell/Modules/DankBar/Widgets/PrivacyIndicator.qml
2026-02-24 13:59:38 -05:00

248 lines
8.9 KiB
QML

import QtQuick
import qs.Common
import qs.Modules.Plugins
import qs.Services
import qs.Widgets
BasePill {
id: root
section: "right"
property bool showMicIcon: SettingsData.privacyShowMicIcon
property bool showCameraIcon: SettingsData.privacyShowCameraIcon
property bool showScreenSharingIcon: SettingsData.privacyShowScreenShareIcon
readonly property bool hasActivePrivacy: showMicIcon || showCameraIcon || showScreenSharingIcon || PrivacyService.anyPrivacyActive
readonly property int activeCount: (showMicIcon ? 1 : PrivacyService.microphoneActive) + (showCameraIcon ? 1 : PrivacyService.cameraActive) + (showScreenSharingIcon ? 1 : PrivacyService.screensharingActive)
readonly property real contentWidth: hasActivePrivacy ? (activeCount * 18 + (activeCount - 1) * Theme.spacingXS) : 0
readonly property real contentHeight: hasActivePrivacy ? (activeCount * 18 + (activeCount - 1) * Theme.spacingXS) : 0
opacity: hasActivePrivacy ? 1 : 0
states: [
State {
name: "hidden_horizontal"
when: !hasActivePrivacy && !isVerticalOrientation
PropertyChanges {
target: root
width: 0
}
},
State {
name: "hidden_vertical"
when: !hasActivePrivacy && isVerticalOrientation
PropertyChanges {
target: root
height: 0
}
}
]
transitions: [
Transition {
NumberAnimation {
properties: "width,height"
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
]
Behavior on opacity {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
content: Component {
Item {
implicitWidth: root.hasActivePrivacy ? root.contentWidth : 0
implicitHeight: root.hasActivePrivacy ? root.contentHeight : 0
Column {
anchors.centerIn: parent
spacing: Theme.spacingXS
visible: root.isVerticalOrientation && root.hasActivePrivacy
Item {
width: 18
height: 18
visible: root.showMicIcon || PrivacyService.microphoneActive
anchors.horizontalCenter: parent.horizontalCenter
DankIcon {
name: {
const sourceAudio = AudioService.source?.audio;
const muted = !sourceAudio || sourceAudio.muted || sourceAudio.volume === 0.0;
if (muted)
return "mic_off";
return "mic";
}
size: Theme.iconSizeSmall
color: PrivacyService.microphoneActive ? Theme.error : Theme.surfaceText
filled: PrivacyService.microphoneActive
anchors.centerIn: parent
}
}
Item {
width: 18
height: 18
visible: root.showCameraIcon || PrivacyService.cameraActive
anchors.horizontalCenter: parent.horizontalCenter
DankIcon {
name: "camera_video"
size: Theme.iconSizeSmall
color: PrivacyService.cameraActive ? Theme.error : Theme.surfaceText
filled: PrivacyService.cameraActive
anchors.centerIn: parent
}
Rectangle {
width: 6
height: 6
radius: 3
color: Theme.error
anchors.right: parent.right
anchors.top: parent.top
anchors.rightMargin: -2
anchors.topMargin: -1
visible: PrivacyService.cameraActive
}
}
Item {
width: 18
height: 18
visible: root.showScreenSharingIcon || PrivacyService.screensharingActive
anchors.horizontalCenter: parent.horizontalCenter
DankIcon {
name: "screen_share"
size: Theme.iconSizeSmall
color: PrivacyService.screensharingActive ? Theme.warning : Theme.surfaceText
filled: PrivacyService.screensharingActive
anchors.centerIn: parent
}
}
}
Row {
anchors.centerIn: parent
spacing: Theme.spacingXS
visible: !root.isVerticalOrientation && root.hasActivePrivacy
Item {
width: 18
height: 18
visible: root.showMicIcon || PrivacyService.microphoneActive
anchors.verticalCenter: parent.verticalCenter
DankIcon {
name: {
const sourceAudio = AudioService.source?.audio;
const muted = !sourceAudio || sourceAudio.muted || sourceAudio.volume === 0.0;
if (muted)
return "mic_off";
return "mic";
}
size: Theme.iconSizeSmall
color: PrivacyService.microphoneActive ? Theme.error : Theme.surfaceText
filled: PrivacyService.microphoneActive
anchors.centerIn: parent
}
}
Item {
width: 18
height: 18
visible: root.showCameraIcon || PrivacyService.cameraActive
anchors.verticalCenter: parent.verticalCenter
DankIcon {
name: "camera_video"
size: Theme.iconSizeSmall
color: PrivacyService.cameraActive ? Theme.error : Theme.surfaceText
filled: PrivacyService.cameraActive
anchors.centerIn: parent
}
Rectangle {
width: 6
height: 6
radius: 3
color: Theme.error
anchors.right: parent.right
anchors.top: parent.top
anchors.rightMargin: -2
anchors.topMargin: -1
visible: PrivacyService.cameraActive
}
}
Item {
width: 18
height: 18
visible: root.showScreenSharingIcon || PrivacyService.screensharingActive
anchors.verticalCenter: parent.verticalCenter
DankIcon {
name: "screen_share"
size: Theme.iconSizeSmall
color: PrivacyService.screensharingActive ? Theme.warning : Theme.surfaceText
filled: PrivacyService.screensharingActive
anchors.centerIn: parent
}
}
}
}
}
Rectangle {
id: tooltip
width: tooltipText.contentWidth + Theme.spacingM * 2
height: tooltipText.contentHeight + Theme.spacingS * 2
radius: Theme.cornerRadius
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
border.color: Theme.outlineMedium
border.width: 1
visible: false
opacity: root.isMouseHovered && hasActivePrivacy ? 1 : 0
z: 100
x: (parent.width - width) / 2
y: -height - Theme.spacingXS
StyledText {
id: tooltipText
anchors.centerIn: parent
text: PrivacyService.getPrivacySummary()
font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale, barConfig?.maximizeWidgetText)
color: Theme.widgetTextColor
}
Rectangle {
width: 8
height: 8
color: parent.color
border.color: parent.border.color
border.width: parent.border.width
rotation: 45
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.bottom
anchors.topMargin: -4
}
Behavior on opacity {
enabled: hasActivePrivacy && root.visible
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}