inital commit
This commit is contained in:
@@ -0,0 +1,273 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Services.Pipewire
|
||||
import qs.Commons
|
||||
import qs.Modules.Bar.Extras
|
||||
import qs.Services.UI
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property var pluginApi: null
|
||||
|
||||
property ShellScreen screen
|
||||
property string widgetId: ""
|
||||
property string section: ""
|
||||
|
||||
readonly property string barPosition: Settings.data.bar.position
|
||||
readonly property bool isVertical: barPosition === "left" || barPosition === "right"
|
||||
|
||||
property bool micActive: false
|
||||
property bool camActive: false
|
||||
property bool scrActive: false
|
||||
property var micApps: []
|
||||
property var camApps: []
|
||||
property var scrApps: []
|
||||
|
||||
property var cfg: pluginApi?.pluginSettings || ({})
|
||||
property var defaults: pluginApi?.manifest?.metadata?.defaultSettings || ({})
|
||||
|
||||
property bool hideInactive: cfg.hideInactive ?? defaults.hideInactive
|
||||
property bool removeMargins: cfg.removeMargins ?? defaults.removeMargins
|
||||
property int iconSpacing: cfg.iconSpacing || Style.marginXS
|
||||
|
||||
readonly property color activeColor: Color.mPrimary
|
||||
readonly property color inactiveColor: Qt.alpha(Color.mOnSurfaceVariant, 0.3)
|
||||
readonly property color micColor: micActive ? activeColor : inactiveColor
|
||||
readonly property color camColor: camActive ? activeColor : inactiveColor
|
||||
readonly property color scrColor: scrActive ? activeColor : inactiveColor
|
||||
|
||||
readonly property bool isVisible: !hideInactive || micActive || camActive || scrActive
|
||||
|
||||
property real margins: removeMargins ? 0 : Style.marginM * 2
|
||||
implicitWidth: isVertical ? Style.capsuleHeight : Math.round(layout.implicitWidth + margins)
|
||||
implicitHeight: isVertical ? Math.round(layout.implicitHeight + margins) : Style.capsuleHeight
|
||||
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
radius: Style.radiusM
|
||||
color: Style.capsuleColor
|
||||
visible: root.isVisible
|
||||
opacity: root.isVisible ? 1.0 : 0.0
|
||||
|
||||
PwObjectTracker {
|
||||
objects: Pipewire.ready ? Pipewire.nodes.values : []
|
||||
}
|
||||
|
||||
Process {
|
||||
id: cameraCheckProcess
|
||||
running: false
|
||||
|
||||
command: ["sh", "-c", "for dev in /dev/video*; do [ -e \"$dev\" ] && [ -n \"$(find /proc/[0-9]*/fd/ -lname \"$dev\" 2>/dev/null | head -n1)\" ] && echo \"active\" && exit 0; done; exit 1"]
|
||||
|
||||
onExited: (code, status) => {
|
||||
var isActive = code === 0;
|
||||
root.camActive = isActive;
|
||||
|
||||
if (isActive) {
|
||||
cameraAppsProcess.running = true;
|
||||
} else {
|
||||
root.camApps = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: cameraAppsProcess
|
||||
running: false
|
||||
|
||||
command: ["sh", "-c", "for dev in /dev/video*; do [ -e \"$dev\" ] && for fd in /proc/[0-9]*/fd/*; do [ -L \"$fd\" ] && [ \"$(readlink \"$fd\" 2>/dev/null)\" = \"$dev\" ] && ps -p \"$(echo \"$fd\" | cut -d/ -f3)\" -o comm= 2>/dev/null; done; done | sort -u | tr '\\n' ',' | sed 's/,$//'"]
|
||||
|
||||
onExited: (code, status) => {
|
||||
if (stdout) {
|
||||
var appsString = stdout.trim();
|
||||
var apps = appsString.length > 0 ? appsString.split(',') : [];
|
||||
root.camApps = apps;
|
||||
} else {
|
||||
root.camApps = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 1000
|
||||
repeat: true
|
||||
running: true
|
||||
triggeredOnStart: true
|
||||
onTriggered: updatePrivacyState()
|
||||
}
|
||||
|
||||
function hasNodeLinks(node, links) {
|
||||
for (var i = 0; i < links.length; i++) {
|
||||
var link = links[i];
|
||||
if (link && (link.source === node || link.target === node)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getAppName(node) {
|
||||
return node.properties["application.name"] || node.nickname || node.name || "";
|
||||
}
|
||||
|
||||
function updateMicrophoneState(nodes, links) {
|
||||
var appNames = [];
|
||||
var isActive = false;
|
||||
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
var node = nodes[i];
|
||||
if (!node || !node.isStream || !node.audio || node.isSink) continue;
|
||||
if (!hasNodeLinks(node, links) || !node.properties) continue;
|
||||
|
||||
var mediaClass = node.properties["media.class"] || "";
|
||||
if (mediaClass === "Stream/Input/Audio") {
|
||||
if (node.properties["stream.capture.sink"] === "true") {
|
||||
continue;
|
||||
}
|
||||
|
||||
isActive = true;
|
||||
var appName = getAppName(node);
|
||||
if (appName && appNames.indexOf(appName) === -1) {
|
||||
appNames.push(appName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
root.micActive = isActive;
|
||||
root.micApps = appNames;
|
||||
}
|
||||
|
||||
function updateCameraState() {
|
||||
cameraCheckProcess.running = true;
|
||||
}
|
||||
|
||||
function isScreenShareNode(node) {
|
||||
if (!node.properties) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var mediaClass = node.properties["media.class"] || "";
|
||||
|
||||
if (mediaClass.indexOf("Audio") >= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mediaClass.indexOf("Video") === -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var mediaName = (node.properties["media.name"] || "").toLowerCase();
|
||||
|
||||
if (mediaName.match(/^(xdph-streaming|gsr-default|game capture|screen|desktop|display|cast|webrtc|v4l2)/) ||
|
||||
mediaName === "gsr-default_output" ||
|
||||
mediaName.match(/screen-cast|screen-capture|desktop-capture|monitor-capture|window-capture|game-capture/i)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function updateScreenShareState(nodes, links) {
|
||||
var appNames = [];
|
||||
var isActive = false;
|
||||
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
var node = nodes[i];
|
||||
if (!node || !hasNodeLinks(node, links) || !node.properties) continue;
|
||||
|
||||
if (isScreenShareNode(node)) {
|
||||
isActive = true;
|
||||
var appName = getAppName(node);
|
||||
if (appName && appNames.indexOf(appName) === -1) {
|
||||
appNames.push(appName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
root.scrActive = isActive;
|
||||
root.scrApps = appNames;
|
||||
}
|
||||
|
||||
function updatePrivacyState() {
|
||||
if (!Pipewire.ready) return;
|
||||
|
||||
var nodes = Pipewire.nodes.values || [];
|
||||
var links = Pipewire.links.values || [];
|
||||
|
||||
updateMicrophoneState(nodes, links);
|
||||
updateCameraState();
|
||||
updateScreenShareState(nodes, links);
|
||||
}
|
||||
|
||||
function buildTooltip() {
|
||||
var parts = [];
|
||||
|
||||
if (micActive && micApps.length > 0) {
|
||||
parts.push("Mic: " + micApps.join(", "));
|
||||
}
|
||||
|
||||
if (camActive && camApps.length > 0) {
|
||||
parts.push("Cam: " + camApps.join(", "));
|
||||
}
|
||||
|
||||
if (scrActive && scrApps.length > 0) {
|
||||
parts.push("Screen sharing: " + scrApps.join(", "));
|
||||
}
|
||||
|
||||
return parts.length > 0 ? parts.join("\n") : "";
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.RightButton
|
||||
hoverEnabled: true
|
||||
|
||||
onEntered: {
|
||||
var tooltipText = buildTooltip();
|
||||
if (tooltipText) {
|
||||
TooltipService.show(root, tooltipText, BarService.getTooltipDirection());
|
||||
}
|
||||
}
|
||||
onExited: TooltipService.hide()
|
||||
}
|
||||
|
||||
Item {
|
||||
id: layout
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
implicitWidth: iconsLayout.implicitWidth
|
||||
implicitHeight: iconsLayout.implicitHeight
|
||||
|
||||
GridLayout {
|
||||
id: iconsLayout
|
||||
|
||||
columns: root.isVertical ? 1 : 3
|
||||
rows: root.isVertical ? 3 : 1
|
||||
|
||||
rowSpacing: root.iconSpacing
|
||||
columnSpacing: root.iconSpacing
|
||||
|
||||
NIcon {
|
||||
visible: micActive || !root.hideInactive
|
||||
icon: micActive ? "microphone" : "microphone-off"
|
||||
color: root.micColor
|
||||
}
|
||||
NIcon {
|
||||
visible: camActive || !root.hideInactive
|
||||
icon: camActive ? "camera" : "camera-off"
|
||||
color: root.camColor
|
||||
}
|
||||
NIcon {
|
||||
visible: scrActive || !root.hideInactive
|
||||
icon: scrActive ? "screen-share" : "screen-share-off"
|
||||
color: root.scrColor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
# Privacy Indicator Plugin
|
||||
|
||||
A privacy indicator widget that monitors and displays when microphone, camera, or screen sharing is active on your system.
|
||||
|
||||
## Features
|
||||
|
||||
- **Microphone Monitoring**: Detects active microphone usage via Pipewire
|
||||
- **Camera Monitoring**: Detects active camera usage by checking `/dev/video*` devices
|
||||
- **Screen Sharing Detection**: Monitors screen sharing sessions via Pipewire
|
||||
- **Visual Indicators**: Shows icons that change color based on active state
|
||||
- Active: Primary color
|
||||
- Inactive: Semi-transparent variant color
|
||||
- **App Information**: Tooltip displays which applications are using each resource
|
||||
- **Adaptive Layout**: Automatically adjusts layout for horizontal or vertical bar positions
|
||||
|
||||
## Configuration
|
||||
|
||||
Access the plugin settings in Noctalia to configure the following options:
|
||||
|
||||
- **Hide Inactive States**: If enabled, microphone, camera, and screen icons are hidden whenever they are inactive. Only active states are shown.
|
||||
- **RemoveMargins**: If enabled, removes all outer margins of the widget.
|
||||
- **Icon Spacing**: Controls the horizontal/vertical spacing between the icons.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
The widget displays three icons in the bar:
|
||||
- **Microphone**: Shows when any app is using the microphone
|
||||
- **Camera**: Shows when any app is accessing the camera
|
||||
- **Screen Share**: Shows when screen sharing is active
|
||||
|
||||
Hover over the widget to see a tooltip listing which applications are using each resource.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Noctalia Shell 3.6.0 or higher
|
||||
- Pipewire (for microphone and screen sharing detection)
|
||||
- Access to `/dev/video*` devices (for camera detection)
|
||||
|
||||
## Technical Details
|
||||
|
||||
- Updates privacy state every second
|
||||
- Uses Pipewire API to monitor audio/video streams
|
||||
- Checks `/proc/[0-9]*/fd/` for camera device access
|
||||
- Detects screen sharing by analyzing Pipewire node properties and media class
|
||||
@@ -0,0 +1,88 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import qs.Commons
|
||||
import qs.Widgets
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
property var pluginApi: null
|
||||
|
||||
property var cfg: pluginApi?.pluginSettings || ({})
|
||||
property var defaults: pluginApi?.manifest?.metadata?.defaultSettings || ({})
|
||||
|
||||
property bool hideInactive: cfg.hideInactive ?? defaults.hideInactive
|
||||
property bool removeMargins: cfg.removeMargins ?? defaults.removeMargins
|
||||
property int iconSpacing: cfg.iconSpacing || Style.marginXS
|
||||
|
||||
spacing: Style.marginL
|
||||
|
||||
Component.onCompleted: {
|
||||
Logger.i("PrivacyIndicator", "Settings UI loaded");
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: Style.marginM
|
||||
Layout.fillWidth: true
|
||||
|
||||
NToggle {
|
||||
label: pluginApi?.tr("settings.hideInactive.label")
|
||||
description: pluginApi?.tr("settings.hideInactive.desc")
|
||||
|
||||
checked: root.hideInactive
|
||||
onToggled: function (checked) {
|
||||
root.hideInactive = checked;
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: pluginApi?.tr("settings.removeMargins.label")
|
||||
description: pluginApi?.tr("settings.removeMargins.desc")
|
||||
|
||||
checked: root.removeMargins
|
||||
onToggled: function (checked) {
|
||||
root.removeMargins = checked;
|
||||
}
|
||||
}
|
||||
|
||||
NComboBox {
|
||||
label: pluginApi?.tr("settings.iconSpacing.label")
|
||||
description: pluginApi?.tr("settings.iconSpacing.desc")
|
||||
|
||||
model: {
|
||||
const labels = ["XXS", "XS", "S", "M", "L", "XL"];
|
||||
const values = [Style.marginXXS, Style.marginXS, Style.marginS, Style.marginM, Style.marginL, Style.marginXL];
|
||||
|
||||
const result = [];
|
||||
for (var i = 0; i < labels.length; ++i) {
|
||||
const v = values[i];
|
||||
result.push({
|
||||
key: v.toFixed(0),
|
||||
name: `${labels[i]} (${v}px)`
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// INFO: From my understanding, the toFixed(0) shouldn't be needed here and there, but without the
|
||||
// current key does not show when opening the settings window.
|
||||
currentKey: root.iconSpacing.toFixed(0)
|
||||
onSelected: key => root.iconSpacing = key
|
||||
}
|
||||
}
|
||||
|
||||
function saveSettings() {
|
||||
if (!pluginApi) {
|
||||
Logger.e("PrivacyIndicator", "Cannot save settings: pluginApi is null");
|
||||
return;
|
||||
}
|
||||
|
||||
pluginApi.pluginSettings.hideInactive = root.hideInactive;
|
||||
pluginApi.pluginSettings.iconSpacing = root.iconSpacing;
|
||||
pluginApi.pluginSettings.removeMargins = root.removeMargins;
|
||||
|
||||
pluginApi.saveSettings();
|
||||
|
||||
Logger.i("PrivacyIndicator", "Settings saved successfully");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"settings": {
|
||||
"hideInactive": {
|
||||
"desc": "Mikrofon-, Kamera- und Bildschirmsymbole ausblenden, wenn sie inaktiv sind.",
|
||||
"label": "Inaktive Zustände ausblenden"
|
||||
},
|
||||
"iconSpacing": {
|
||||
"desc": "Den Abstand zwischen den Symbolen festlegen.",
|
||||
"label": "Symbolabstand"
|
||||
},
|
||||
"removeMargins": {
|
||||
"desc": "Alle äußeren Ränder des Widgets entfernen.",
|
||||
"label": "Ränder entfernen"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"cam-on": "Kamera: {apps}",
|
||||
"mic-on": "Mikrofon: {apps}",
|
||||
"screen-on": "Bildschirmfreigabe: {apps}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"settings": {
|
||||
"hideInactive": {
|
||||
"desc": "Hide microphone, camera, and screen icons when there are inactive.",
|
||||
"label": "Hide inactive states"
|
||||
},
|
||||
"iconSpacing": {
|
||||
"desc": "Set the spacing between the icons.",
|
||||
"label": "Icon spacing"
|
||||
},
|
||||
"removeMargins": {
|
||||
"desc": "Remove all outer margins of the widget.",
|
||||
"label": "Remove margins"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"cam-on": "Camera: {apps}",
|
||||
"mic-on": "Microphone: {apps}",
|
||||
"screen-on": "Screen sharing: {apps}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"settings": {
|
||||
"hideInactive": {
|
||||
"desc": "Ocultar los iconos de micrófono, cámara y pantalla cuando estén inactivos.",
|
||||
"label": "Ocultar estados inactivos"
|
||||
},
|
||||
"iconSpacing": {
|
||||
"desc": "Configurar el espacio entre los iconos.",
|
||||
"label": "Espaciado de iconos"
|
||||
},
|
||||
"removeMargins": {
|
||||
"desc": "Quita todos los márgenes externos del widget.",
|
||||
"label": "Quitar márgenes"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"cam-on": "Cámara: {apps}",
|
||||
"mic-on": "Micrófono: {apps}",
|
||||
"screen-on": "Compartir pantalla: {apps}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"settings": {
|
||||
"hideInactive": {
|
||||
"desc": "Masquer les icônes du micro, de la caméra et de l’écran lorsqu’ils sont inactifs.",
|
||||
"label": "Masquer les états inactifs"
|
||||
},
|
||||
"iconSpacing": {
|
||||
"desc": "Définir l’espacement entre les icônes.",
|
||||
"label": "Espacement des icônes"
|
||||
},
|
||||
"removeMargins": {
|
||||
"desc": "Supprime toutes les marges extérieures du widget.",
|
||||
"label": "Supprimer les marges"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"cam-on": "Caméra: {apps}",
|
||||
"mic-on": "Microphone: {apps}",
|
||||
"screen-on": "Partage d'écran: {apps}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"settings": {
|
||||
"hideInactive": {
|
||||
"desc": "Nascondi le icone di microfono, fotocamera e schermo quando sono inattive.",
|
||||
"label": "Nascondi stati inattivi"
|
||||
},
|
||||
"iconSpacing": {
|
||||
"desc": "Imposta la distanza tra le icone.",
|
||||
"label": "Spaziatura delle icone"
|
||||
},
|
||||
"removeMargins": {
|
||||
"desc": "Rimuove tutti i margini esterni del widget.",
|
||||
"label": "Rimuovi margini"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"cam-on": "Kamera: {apps}",
|
||||
"mic-on": "Mikrofonoa: {apps}",
|
||||
"screen-on": "Ekran-partaĝado: {apps}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"settings": {
|
||||
"hideInactive": {
|
||||
"desc": "マイク・カメラ・画面共有のアイコンを、非アクティブなときは非表示にします。",
|
||||
"label": "非アクティブ状態を非表示"
|
||||
},
|
||||
"iconSpacing": {
|
||||
"desc": "アイコン同士の間隔を設定します。",
|
||||
"label": "アイコン間隔"
|
||||
},
|
||||
"removeMargins": {
|
||||
"desc": "ウィジェットの外側の余白をすべて削除します。",
|
||||
"label": "余白を削除"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"cam-on": "カメラ: {apps}",
|
||||
"mic-on": "マイク: {apps}",
|
||||
"screen-on": "画面共有: {apps}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"settings": {
|
||||
"hideInactive": {
|
||||
"desc": "Verberg de pictogrammen voor microfoon, camera en scherm wanneer ze inactief zijn.",
|
||||
"label": "Inactieve status verbergen"
|
||||
},
|
||||
"iconSpacing": {
|
||||
"desc": "Stel de afstand tussen de pictogrammen in.",
|
||||
"label": "Pictogramafstand"
|
||||
},
|
||||
"removeMargins": {
|
||||
"desc": "Verwijdert alle buitenste marges van de widget.",
|
||||
"label": "Marges verwijderen"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"cam-on": "Camera: {apps}",
|
||||
"mic-on": "Microfoon: {apps}",
|
||||
"screen-on": "Schermdeling: {apps}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"settings": {
|
||||
"hideInactive": {
|
||||
"desc": "Oculta os ícones de microfone, câmera e tela quando estiverem inativos.",
|
||||
"label": "Ocultar estados inativos"
|
||||
},
|
||||
"iconSpacing": {
|
||||
"desc": "Define o espaçamento entre os ícones.",
|
||||
"label": "Espaçamento dos ícones"
|
||||
},
|
||||
"removeMargins": {
|
||||
"desc": "Remove todas as margens externas do widget.",
|
||||
"label": "Remover margens"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"cam-on": "Câmera: {apps}",
|
||||
"mic-on": "Microfone: {apps}",
|
||||
"screen-on": "Compartilhamento de tela: {apps}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"settings": {
|
||||
"hideInactive": {
|
||||
"desc": "Скрывать значки микрофона, камеры и экрана, когда они неактивны.",
|
||||
"label": "Скрывать неактивные состояния"
|
||||
},
|
||||
"iconSpacing": {
|
||||
"desc": "Задать расстояние между значками.",
|
||||
"label": "Интервал между значками"
|
||||
},
|
||||
"removeMargins": {
|
||||
"desc": "Удаляет все внешние отступы виджета.",
|
||||
"label": "Убрать отступы"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"cam-on": "Камера: {apps}",
|
||||
"mic-on": "Микрофон: {apps}",
|
||||
"screen-on": "Демонстрация экрана: {apps}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"settings": {
|
||||
"hideInactive": {
|
||||
"desc": "Mikrofon, kamera ve ekran simgelerini pasif olduklarında gizle.",
|
||||
"label": "Pasif durumları gizle"
|
||||
},
|
||||
"iconSpacing": {
|
||||
"desc": "Simgeler arasındaki boşluğu ayarla.",
|
||||
"label": "Simge aralığı"
|
||||
},
|
||||
"removeMargins": {
|
||||
"desc": "Widget’ın tüm dış kenar boşluklarını kaldırır.",
|
||||
"label": "Kenarlıkları kaldır"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"cam-on": "Kamera: {apps}",
|
||||
"mic-on": "Mikrofon: {apps}",
|
||||
"screen-on": "Ekran paylaşımı: {apps}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"settings": {
|
||||
"hideInactive": {
|
||||
"desc": "Приховувати значки мікрофона, камери та екрана, коли вони неактивні.",
|
||||
"label": "Приховувати неактивні стани"
|
||||
},
|
||||
"iconSpacing": {
|
||||
"desc": "Встановити відстань між значками.",
|
||||
"label": "Інтервал між значками"
|
||||
},
|
||||
"removeMargins": {
|
||||
"desc": "Видаляє всі зовнішні відступи віджета.",
|
||||
"label": "Прибрати відступи"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"cam-on": "Камера: {apps}",
|
||||
"mic-on": "Мікрофон: {apps}",
|
||||
"screen-on": "Демонстрація екрана: {apps}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"settings": {
|
||||
"hideInactive": {
|
||||
"desc": "在麦克风、摄像头和屏幕图标处于非活动状态时将其隐藏。",
|
||||
"label": "隐藏非活动状态"
|
||||
},
|
||||
"iconSpacing": {
|
||||
"desc": "设置图标之间的间距。",
|
||||
"label": "图标间距"
|
||||
},
|
||||
"removeMargins": {
|
||||
"desc": "移除小部件所有外部边距。",
|
||||
"label": "移除边距"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"cam-on": "摄像头: {apps}",
|
||||
"mic-on": "麦克风: {apps}",
|
||||
"screen-on": "屏幕共享: {apps}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"id": "privacy-indicator",
|
||||
"name": "Privacy Indicator",
|
||||
"version": "1.0.10",
|
||||
"minNoctaliaVersion": "3.6.0",
|
||||
"author": "Noctalia Team <team@noctalia.dev>",
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/noctalia-dev/noctalia-plugins",
|
||||
"description": "A privacy indicator widget that shows when microphone, camera or screen sharing is active.",
|
||||
"entryPoints": {
|
||||
"barWidget": "BarWidget.qml",
|
||||
"settings": "Settings.qml"
|
||||
},
|
||||
"dependencies": {
|
||||
"plugins": []
|
||||
},
|
||||
"metadata": {
|
||||
"defaultSettings": {
|
||||
"hideInactive": false,
|
||||
"removeMargins": false
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"hideInactive": true,
|
||||
"iconSpacing": 4,
|
||||
"removeMargins": false
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Commons
|
||||
import qs.Widgets
|
||||
import qs.Services.UI
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property var pluginApi: null
|
||||
property ShellScreen screen
|
||||
property string widgetId: ""
|
||||
property string section: ""
|
||||
property bool hovered: false
|
||||
|
||||
readonly property string barPosition: Settings.data.bar.position
|
||||
readonly property bool isVertical: barPosition === "left" || barPosition === "right"
|
||||
|
||||
implicitWidth: isVertical ? Style.capsuleHeight : layout.implicitWidth + Style.marginS * 2
|
||||
implicitHeight: isVertical ? layout.implicitHeight + Style.marginS * 2 : Style.capsuleHeight
|
||||
|
||||
color: root.hovered ? Color.mHover : Style.capsuleColor
|
||||
radius: Style.radiusM
|
||||
border.color: Style.capsuleBorderColor
|
||||
border.width: Style.capsuleBorderWidth
|
||||
|
||||
property string currentIconName: pluginApi?.pluginSettings?.currentIconName || pluginApi?.manifest?.metadata?.defaultSettings?.currentIconName
|
||||
property bool hideOnZero: pluginApi?.pluginSettings.hideOnZero || pluginApi?.manifest?.metadata.defaultSettings?.hideOnZero
|
||||
readonly property bool isVisible: (root.pluginApi?.mainInstance?.updateCount > 0) || !root.hideOnZero
|
||||
visible: root.isVisible
|
||||
// also set opacity to zero when invisible as we use opacity to hide the barWidgetLoader
|
||||
opacity: root.isVisible ? 1.0 : 0.0
|
||||
|
||||
|
||||
//
|
||||
// ------ Widget ------
|
||||
//
|
||||
Item {
|
||||
id: layout
|
||||
anchors.centerIn: parent
|
||||
|
||||
implicitWidth: grid.implicitWidth
|
||||
implicitHeight: grid.implicitHeight
|
||||
|
||||
GridLayout {
|
||||
id: grid
|
||||
columns: root.isVertical ? 1 : 2
|
||||
rowSpacing: Style.marginS
|
||||
columnSpacing: Style.marginS
|
||||
|
||||
NIcon {
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
||||
icon: root.currentIconName
|
||||
color: root.hovered ? Color.mOnHover : Color.mOnSurface
|
||||
}
|
||||
|
||||
NText {
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
||||
text: root.pluginApi?.mainInstance?.updateCount.toString()
|
||||
color: root.hovered ? Color.mOnHover : Color.mOnSurface
|
||||
pointSize: Style.fontSizeS
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: root.pluginApi?.mainInstance?.updateCount > 0 ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
|
||||
onClicked: {
|
||||
root.pluginApi?.mainInstance?.startDoSystemUpdate();
|
||||
}
|
||||
|
||||
|
||||
onEntered: {
|
||||
root.hovered = true;
|
||||
buildTooltip();
|
||||
}
|
||||
|
||||
onExited: {
|
||||
root.hovered = false;
|
||||
TooltipService.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function buildTooltip() {
|
||||
const updateCount = root.pluginApi?.mainInstance?.updateCount
|
||||
|
||||
if (updateCount === 0) {
|
||||
TooltipService.show(root, pluginApi?.tr("tooltip.noUpdatesAvailable"), BarService.getTooltipDirection());
|
||||
} else {
|
||||
TooltipService.show(root, pluginApi?.tr("tooltip.updatesAvailable"), BarService.getTooltipDirection());
|
||||
}
|
||||
}
|
||||
}
|
||||
126
home/aiden/.config/noctalia/plugins/update-count/Main.qml
Normal file
126
home/aiden/.config/noctalia/plugins/update-count/Main.qml
Normal file
@@ -0,0 +1,126 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Commons
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property var pluginApi: null
|
||||
|
||||
readonly property url updaterJson: Qt.resolvedUrl("file://" + Settings.configDir + "/plugins/update-count/updaterConfigs.json")
|
||||
readonly property int minutesToMillis: 60_000
|
||||
|
||||
readonly property int updateIntervalMinutes: pluginApi?.pluginSettings.updateIntervalMinutes || pluginApi?.manifest?.metadata.defaultSettings?.updateIntervalMinutes || 30
|
||||
readonly property string updateTerminalCommand: pluginApi?.pluginSettings.updateTerminalCommand || pluginApi?.manifest?.metadata.defaultSettings?.updateTerminalCommand || ""
|
||||
|
||||
property int updateCount: 0
|
||||
property var updater: null
|
||||
property var customUpdater: ({
|
||||
name: "custom",
|
||||
cmdGetNumUpdates: pluginApi?.pluginSettings.customCmdGetNumUpdates || "",
|
||||
cmdDoSystemUpdate: pluginApi?.pluginSettings.customCmdDoSystemUpdate || ""
|
||||
})
|
||||
|
||||
//
|
||||
// ------ Initialization ------
|
||||
//
|
||||
property var updaters: []
|
||||
property int checkIndex: 0
|
||||
property var current: null
|
||||
|
||||
FileView {
|
||||
id: updaterFile
|
||||
path: root.updaterJson
|
||||
|
||||
onLoaded: {
|
||||
try {
|
||||
root.updaters = JSON.parse(updaterFile.text());
|
||||
root.runAllCmdChecks();
|
||||
} catch (e) {
|
||||
Logger.e("UpdateCount", "JSON Error in", root.updaterJson, ":", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function runAllCmdChecks() {
|
||||
if (!root.updaters || root.updaters.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
root.checkIndex = 0;
|
||||
root.checkNext();
|
||||
}
|
||||
|
||||
function checkNext() {
|
||||
if (root.checkIndex >= root.updaters.length) {
|
||||
startGetNumUpdates();
|
||||
return;
|
||||
}
|
||||
|
||||
root.current = root.updaters[root.checkIndex++];
|
||||
cmdCheckProc.command = ["sh", "-c", root.current.cmdCheck];
|
||||
cmdCheckProc.running = true;
|
||||
}
|
||||
|
||||
Process {
|
||||
id: cmdCheckProc
|
||||
|
||||
onExited: function (exitCode, exitStatus) {
|
||||
if (exitCode === 0) {
|
||||
root.updater = root.current
|
||||
Logger.i("UpdateCount", `Initialization finished. Detected updater: ${root.updater.name}.`);
|
||||
root.startGetNumUpdates()
|
||||
} else {
|
||||
root.checkNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// ------ Get number of updates ------
|
||||
//
|
||||
Timer {
|
||||
id: timerGetNumUpdates
|
||||
|
||||
interval: root.updateIntervalMinutes * root.minutesToMillis
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: root.startGetNumUpdates()
|
||||
}
|
||||
|
||||
function startGetNumUpdates() {
|
||||
const cmd = root.customUpdater.cmdGetNumUpdates || root.updater.cmdGetNumUpdates || "exit 1"
|
||||
getNumUpdates.command = ["sh", "-c", cmd]
|
||||
getNumUpdates.running = true;
|
||||
}
|
||||
|
||||
Process {
|
||||
id: getNumUpdates
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
var count = parseInt(text.trim());
|
||||
root.updateCount = isNaN(count) ? -1 : count;
|
||||
if (root.updateCount >= 0) {
|
||||
Logger.i("UpdateCount", `Updates available: ${root.updateCount}`);
|
||||
} else {
|
||||
Logger.e("UpdateCount", `getNumUpdates return '${text.trim()}' cannot be parsed into int`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// ------ Start update ------
|
||||
//
|
||||
function startDoSystemUpdate() {
|
||||
const cmd = root.customUpdater.cmdDoSystemUpdate || root.updater.cmdDoSystemUpdate || "echo 'No update cmd found.'"
|
||||
const term = root.updateTerminalCommand.trim();
|
||||
|
||||
const fullCmd = (term.indexOf("{}") !== -1) ? term.replace("{}", cmd) : term + " " + cmd;
|
||||
|
||||
Quickshell.execDetached(["sh", "-c", fullCmd]);
|
||||
Logger.i("UpdateCount", `Executed update command: ${fullCmd}`);
|
||||
}
|
||||
}
|
||||
52
home/aiden/.config/noctalia/plugins/update-count/README.md
Normal file
52
home/aiden/.config/noctalia/plugins/update-count/README.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# Update Count Plugin
|
||||
|
||||
A compact Noctalia bar widget that periodically checks for available system updates and displays the current update count. Clicking the widget spawns a terminal to execute the configured system update command.
|
||||
|
||||
## Features
|
||||
|
||||
- **Periodic Update Checks**: Polls at a configurable interval and updates the displayed count.
|
||||
- **Package Manager Detection**: Supports common update-check/update flows for supported distros (see Requirements).
|
||||
- **Click to Update**: Launches a terminal to execute the configured system update command.
|
||||
- **Custom Commands**: Optional custom commands for both “get number of updates” and “do system update”.
|
||||
|
||||
## Installation
|
||||
|
||||
This plugin is part of the `noctalia-plugins` repository.
|
||||
|
||||
## Configuration
|
||||
|
||||
Configure the plugin in Noctalia settings:
|
||||
|
||||
- **Hide on Zero Updates**: Hides the widget when the available update count is `0`.
|
||||
- **Update Check Interval**: Polling interval used for update checks.
|
||||
- **Icon Identifier / Select Icon**: View and change the currently used icon name.
|
||||
- **Custom Update Count Command**: Shell command that must output a single integer.
|
||||
- **Custom System Update Command**: Shell command used to perform the update.
|
||||
- **Terminal Emulator**: Command used to spawn a terminal for the update action.
|
||||
- If the value contains `{}`, it will be replaced with the update command.
|
||||
- If `{}` is not present, the update command is appended.
|
||||
|
||||
## Usage
|
||||
|
||||
- **Display**: Shows an icon and the current update count.
|
||||
- **Click**: Spawns the configured terminal command and executes the system update command.
|
||||
- **Hover**: Shows a tooltip indicating whether updates are available or not.
|
||||
|
||||
## Requirements
|
||||
|
||||
- **Noctalia Shell**: 3.6.0 or later.
|
||||
- **Update backend**: one of the supported package managers defined in `updaterConfigs.json` (recommended, but not required).
|
||||
|
||||
## Technical Details
|
||||
|
||||
- **Updater selection**:
|
||||
- Built-in update handling is driven by `updaterConfigs.json`, which defines the commands used to:
|
||||
- determine the number of available updates (`cmdGetNumUpdates`), and
|
||||
- perform the system update (`cmdDoSystemUpdate`).
|
||||
- At runtime, the plugin selects the **first available** updater whose required executable checks succeed.
|
||||
- If no updater matches, the plugin relies on the **custom command** settings.
|
||||
|
||||
- **Supported package managers / tools**:
|
||||
- Arch Linux: `pacman`; `yay`, `paru` (AUR helpers)
|
||||
- Fedora: `dnf`
|
||||
- Void Linux: `xbps`
|
||||
193
home/aiden/.config/noctalia/plugins/update-count/Settings.qml
Normal file
193
home/aiden/.config/noctalia/plugins/update-count/Settings.qml
Normal file
@@ -0,0 +1,193 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Commons
|
||||
import qs.Widgets
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
property var pluginApi: null
|
||||
|
||||
property int updateIntervalMinutes: pluginApi?.pluginSettings?.updateIntervalMinutes || pluginApi?.manifest?.metadata?.defaultSettings?.updateIntervalMinutes
|
||||
property string updateTerminalCommand: pluginApi?.pluginSettings?.updateTerminalCommand || pluginApi?.manifest?.metadata.defaultSettings?.updateTerminalCommand
|
||||
property string currentIconName: pluginApi?.pluginSettings?.currentIconName || pluginApi?.manifest?.metadata?.defaultSettings?.currentIconName
|
||||
property bool hideOnZero: pluginApi?.pluginSettings?.hideOnZero || pluginApi?.manifest?.metadata?.defaultSettings?.hideOnZero
|
||||
|
||||
property string customCmdGetNumUpdates: pluginApi?.pluginSettings.customCmdGetNumUpdates || ""
|
||||
property string customCmdDoSystemUpdate: pluginApi?.pluginSettings.customCmdDoSystemUpdate || ""
|
||||
|
||||
spacing: Style.marginL
|
||||
|
||||
Component.onCompleted: {
|
||||
Logger.i("UpdateCount", "Settings UI loaded");
|
||||
}
|
||||
|
||||
//
|
||||
// ------ General ------
|
||||
//
|
||||
NToggle {
|
||||
id: widgetSwitch
|
||||
label: pluginApi?.tr("settings.hideWidget.label")
|
||||
description: pluginApi?.tr("settings.hideWidget.desc")
|
||||
checked: root.hideOnZero
|
||||
onToggled: function (checked) {
|
||||
root.hideOnZero = checked;
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: Style.marginL
|
||||
|
||||
NLabel {
|
||||
label: pluginApi?.tr("settings.currentIconName.label")
|
||||
description: pluginApi?.tr("settings.currentIconName.desc")
|
||||
}
|
||||
|
||||
NText {
|
||||
text: root.currentIconName
|
||||
color: Settings.data.colorSchemes.darkMode ? Color.mPrimary : Color.mOnPrimary
|
||||
}
|
||||
|
||||
NIcon {
|
||||
icon: root.currentIconName
|
||||
color: Settings.data.colorSchemes.darkMode ? Color.mPrimary : Color.mOnPrimary
|
||||
}
|
||||
|
||||
NButton {
|
||||
text: pluginApi?.tr("settings.changeIcon.label")
|
||||
onClicked: {
|
||||
Logger.i("UpdateCount", "Icon selector button clicked.");
|
||||
changeIcon.open();
|
||||
}
|
||||
}
|
||||
|
||||
NIconPicker {
|
||||
id: changeIcon
|
||||
onIconSelected: function (icon) {
|
||||
root.currentIconName = icon;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginL
|
||||
|
||||
NLabel {
|
||||
label: pluginApi?.tr("settings.updateInterval.label")
|
||||
description: pluginApi?.tr("settings.updateInterval.desc")
|
||||
}
|
||||
|
||||
NSlider {
|
||||
from: 5
|
||||
to: 300
|
||||
value: root.updateIntervalMinutes
|
||||
stepSize: 5
|
||||
onValueChanged: {
|
||||
root.updateIntervalMinutes = value;
|
||||
}
|
||||
}
|
||||
|
||||
NText {
|
||||
text: root.updateIntervalMinutes.toString().padStart(3, " ") + " minutes"
|
||||
color: Settings.data.colorSchemes.darkMode ? Color.mOnSurface : Color.mOnPrimary
|
||||
}
|
||||
}
|
||||
|
||||
NDivider {
|
||||
visible: true
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Style.marginL
|
||||
Layout.bottomMargin: Style.marginL
|
||||
}
|
||||
|
||||
//
|
||||
// ------ Custom commands ------
|
||||
//
|
||||
NTextInput {
|
||||
label: pluginApi?.tr("settings.customCmdGetNumUpdates.label")
|
||||
description: pluginApi?.tr("settings.customCmdGetNumUpdates.desc")
|
||||
placeholderText: pluginApi?.tr("settings.customCmdGetNumUpdates.placeholder")
|
||||
text: root.customCmdGetNumUpdates
|
||||
onTextChanged: root.customCmdGetNumUpdates = text
|
||||
}
|
||||
|
||||
NTextInput {
|
||||
label: pluginApi?.tr("settings.customCmdDoSystemUpdate.label")
|
||||
description: pluginApi?.tr("settings.customCmdDoSystemUpdate.desc")
|
||||
placeholderText: pluginApi?.tr("settings.customCmdDoSystemUpdate.placeholder")
|
||||
text: root.customCmdDoSystemUpdate
|
||||
onTextChanged: root.customCmdDoSystemUpdate = text
|
||||
}
|
||||
|
||||
NTextInput {
|
||||
Layout.fillWidth: true
|
||||
label: pluginApi?.tr("settings.terminal.label")
|
||||
description: pluginApi?.tr("settings.terminal.desc")
|
||||
placeholderText: pluginApi?.tr("settings.terminal.placeholder")
|
||||
text: root.updateTerminalCommand
|
||||
onTextChanged: root.updateTerminalCommand = text
|
||||
}
|
||||
|
||||
NDivider {
|
||||
visible: true
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Style.marginL
|
||||
Layout.bottomMargin: Style.marginL
|
||||
}
|
||||
|
||||
//
|
||||
// ------ Information ------
|
||||
//
|
||||
NLabel {
|
||||
label: pluginApi?.tr("settings.currentCommands.label")
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
RowLayout {
|
||||
NText {
|
||||
Layout.fillWidth: true
|
||||
text: pluginApi?.tr("settings.currentNumUpdatesCmd.label")
|
||||
color: Settings.data.colorSchemes.darkMode ? Color.mSecondary : Color.mOnSecondary
|
||||
}
|
||||
NText {
|
||||
text: root.customCmdGetNumUpdates || pluginApi?.mainInstance?.updater.cmdGetNumUpdates || "NA"
|
||||
color: Settings.data.colorSchemes.darkMode ? Color.mTertiary : Color.mOnTertiary
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
NText {
|
||||
Layout.fillWidth: true
|
||||
text: pluginApi?.tr("settings.currentUpdateCmd.label")
|
||||
color: Settings.data.colorSchemes.darkMode ? Color.mSecondary : Color.mOnSecondary
|
||||
}
|
||||
NText {
|
||||
text: root.customCmdDoSystemUpdate || pluginApi?.mainInstance?.updater.cmdDoSystemUpdate || "NA"
|
||||
color: Settings.data.colorSchemes.darkMode ? Color.mTertiary : Color.mOnTertiary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function saveSettings() {
|
||||
if (!pluginApi) {
|
||||
Logger.e("UpdateCount", "Cannot save settings: pluginApi is null");
|
||||
return;
|
||||
}
|
||||
|
||||
pluginApi.pluginSettings.updateIntervalMinutes = root.updateIntervalMinutes;
|
||||
pluginApi.pluginSettings.updateTerminalCommand = root.updateTerminalCommand || pluginApi?.manifest?.metadata.defaultSettings?.updateTerminalCommand;
|
||||
pluginApi.pluginSettings.currentIconName = root.currentIconName;
|
||||
pluginApi.pluginSettings.hideOnZero = root.hideOnZero;
|
||||
|
||||
pluginApi.pluginSettings.customCmdGetNumUpdates = root.customCmdGetNumUpdates;
|
||||
pluginApi.pluginSettings.customCmdDoSystemUpdate = root.customCmdDoSystemUpdate;
|
||||
|
||||
pluginApi.saveSettings();
|
||||
pluginApi?.mainInstance?.startGetNumUpdates();
|
||||
|
||||
Logger.i("UpdateCount", "Settings saved successfully");
|
||||
pluginApi.closePanel(root.screen);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"settings": {
|
||||
"changeIcon": {
|
||||
"label": "Icon auswählen"
|
||||
},
|
||||
"currentCommands": {
|
||||
"label": "Aktuell konfigurierte Befehle"
|
||||
},
|
||||
"currentIconName": {
|
||||
"desc": "Der aktuell konfigurierte Icon-Name.",
|
||||
"label": "Icon-Kennung"
|
||||
},
|
||||
"currentNumUpdatesCmd": {
|
||||
"label": "Update-Anzahl"
|
||||
},
|
||||
"currentUpdateCmd": {
|
||||
"label": "System-Update"
|
||||
},
|
||||
"customCmdDoSystemUpdate": {
|
||||
"desc": "Shell-Befehl zum Ausführen des System-Updates.",
|
||||
"label": "Benutzerdefinierter System-Update-Befehl",
|
||||
"placeholder": "z. B. yay -Syu"
|
||||
},
|
||||
"customCmdGetNumUpdates": {
|
||||
"desc": "Shell-Befehl, der eine einzelne Ganzzahl als Anzahl verfügbarer Updates ausgeben muss.",
|
||||
"label": "Benutzerdefinierter Befehl für Update-Anzahl",
|
||||
"placeholder": "z. B. yay -Quq 2>/dev/null | wc -l"
|
||||
},
|
||||
"hideWidget": {
|
||||
"desc": "Blendet das Widget aus, wenn die Anzahl verfügbarer Updates 0 ist.",
|
||||
"label": "Bei 0 Updates ausblenden"
|
||||
},
|
||||
"terminal": {
|
||||
"desc": "Terminalbefehl zum Ausführen des System-Update-Befehls. Optional: {} für den Update-Befehl.",
|
||||
"label": "Terminal-Emulator",
|
||||
"placeholder": "z. B. foot -e, hyprctl dispatch exec '[float] kitty -e {}'"
|
||||
},
|
||||
"updateInterval": {
|
||||
"desc": "Abfrageintervall für Update-Prüfungen",
|
||||
"label": "Intervall für Update-Prüfung"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"noUpdatesAvailable": "Keine Updates gefunden",
|
||||
"updatesAvailable": "Klicken, um den konfigurierten System-Update-Befehl auszuführen"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"settings": {
|
||||
"changeIcon": {
|
||||
"label": "Select Icon"
|
||||
},
|
||||
"currentCommands": {
|
||||
"label": "Currently configured commands"
|
||||
},
|
||||
"currentIconName": {
|
||||
"desc": "Currently configured icon name.",
|
||||
"label": "Icon Identifier"
|
||||
},
|
||||
"currentNumUpdatesCmd": {
|
||||
"label": "Update count"
|
||||
},
|
||||
"currentUpdateCmd": {
|
||||
"label": "System update"
|
||||
},
|
||||
"customCmdDoSystemUpdate": {
|
||||
"desc": "Shell command used to perform the system update.",
|
||||
"label": "Custom System Update Command",
|
||||
"placeholder": "e.g., yay -Syu"
|
||||
},
|
||||
"customCmdGetNumUpdates": {
|
||||
"desc": "Shell command that must output a single integer representing the number of available updates.",
|
||||
"label": "Custom Update Count Command",
|
||||
"placeholder": "e.g., yay -Quq 2>/dev/null | wc -l"
|
||||
},
|
||||
"hideWidget": {
|
||||
"desc": "Hide the widget when the available update count is 0.",
|
||||
"label": "Hide on Zero Updates"
|
||||
},
|
||||
"terminal": {
|
||||
"desc": "Terminal command used to execute the system update command. Optional: {} for update command.",
|
||||
"label": "Terminal Emulator",
|
||||
"placeholder": "e.g., foot -e, hyprctl dispatch exec '[float] kitty -e {}'"
|
||||
},
|
||||
"updateInterval": {
|
||||
"desc": "Polling interval for update checks",
|
||||
"label": "Update Check Interval"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"noUpdatesAvailable": "No updates detected",
|
||||
"updatesAvailable": "Click to run the configured system update command"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"settings": {
|
||||
"changeIcon": {
|
||||
"label": "Seleccionar icono"
|
||||
},
|
||||
"currentCommands": {
|
||||
"label": "Comandos configurados actualmente"
|
||||
},
|
||||
"currentIconName": {
|
||||
"desc": "Nombre de icono configurado actualmente.",
|
||||
"label": "Identificador de icono"
|
||||
},
|
||||
"currentNumUpdatesCmd": {
|
||||
"label": "Recuento de actualizaciones"
|
||||
},
|
||||
"currentUpdateCmd": {
|
||||
"label": "Actualización del sistema"
|
||||
},
|
||||
"customCmdDoSystemUpdate": {
|
||||
"desc": "Comando de shell para ejecutar la actualización del sistema.",
|
||||
"label": "Comando personalizado de actualización",
|
||||
"placeholder": "p. ej., yay -Syu"
|
||||
},
|
||||
"customCmdGetNumUpdates": {
|
||||
"desc": "Comando de shell que debe imprimir un único entero con el número de actualizaciones disponibles.",
|
||||
"label": "Comando personalizado de recuento",
|
||||
"placeholder": "p. ej., yay -Quq 2>/dev/null | wc -l"
|
||||
},
|
||||
"hideWidget": {
|
||||
"desc": "Oculta el widget cuando el número de actualizaciones disponibles es 0.",
|
||||
"label": "Ocultar con 0 actualizaciones"
|
||||
},
|
||||
"terminal": {
|
||||
"desc": "Comando del terminal usado para ejecutar el comando de actualización del sistema. Opcional: {} para el comando de actualización.",
|
||||
"label": "Emulador de terminal",
|
||||
"placeholder": "p. ej., foot -e, hyprctl dispatch exec '[float] kitty -e {}'"
|
||||
},
|
||||
"updateInterval": {
|
||||
"desc": "Intervalo de sondeo para las comprobaciones de actualizaciones",
|
||||
"label": "Intervalo de comprobación"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"noUpdatesAvailable": "No se detectaron actualizaciones",
|
||||
"updatesAvailable": "Haz clic para ejecutar el comando de actualización del sistema configurado"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"settings": {
|
||||
"changeIcon": {
|
||||
"label": "Choisir l’icône"
|
||||
},
|
||||
"currentCommands": {
|
||||
"label": "Commandes actuellement configurées"
|
||||
},
|
||||
"currentIconName": {
|
||||
"desc": "Nom d’icône actuellement configuré.",
|
||||
"label": "Identifiant d’icône"
|
||||
},
|
||||
"currentNumUpdatesCmd": {
|
||||
"label": "Nombre de mises à jour"
|
||||
},
|
||||
"currentUpdateCmd": {
|
||||
"label": "Mise à jour système"
|
||||
},
|
||||
"customCmdDoSystemUpdate": {
|
||||
"desc": "Commande shell utilisée pour effectuer la mise à jour du système.",
|
||||
"label": "Commande personnalisée de mise à jour",
|
||||
"placeholder": "ex. yay -Syu"
|
||||
},
|
||||
"customCmdGetNumUpdates": {
|
||||
"desc": "Commande shell devant afficher un seul entier correspondant au nombre de mises à jour disponibles.",
|
||||
"label": "Commande personnalisée de comptage",
|
||||
"placeholder": "ex. yay -Quq 2>/dev/null | wc -l"
|
||||
},
|
||||
"hideWidget": {
|
||||
"desc": "Masque le widget lorsque le nombre de mises à jour disponibles est 0.",
|
||||
"label": "Masquer si 0 mise à jour"
|
||||
},
|
||||
"terminal": {
|
||||
"desc": "Commande du terminal utilisée pour exécuter la commande de mise à jour du système. Optionnel : {} pour la commande de mise à jour.",
|
||||
"label": "Émulateur de terminal",
|
||||
"placeholder": "ex. foot -e, hyprctl dispatch exec '[float] kitty -e {}'"
|
||||
},
|
||||
"updateInterval": {
|
||||
"desc": "Intervalle de sondage pour les vérifications de mises à jour",
|
||||
"label": "Intervalle de vérification"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"noUpdatesAvailable": "Aucune mise à jour détectée",
|
||||
"updatesAvailable": "Cliquer pour exécuter la commande de mise à jour système configurée"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"settings": {
|
||||
"changeIcon": {
|
||||
"label": "Seleziona icona"
|
||||
},
|
||||
"currentCommands": {
|
||||
"label": "Comandi attualmente configurati"
|
||||
},
|
||||
"currentIconName": {
|
||||
"desc": "Nome icona attualmente configurato.",
|
||||
"label": "Identificatore icona"
|
||||
},
|
||||
"currentNumUpdatesCmd": {
|
||||
"label": "Conteggio aggiornamenti"
|
||||
},
|
||||
"currentUpdateCmd": {
|
||||
"label": "Aggiornamento di sistema"
|
||||
},
|
||||
"customCmdDoSystemUpdate": {
|
||||
"desc": "Comando shell usato per effettuare l’aggiornamento di sistema.",
|
||||
"label": "Comando personalizzato di aggiornamento",
|
||||
"placeholder": "es., yay -Syu"
|
||||
},
|
||||
"customCmdGetNumUpdates": {
|
||||
"desc": "Comando shell che deve stampare un singolo intero che rappresenta il numero di aggiornamenti disponibili.",
|
||||
"label": "Comando personalizzato per conteggio",
|
||||
"placeholder": "es., yay -Quq 2>/dev/null | wc -l"
|
||||
},
|
||||
"hideWidget": {
|
||||
"desc": "Nasconde il widget quando il numero di aggiornamenti disponibili è 0.",
|
||||
"label": "Nascondi con 0 aggiornamenti"
|
||||
},
|
||||
"terminal": {
|
||||
"desc": "Comando del terminale usato per eseguire il comando di aggiornamento di sistema. Opzionale: {} per il comando di aggiornamento.",
|
||||
"label": "Emulatore di terminale",
|
||||
"placeholder": "es., foot -e, hyprctl dispatch exec '[float] kitty -e {}'"
|
||||
},
|
||||
"updateInterval": {
|
||||
"desc": "Intervallo di polling per i controlli aggiornamenti",
|
||||
"label": "Intervallo di verifica"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"noUpdatesAvailable": "Nessun aggiornamento rilevato",
|
||||
"updatesAvailable": "Clicca per eseguire il comando di aggiornamento di sistema configurato"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"settings": {
|
||||
"changeIcon": {
|
||||
"label": "アイコンを選択"
|
||||
},
|
||||
"currentCommands": {
|
||||
"label": "現在の設定コマンド"
|
||||
},
|
||||
"currentIconName": {
|
||||
"desc": "現在設定されているアイコン名です。",
|
||||
"label": "アイコン識別子"
|
||||
},
|
||||
"currentNumUpdatesCmd": {
|
||||
"label": "更新件数"
|
||||
},
|
||||
"currentUpdateCmd": {
|
||||
"label": "システム更新"
|
||||
},
|
||||
"customCmdDoSystemUpdate": {
|
||||
"desc": "システム更新を実行するためのシェルコマンドです。",
|
||||
"label": "システム更新のカスタムコマンド",
|
||||
"placeholder": "例: yay -Syu"
|
||||
},
|
||||
"customCmdGetNumUpdates": {
|
||||
"desc": "利用可能な更新数を表す整数を 1 つ出力する必要があります。",
|
||||
"label": "更新件数のカスタムコマンド",
|
||||
"placeholder": "例: yay -Quq 2>/dev/null | wc -l"
|
||||
},
|
||||
"hideWidget": {
|
||||
"desc": "利用可能な更新数が 0 の場合にウィジェットを非表示にします。",
|
||||
"label": "更新 0 件で非表示"
|
||||
},
|
||||
"terminal": {
|
||||
"desc": "システム更新コマンドを実行するためのターミナルコマンド。任意: 更新コマンド用に {} を使用します。",
|
||||
"label": "ターミナルエミュレーター",
|
||||
"placeholder": "例: foot -e, hyprctl dispatch exec '[float] kitty -e {}'"
|
||||
},
|
||||
"updateInterval": {
|
||||
"desc": "更新チェックのポーリング間隔",
|
||||
"label": "更新チェック間隔"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"noUpdatesAvailable": "更新は検出されませんでした",
|
||||
"updatesAvailable": "クリックして設定済みのシステム更新コマンドを実行"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"settings": {
|
||||
"changeIcon": {
|
||||
"label": "Pictogram kiezen"
|
||||
},
|
||||
"currentCommands": {
|
||||
"label": "Huidig geconfigureerde commando’s"
|
||||
},
|
||||
"currentIconName": {
|
||||
"desc": "Huidig geconfigureerde pictogramnaam.",
|
||||
"label": "Pictogram-ID"
|
||||
},
|
||||
"currentNumUpdatesCmd": {
|
||||
"label": "Update-aantal"
|
||||
},
|
||||
"currentUpdateCmd": {
|
||||
"label": "Systeemupdate"
|
||||
},
|
||||
"customCmdDoSystemUpdate": {
|
||||
"desc": "Shell-commando om de systeemupdate uit te voeren.",
|
||||
"label": "Aangepast systeemupdatecommando",
|
||||
"placeholder": "bijv. yay -Syu"
|
||||
},
|
||||
"customCmdGetNumUpdates": {
|
||||
"desc": "Shell-commando dat één geheel getal moet uitvoereren met het aantal beschikbare updates.",
|
||||
"label": "Aangepast commando voor update-aantal",
|
||||
"placeholder": "bijv. yay -Quq 2>/dev/null | wc -l"
|
||||
},
|
||||
"hideWidget": {
|
||||
"desc": "Verbergt de widget wanneer het aantal beschikbare updates 0 is.",
|
||||
"label": "Verbergen bij 0 updates"
|
||||
},
|
||||
"terminal": {
|
||||
"desc": "Terminalcommando om het systeemupdatecommando uit te voeren. Optioneel: {} voor het updatecommando.",
|
||||
"label": "Terminalemulator",
|
||||
"placeholder": "bijv. foot -e, hyprctl dispatch exec '[float] kitty -e {}'"
|
||||
},
|
||||
"updateInterval": {
|
||||
"desc": "Poll-interval voor updatecontroles",
|
||||
"label": "Controle-interval"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"noUpdatesAvailable": "Geen updates gevonden",
|
||||
"updatesAvailable": "Klik om het geconfigureerde systeemupdatecommando uit te voeren"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"settings": {
|
||||
"changeIcon": {
|
||||
"label": "Selecionar ícone"
|
||||
},
|
||||
"currentCommands": {
|
||||
"label": "Comandos atualmente configurados"
|
||||
},
|
||||
"currentIconName": {
|
||||
"desc": "Nome do ícone atualmente configurado.",
|
||||
"label": "Identificador do ícone"
|
||||
},
|
||||
"currentNumUpdatesCmd": {
|
||||
"label": "Contagem de atualizações"
|
||||
},
|
||||
"currentUpdateCmd": {
|
||||
"label": "Atualização do sistema"
|
||||
},
|
||||
"customCmdDoSystemUpdate": {
|
||||
"desc": "Comando de shell usado para efetuar a atualização do sistema.",
|
||||
"label": "Comando personalizado de atualização do sistema",
|
||||
"placeholder": "ex.: yay -Syu"
|
||||
},
|
||||
"customCmdGetNumUpdates": {
|
||||
"desc": "Comando de shell que deve imprimir um único inteiro representando o número de atualizações disponíveis.",
|
||||
"label": "Comando personalizado para contagem de atualizações",
|
||||
"placeholder": "ex.: yay -Quq 2>/dev/null | wc -l"
|
||||
},
|
||||
"hideWidget": {
|
||||
"desc": "Oculta o widget quando o número de atualizações disponíveis é 0.",
|
||||
"label": "Ocultar com 0 atualizações"
|
||||
},
|
||||
"terminal": {
|
||||
"desc": "Comando de terminal usado para executar o comando de atualização do sistema. Opcional: {} para o comando de atualização.",
|
||||
"label": "Emulador de terminal",
|
||||
"placeholder": "ex.: foot -e, hyprctl dispatch exec '[float] kitty -e {}'"
|
||||
},
|
||||
"updateInterval": {
|
||||
"desc": "Intervalo de polling para verificações de atualizações",
|
||||
"label": "Intervalo de verificação de atualizações"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"noUpdatesAvailable": "Nenhuma atualização detetada",
|
||||
"updatesAvailable": "Clique para executar o comando de atualização do sistema configurado"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"settings": {
|
||||
"changeIcon": {
|
||||
"label": "Выбрать значок"
|
||||
},
|
||||
"currentCommands": {
|
||||
"label": "Текущие настроенные команды"
|
||||
},
|
||||
"currentIconName": {
|
||||
"desc": "Текущее настроенное имя значка.",
|
||||
"label": "Идентификатор значка"
|
||||
},
|
||||
"currentNumUpdatesCmd": {
|
||||
"label": "Количество обновлений"
|
||||
},
|
||||
"currentUpdateCmd": {
|
||||
"label": "Обновление системы"
|
||||
},
|
||||
"customCmdDoSystemUpdate": {
|
||||
"desc": "Команда оболочки для выполнения обновления системы.",
|
||||
"label": "Пользовательская команда обновления",
|
||||
"placeholder": "например: yay -Syu"
|
||||
},
|
||||
"customCmdGetNumUpdates": {
|
||||
"desc": "Команда оболочки должна вывести одно целое число — количество доступных обновлений.",
|
||||
"label": "Пользовательская команда подсчёта",
|
||||
"placeholder": "например: yay -Quq 2>/dev/null | wc -l"
|
||||
},
|
||||
"hideWidget": {
|
||||
"desc": "Скрывает виджет, когда количество доступных обновлений равно 0.",
|
||||
"label": "Скрывать при 0 обновлений"
|
||||
},
|
||||
"terminal": {
|
||||
"desc": "Команда терминала для выполнения команды обновления системы. Необязательно: {} для команды обновления.",
|
||||
"label": "Эмулятор терминала",
|
||||
"placeholder": "например: foot -e, hyprctl dispatch exec '[float] kitty -e {}'"
|
||||
},
|
||||
"updateInterval": {
|
||||
"desc": "Интервал опроса для проверки обновлений",
|
||||
"label": "Интервал проверки"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"noUpdatesAvailable": "Обновления не обнаружены",
|
||||
"updatesAvailable": "Нажмите, чтобы выполнить настроенную команду обновления системы"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"settings": {
|
||||
"changeIcon": {
|
||||
"label": "Simge seç"
|
||||
},
|
||||
"currentCommands": {
|
||||
"label": "Şu anda yapılandırılmış komutlar"
|
||||
},
|
||||
"currentIconName": {
|
||||
"desc": "Şu anda yapılandırılmış simge adı.",
|
||||
"label": "Simge tanımlayıcı"
|
||||
},
|
||||
"currentNumUpdatesCmd": {
|
||||
"label": "Güncelleme sayısı"
|
||||
},
|
||||
"currentUpdateCmd": {
|
||||
"label": "Sistem güncellemesi"
|
||||
},
|
||||
"customCmdDoSystemUpdate": {
|
||||
"desc": "Sistem güncellemesini gerçekleştirmek için kullanılan kabuk komutu.",
|
||||
"label": "Özel sistem güncelleme komutu",
|
||||
"placeholder": "örn., yay -Syu"
|
||||
},
|
||||
"customCmdGetNumUpdates": {
|
||||
"desc": "Mevcut güncellemelerin sayısını temsil eden tek bir tamsayı çıktılaması gereken kabuk komutu.",
|
||||
"label": "Özel güncelleme sayısı komutu",
|
||||
"placeholder": "örn., yay -Quq 2>/dev/null | wc -l"
|
||||
},
|
||||
"hideWidget": {
|
||||
"desc": "Mevcut güncelleme sayısı 0 olduğunda widget'ı gizler.",
|
||||
"label": "0 güncellemede gizle"
|
||||
},
|
||||
"terminal": {
|
||||
"desc": "Sistem güncelleme komutunu çalıştırmak için kullanılan terminal komutu. İsteğe bağlı: güncelleme komutu için {}.",
|
||||
"label": "Terminal emülatörü",
|
||||
"placeholder": "örn., foot -e, hyprctl dispatch exec '[float] kitty -e {}'"
|
||||
},
|
||||
"updateInterval": {
|
||||
"desc": "Güncelleme denetimleri için yoklama aralığı",
|
||||
"label": "Güncelleme denetim aralığı"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"noUpdatesAvailable": "Güncelleme algılanmadı",
|
||||
"updatesAvailable": "Yapılandırılmış sistem güncelleme komutunu çalıştırmak için tıklayın"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"settings": {
|
||||
"changeIcon": {
|
||||
"label": "Вибрати іконку"
|
||||
},
|
||||
"currentCommands": {
|
||||
"label": "Поточні налаштовані команди"
|
||||
},
|
||||
"currentIconName": {
|
||||
"desc": "Поточна налаштована назва іконки.",
|
||||
"label": "Ідентифікатор іконки"
|
||||
},
|
||||
"currentNumUpdatesCmd": {
|
||||
"label": "Кількість оновлень"
|
||||
},
|
||||
"currentUpdateCmd": {
|
||||
"label": "Оновлення системи"
|
||||
},
|
||||
"customCmdDoSystemUpdate": {
|
||||
"desc": "Команда оболонки для виконання оновлення системи.",
|
||||
"label": "Користувацька команда оновлення системи",
|
||||
"placeholder": "напр., yay -Syu"
|
||||
},
|
||||
"customCmdGetNumUpdates": {
|
||||
"desc": "Команда оболонки має вивести одне ціле число, що представляє кількість доступних оновлень.",
|
||||
"label": "Користувацька команда підрахунку оновлень",
|
||||
"placeholder": "напр., yay -Quq 2>/dev/null | wc -l"
|
||||
},
|
||||
"hideWidget": {
|
||||
"desc": "Приховує віджет, коли кількість доступних оновлень дорівнює 0.",
|
||||
"label": "Приховувати за 0 оновлень"
|
||||
},
|
||||
"terminal": {
|
||||
"desc": "Команда термінала для виконання команди оновлення системи. Необов’язково: {} для команди оновлення.",
|
||||
"label": "Емулятор термінала",
|
||||
"placeholder": "напр., foot -e, hyprctl dispatch exec '[float] kitty -e {}'"
|
||||
},
|
||||
"updateInterval": {
|
||||
"desc": "Інтервал опитування для перевірок оновлень",
|
||||
"label": "Інтервал перевірки оновлень"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"noUpdatesAvailable": "Оновлень не виявлено",
|
||||
"updatesAvailable": "Натисніть, щоб запустити налаштовану команду оновлення системи"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"settings": {
|
||||
"changeIcon": {
|
||||
"label": "选择图标"
|
||||
},
|
||||
"currentCommands": {
|
||||
"label": "当前配置的命令"
|
||||
},
|
||||
"currentIconName": {
|
||||
"desc": "当前配置的图标名称。",
|
||||
"label": "图标标识"
|
||||
},
|
||||
"currentNumUpdatesCmd": {
|
||||
"label": "更新数量"
|
||||
},
|
||||
"currentUpdateCmd": {
|
||||
"label": "系统更新"
|
||||
},
|
||||
"customCmdDoSystemUpdate": {
|
||||
"desc": "用于执行系统更新的 Shell 命令。",
|
||||
"label": "自定义系统更新命令",
|
||||
"placeholder": "例如:yay -Syu"
|
||||
},
|
||||
"customCmdGetNumUpdates": {
|
||||
"desc": "Shell 命令必须输出一个整数,表示可用更新的数量。",
|
||||
"label": "自定义更新数量命令",
|
||||
"placeholder": "例如:yay -Quq 2>/dev/null | wc -l"
|
||||
},
|
||||
"hideWidget": {
|
||||
"desc": "当可用更新数为 0 时隐藏该小部件。",
|
||||
"label": "零更新时隐藏"
|
||||
},
|
||||
"terminal": {
|
||||
"desc": "用于执行系统更新命令的终端命令。可选:使用 {} 代表更新命令占位符。",
|
||||
"label": "终端模拟器",
|
||||
"placeholder": "例如:foot -e,hyprctl dispatch exec '[float] kitty -e {}'"
|
||||
},
|
||||
"updateInterval": {
|
||||
"desc": "更新检查的轮询间隔",
|
||||
"label": "检查间隔"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"noUpdatesAvailable": "未检测到更新",
|
||||
"updatesAvailable": "点击运行已配置的系统更新命令"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"id": "update-count",
|
||||
"name": "Update Count",
|
||||
"version": "1.0.5",
|
||||
"minNoctaliaVersion": "3.6.0",
|
||||
"author": "BukoMoon",
|
||||
"license": "GPLv3",
|
||||
"repository": "https://github.com/noctalia-dev/noctalia-plugins",
|
||||
"description": "Checks for system updates and shows the update count. Click to run update command in a terminal.",
|
||||
"entryPoints": {
|
||||
"main": "Main.qml",
|
||||
"barWidget": "BarWidget.qml",
|
||||
"settings": "Settings.qml"
|
||||
},
|
||||
"dependencies": {
|
||||
"plugins": []
|
||||
},
|
||||
"metadata": {
|
||||
"defaultSettings": {
|
||||
"updateIntervalMinutes": 30,
|
||||
"updateTerminalCommand": "foot -e",
|
||||
"currentIconName": "world-download",
|
||||
"hideOnZero": false
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
home/aiden/.config/noctalia/plugins/update-count/preview.png
Normal file
BIN
home/aiden/.config/noctalia/plugins/update-count/preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 435 KiB |
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"updateIntervalMinutes": 30,
|
||||
"updateTerminalCommand": "alacritty -e",
|
||||
"currentIconName": "world-download",
|
||||
"hideOnZero": true,
|
||||
"customCmdGetNumUpdates": "expr $(xbps-install -Mnu 2>&1 | grep -v '^$' | wc -l) + $(flatpak remote-ls --updates | wc -l)",
|
||||
"customCmdDoSystemUpdate": "~/update.sh"
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
[
|
||||
{
|
||||
"name": "yay",
|
||||
"cmdCheck": "command -v yay >/dev/null 2>&1",
|
||||
"cmdGetNumUpdates": "yay -Sy >/dev/null 2>&1; yay -Quq 2>/dev/null | wc -l",
|
||||
"cmdDoSystemUpdate": "yay -Syu"
|
||||
},
|
||||
{
|
||||
"name": "paru",
|
||||
"cmdCheck": "command -v paru >/dev/null 2>&1",
|
||||
"cmdGetNumUpdates": "paru -Sy >/dev/null 2>&1; paru -Quq 2>/dev/null | wc -l",
|
||||
"cmdDoSystemUpdate": "paru -Syu"
|
||||
},
|
||||
{
|
||||
"name": "pacman",
|
||||
"cmdCheck": "command -v pacman >/dev/null 2>&1",
|
||||
"cmdGetNumUpdates": "pacman -Quq 2>/dev/null | wc -l",
|
||||
"cmdDoSystemUpdate": "sudo pacman -Syu"
|
||||
},
|
||||
{
|
||||
"name": "dnf",
|
||||
"cmdCheck": "command -v dnf >/dev/null 2>&1",
|
||||
"cmdGetNumUpdates": "dnf check-update -q | grep -c ^[a-z0-9]",
|
||||
"cmdDoSystemUpdate": "sudo dnf upgrade"
|
||||
},
|
||||
{
|
||||
"name": "xbps",
|
||||
"cmdCheck": "command -v xbps-install >/dev/null 2>&1",
|
||||
"cmdGetNumUpdates": "xbps-install -Mnu 2>&1 | grep -v '^$' | wc -l",
|
||||
"cmdDoSystemUpdate": "sudo xbps-install -Su"
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user