Toast: add media playback info option

This commit is contained in:
Ly-sec
2026-01-17 17:40:19 +01:00
parent 60792521e1
commit f989465ce9
20 changed files with 135 additions and 123 deletions
+5 -3
View File
@@ -427,7 +427,7 @@
"search": "Suche",
"security": "Sicherheit",
"select": "Auswählen",
"shortcuts": "Tastenkombinationen",
"shortcuts": "Kurzbefehle",
"shutdown": "Herunterfahren",
"signal": "Signal",
"sound": "Ton",
@@ -674,7 +674,7 @@
"volumes-mute-output-description": "Die Haupt-Audio-Ausgabe des Systems stummschalten.",
"volumes-mute-output-label": "Audio-Ausgabe stummschalten",
"volumes-output-volume-description": "Systemweite Lautstärke.",
"volumes-step-size-description": "Schrittgröße für Lautstärkeänderungen anpassen (Mausrad, Tastenkombinationen).",
"volumes-step-size-description": "Schrittgröße für Lautstärkeänderungen anpassen (Mausrad, Tastenkürzel).",
"volumes-step-size-label": "Lautstärke-Schrittgröße",
"volumes-volume-overdrive-description": "Erlaubt das Anheben der Lautstärke über 100%. Wird möglicherweise nicht von aller Hardware unterstützt.",
"volumes-volume-overdrive-label": "Lautstärke-Übersteuerung erlauben"
@@ -838,7 +838,7 @@
"weather-show-background-description": "Zeige den Hintergrundcontainer für das Wetter-Widget an."
},
"display": {
"monitors-brightness-step-description": "Schrittgröße für Helligkeitsänderungen anpassen (Mausrad und Tastenkombinationen).",
"monitors-brightness-step-description": "Schrittgröße für Helligkeitsänderungen anpassen (Mausrad und Tastenkürzel).",
"monitors-brightness-step-label": "Helligkeits-Schrittgröße",
"monitors-brightness-unavailable-ddc-disabled": "Helligkeitssteuerung nicht verfügbar. Aktivieren Sie \"Externe Helligkeitsunterstützung\", um die Helligkeit dieses Displays zu steuern.",
"monitors-brightness-unavailable-generic": "Die Helligkeitssteuerung ist für dieses Display nicht verfügbar.",
@@ -1088,6 +1088,8 @@
"history-low-urgency-label": "Niedrige Dringlichkeit im Verlauf speichern",
"history-normal-urgency-description": "Normale Prioritätsbenachrichtigungen im Verlauf speichern.",
"history-normal-urgency-label": "Normale Dringlichkeit im Verlauf speichern",
"media-toast-description": "Eine Toast-Benachrichtigung anzeigen, wenn sich der Wiedergabestatus von Medien ändert.",
"media-toast-label": "Medien",
"monitors-desc": "Benachrichtigungen auf bestimmten Monitoren anzeigen. Standardmäßig werden sie auf allen Monitoren angezeigt.",
"settings-always-on-top-description": "Benachrichtigungen über Vollbildfenstern und anderen Ebenen anzeigen.",
"settings-background-opacity-description": "Transparenz der Benachrichtigungshintergründe anpassen.",
+2
View File
@@ -1088,6 +1088,8 @@
"history-low-urgency-label": "Save low urgency to history",
"history-normal-urgency-description": "Save normal priority notifications to history.",
"history-normal-urgency-label": "Save normal urgency to history",
"media-toast-description": "Show a toast when media playback state changes.",
"media-toast-label": "Media",
"monitors-desc": "Show notification on specific monitors. Defaults to all if none are chosen.",
"settings-always-on-top-description": "Display notifications above fullscreen windows and other layers.",
"settings-background-opacity-description": "Adjust the opacity of notification backgrounds.",
+2
View File
@@ -1088,6 +1088,8 @@
"history-low-urgency-label": "Guardar urgencia baja en el historial",
"history-normal-urgency-description": "Guardar notificaciones de prioridad normal en el historial.",
"history-normal-urgency-label": "Guardar urgencia normal en el historial",
"media-toast-description": "Mostrar un toast cuando cambie el estado de reproducción multimedia.",
"media-toast-label": "Multimedia",
"monitors-desc": "Muestra notificaciones en monitores específicos. Por defecto, se muestra en todos si no se elige ninguno.",
"settings-always-on-top-description": "Muestra las notificaciones sobre ventanas a pantalla completa y otras capas.",
"settings-background-opacity-description": "Ajustar la opacidad de los fondos de las notificaciones.",
+2
View File
@@ -1088,6 +1088,8 @@
"history-low-urgency-label": "Enregistrer l'urgence faible dans l'historique",
"history-normal-urgency-description": "Enregistrer les notifications de priorité normale dans l'historique.",
"history-normal-urgency-label": "Enregistrer l'urgence normale dans l'historique",
"media-toast-description": "Afficher une notification toast lorsque l'état de lecture du média change.",
"media-toast-label": "Média",
"monitors-desc": "Afficher les notifications sur des moniteurs spécifiques. Par défaut, sur tous si aucun n'est choisi.",
"settings-always-on-top-description": "Afficher les notifications au-dessus des fenêtres en plein écran et des autres applications.",
"settings-background-opacity-description": "Ajuster l'opacité des arrière-plans de notifications.",
+2
View File
@@ -1088,6 +1088,8 @@
"history-low-urgency-label": "Alacsony sürgősség mentése az előzményekbe",
"history-normal-urgency-description": "Normál prioritású értesítések mentése az előzményekbe.",
"history-normal-urgency-label": "Normál sürgősség mentése az előzményekbe",
"media-toast-description": "Toast üzenet megjelenítése a média lejátszási állapotának változásakor.",
"media-toast-label": "Média",
"monitors-desc": "Értesítés megjelenítése meghatározott monitorokon. Alapértelmezetten mindegyiken, ha nincs kiválasztva.",
"settings-always-on-top-description": "Értesítések megjelenítése teljes képernyős ablakok és más rétegek felett.",
"settings-background-opacity-description": "Az értesítési hátterek átlátszóságának beállítása.",
+2
View File
@@ -1088,6 +1088,8 @@
"history-low-urgency-label": "低緊急度を履歴に保存",
"history-normal-urgency-description": "通常優先度の通知を履歴に保存します。",
"history-normal-urgency-label": "通常緊急度を履歴に保存",
"media-toast-description": "メディアの再生状態が変化したときにトーストを表示します。",
"media-toast-label": "メディア",
"monitors-desc": "通知を表示するディスプレイを選択します。未選択の場合は全てに表示されます。",
"settings-always-on-top-description": "全画面ウィンドウや他のレイヤーよりも手前に通知を表示します。",
"settings-background-opacity-description": "通知の背景の不透明度を調整します。",
+2
View File
@@ -1088,6 +1088,8 @@
"history-low-urgency-label": "Dîroka lezgîniya kêm tomar bike",
"history-normal-urgency-description": "Agahiyên pêşîniya normal di dîrokê de tomar bike.",
"history-normal-urgency-label": "Dîroka lezgîniya normal tomar bike",
"media-toast-description": "Dema rewşa lêdana medyayê biguhere, toastekê nîşan bide.",
"media-toast-label": "Medya",
"monitors-desc": "Nîşandana agahdarkirinê li ser çavdêrên taybet. Heke neyên hilbijartin, bi awayekî xwerû hemûyan nîşan dide.",
"settings-always-on-top-description": "Nîşandanên li ser pencereyên tev-ekran û qatên din nîşan bide.",
"settings-background-opacity-description": "Guhertina zelaliya paşxaneyên agahdariyan.",
+2
View File
@@ -1088,6 +1088,8 @@
"history-low-urgency-label": "Lage urgentie opslaan in geschiedenis",
"history-normal-urgency-description": "Meldingen met normale prioriteit opslaan in de geschiedenis.",
"history-normal-urgency-label": "Normale urgentie opslaan in geschiedenis",
"media-toast-description": "Een toast weergeven wanneer de afspeelstatus van media verandert.",
"media-toast-label": "Media",
"monitors-desc": "Meldingen op specifieke monitoren tonen. Standaard op alle als er geen zijn gekozen.",
"settings-always-on-top-description": "Toon meldingen boven fullscreen-vensters en andere lagen.",
"settings-background-opacity-description": "Pas de dekking van meldingsachtergronden aan.",
+2
View File
@@ -1088,6 +1088,8 @@
"history-low-urgency-label": "Odeślij niską pilność do historii",
"history-normal-urgency-description": "Zapisuj powiadomienia o normalnym priorytecie w historii.",
"history-normal-urgency-label": "Zapisz normalny priorytet do historii",
"media-toast-description": "Wyświetl toast, gdy zmieni się stan odtwarzania multimediów.",
"media-toast-label": "Media",
"monitors-desc": "Pokazuj powiadomienia na konkretnych monitorach. Domyślnie na wszystkich.",
"settings-always-on-top-description": "Wyświetlaj powiadomienia nad oknami pełnoekranowymi i innymi warstwami.",
"settings-background-opacity-description": "Dostosuj przezroczystość tła powiadomień.",
+2
View File
@@ -1088,6 +1088,8 @@
"history-low-urgency-label": "Salvar urgência baixa no histórico",
"history-normal-urgency-description": "Salvar notificações de prioridade normal no histórico.",
"history-normal-urgency-label": "Salvar urgência normal no histórico",
"media-toast-description": "Mostrar um toast quando o estado de reprodução de mídia mudar.",
"media-toast-label": "Multimédia",
"monitors-desc": "Mostra a notificação em monitores específicos. O padrão é todos, se nenhum for escolhido.",
"settings-always-on-top-description": "Exibe notificações acima de janelas em tela cheia e outras camadas.",
"settings-background-opacity-description": "Ajustar a opacidade dos fundos das notificações.",
+2
View File
@@ -1088,6 +1088,8 @@
"history-low-urgency-label": "Сохранять низкую срочность в истории",
"history-normal-urgency-description": "Сохранять уведомления с нормальным приоритетом в истории.",
"history-normal-urgency-label": "Сохранять нормальную срочность в истории",
"media-toast-description": "Показывать всплывающее уведомление при изменении состояния воспроизведения медиа.",
"media-toast-label": "Медиа",
"monitors-desc": "Показывать уведомления на определенных мониторах. По умолчанию на всех, если ни один не выбран.",
"settings-always-on-top-description": "Отображать уведомления поверх полноэкранных окон и других слоев.",
"settings-background-opacity-description": "Настройка непрозрачности фона уведомлений.",
+2
View File
@@ -1088,6 +1088,8 @@
"history-low-urgency-label": "Düşük aciliyeti geçmişe kaydet",
"history-normal-urgency-description": "Normal öncelikli bildirimleri geçmişe kaydet.",
"history-normal-urgency-label": "Normal aciliyeti geçmişe kaydet",
"media-toast-description": "Medya oynatma durumu değiştiğinde bir bildirim göster.",
"media-toast-label": "Medya",
"monitors-desc": "Bildirimleri belirli ekranlarda gösterin. Hiçbiri seçilmezse varsayılan olarak tümünde gösterilir.",
"settings-always-on-top-description": "Bildirimleri tam ekran pencerelerinin ve diğer katmanların üzerinde görüntüle.",
"settings-background-opacity-description": "Bildirim arka planlarının opaklığını ayarlayın.",
+2
View File
@@ -1088,6 +1088,8 @@
"history-low-urgency-label": "Зберігати низьку терміновість в історії",
"history-normal-urgency-description": "Зберігати сповіщення з нормальним пріоритетом в історії.",
"history-normal-urgency-label": "Зберігати нормальну терміновість в історії",
"media-toast-description": "Показувати спливаюче повідомлення, коли змінюється стан відтворення медіа.",
"media-toast-label": "Медіа",
"monitors-desc": "Показувати сповіщення на певних моніторах. За замовчуванням на всіх, якщо не вибрано.",
"settings-always-on-top-description": "Відображати сповіщення поверх повноекранних вікон та інших шарів.",
"settings-background-opacity-description": "Налаштуйте непрозорість фону сповіщень.",
+2
View File
@@ -1088,6 +1088,8 @@
"history-low-urgency-label": "将低紧急度保存到历史记录",
"history-normal-urgency-description": "将正常优先级通知保存到历史记录。",
"history-normal-urgency-label": "将正常紧急度保存到历史记录",
"media-toast-description": "媒体播放状态改变时显示 Toast 提示。",
"media-toast-label": "媒体",
"monitors-desc": "在特定显示器上显示通知。如果未选择,则默认为全部。",
"settings-always-on-top-description": "在全屏窗口和其他图层上方显示通知。",
"settings-background-opacity-description": "调整通知背景的透明度。",
+2
View File
@@ -1050,6 +1050,8 @@
"history-low-urgency-label": "儲存低急迫性到歷史通知",
"history-normal-urgency-description": "將普通急迫的通知存放到歷史通知",
"history-normal-urgency-label": "儲存普通急迫到歷史通知",
"media-toast-description": "媒體播放狀態變更時顯示 Toast 訊息。",
"media-toast-label": "媒體",
"monitors-desc": "只在特定的顯示器顯示通知, 如果全部取消勾選則會顯示在所有顯示器",
"settings-always-on-top-description": "在全螢幕視窗與其他層級上方顯示通知。",
"settings-background-opacity-description": "調整通知背景的不透明度",
+2 -1
View File
@@ -578,6 +578,7 @@ Singleton {
property string lowSoundFile: ""
property string excludedApps: "discord,firefox,chrome,chromium,edge"
}
property bool enableMediaToast: true
}
// on-screen display
@@ -587,7 +588,7 @@ Singleton {
property int autoHideMs: 2000
property bool overlayLayer: true
property real backgroundOpacity: 1.0
property list<var> enabledTypes: [OSD.Type.Volume, OSD.Type.InputVolume, OSD.Type.Brightness, OSD.Type.Media]
property list<var> enabledTypes: [OSD.Type.Volume, OSD.Type.InputVolume, OSD.Type.Brightness]
property list<string> monitors: [] // holds osd visibility per monitor
}
+9 -113
View File
@@ -19,8 +19,7 @@ Variants {
Volume,
InputVolume,
Brightness,
LockKey,
Media
LockKey
}
model: Quickshell.screens.filter(screen => (Settings.data.osd.monitors.includes(screen.name) || Settings.data.osd.monitors.length === 0) && Settings.data.osd.enabled)
@@ -40,11 +39,6 @@ Variants {
// Lock Key States
property string lastLockKeyChanged: "" // "caps", "num", "scroll", or ""
// Media States
property string mediaAction: "" // "play", "pause", or ""
property string mediaTrackTitle: ""
property string mediaTrackArtist: ""
// Current values (computed properties)
readonly property real currentVolume: AudioService.volume
readonly property bool isMuted: AudioService.muted
@@ -84,12 +78,6 @@ Variants {
return currentBrightness <= 0.5 ? "brightness-low" : "brightness-high";
case OSD.Type.LockKey:
return "keyboard";
case OSD.Type.Media:
if (root.mediaAction === "pause")
return "media-pause";
if (root.mediaAction === "play")
return "media-play";
return "music";
default:
return "";
}
@@ -105,8 +93,7 @@ Variants {
return currentBrightness;
case OSD.Type.LockKey:
return 1.0; // Always show 100% when showing lock key status
case OSD.Type.Media:
return 1.0; // Always show full for media
default:
return 0;
}
@@ -125,21 +112,6 @@ Variants {
return lastLockKeyChanged;
}
if (currentOSDType === OSD.Type.Media) {
// For media, show the action or track info
if (root.mediaTrackTitle) {
return root.mediaTrackTitle;
}
switch (root.mediaAction) {
case "play":
return "Playing";
case "pause":
return "Paused";
default:
return "Media";
}
}
const value = getCurrentValue();
const max = getMaxValue();
if ((currentOSDType === OSD.Type.Volume || currentOSDType === OSD.Type.InputVolume) && Settings.data.audio.volumeOverdrive) {
@@ -214,14 +186,6 @@ Variants {
showOSD(OSD.Type.Brightness);
}
// Media Control handling
function triggerMediaAction(action) {
root.mediaAction = action;
root.mediaTrackTitle = MediaService.trackTitle;
root.mediaTrackArtist = MediaService.trackArtist;
showOSD(OSD.Type.Media);
}
// Check if a specific OSD type is enabled
function isTypeEnabled(type) {
const enabledTypes = Settings.data.osd.enabledTypes || [];
@@ -320,48 +284,6 @@ Variants {
}
}
// Media playback monitoring
Connections {
target: MediaService
function onIsPlayingChanged() {
if (MediaService.isPlaying) {
root.mediaAction = "play";
root.mediaTrackTitle = MediaService.trackTitle;
root.mediaTrackArtist = MediaService.trackArtist;
showOSD(OSD.Type.Media);
} else {
// Show OSD when track is paused
root.mediaAction = "pause";
root.mediaTrackTitle = MediaService.trackTitle;
root.mediaTrackArtist = MediaService.trackArtist;
showOSD(OSD.Type.Media);
}
}
function onCurrentPlayerChanged() {
// Show OSD when a new player takes over
if (MediaService.currentPlayer) {
root.mediaTrackTitle = MediaService.trackTitle;
root.mediaTrackArtist = MediaService.trackArtist;
if (MediaService.isPlaying) {
root.mediaAction = "play";
showOSD(OSD.Type.Media);
}
}
}
function onTrackTitleChanged() {
// Show OSD when track changes
root.mediaTrackTitle = MediaService.trackTitle;
root.mediaTrackArtist = MediaService.trackArtist;
root.mediaAction = "play";
if (MediaService.isPlaying) {
showOSD(OSD.Type.Media);
}
}
}
// LockKeys monitoring with a cleaner approach
// Only connect when LockKey OSD is enabled to avoid starting the service unnecessarily
Connections {
@@ -632,21 +554,9 @@ Variants {
Layout.alignment: Qt.AlignVCenter
}
// Media Information Text (replaces progress bar)
NText {
visible: root.currentOSDType === OSD.Type.Media
text: root.getDisplayPercentage()
color: Color.mOnSurface
pointSize: Style.fontSizeS
horizontalAlignment: Text.AlignLeft
elide: Text.ElideRight
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
}
// Progress Bar for Volume/Brightness
Rectangle {
visible: root.currentOSDType !== OSD.Type.LockKey && root.currentOSDType !== OSD.Type.Media
visible: root.currentOSDType !== OSD.Type.LockKey
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
height: panel.barThickness
@@ -678,7 +588,7 @@ Variants {
// Percentage Text for Volume/Brightness
NText {
visible: root.currentOSDType !== OSD.Type.LockKey && root.currentOSDType !== OSD.Type.Media
visible: root.currentOSDType !== OSD.Type.LockKey
text: root.getDisplayPercentage()
color: Color.mOnSurface
pointSize: Style.fontSizeS
@@ -700,8 +610,8 @@ Variants {
anchors.fill: parent
anchors.topMargin: Style.marginL
anchors.bottomMargin: Style.marginL
spacing: root.currentOSDType === OSD.Type.LockKey || root.currentOSDType === OSD.Type.Media ? Style.marginM : Style.marginS
clip: root.currentOSDType !== OSD.Type.LockKey && root.currentOSDType !== OSD.Type.Media
spacing: root.currentOSDType === OSD.Type.LockKey ? Style.marginM : Style.marginS
clip: root.currentOSDType !== OSD.Type.LockKey
ColumnLayout {
id: textVerticalLayout
@@ -759,7 +669,7 @@ Variants {
}
NText {
visible: root.currentOSDType !== OSD.Type.LockKey && root.currentOSDType !== OSD.Type.Media
visible: root.currentOSDType !== OSD.Type.LockKey
text: root.getDisplayPercentage()
color: Color.mOnSurface
pointSize: Style.fontSizeS
@@ -771,24 +681,10 @@ Variants {
Layout.preferredHeight: Math.round(20 * Style.uiScaleRatio)
}
NText {
visible: root.currentOSDType === OSD.Type.Media
text: root.getDisplayPercentage()
color: Color.mOnSurface
pointSize: Style.fontSizeXS
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
Layout.preferredHeight: Math.round(20 * Style.uiScaleRatio)
}
Item {
visible: root.currentOSDType !== OSD.Type.LockKey && root.currentOSDType !== OSD.Type.Media
visible: root.currentOSDType !== OSD.Type.LockKey
Layout.fillWidth: true
Layout.fillHeight: root.currentOSDType !== OSD.Type.LockKey && root.currentOSDType !== OSD.Type.Media
Layout.fillHeight: root.currentOSDType !== OSD.Type.LockKey
Rectangle {
anchors.horizontalCenter: parent.horizontalCenter
@@ -9,11 +9,23 @@ ColumnLayout {
spacing: Style.marginL
Layout.fillWidth: true
NToggle {
NCheckbox {
Layout.fillWidth: true
label: I18n.tr("panels.notifications.media-toast-label")
description: I18n.tr("panels.notifications.media-toast-description")
checked: Settings.data.notifications.enableMediaToast
onToggled: checked => Settings.data.notifications.enableMediaToast = checked
}
NDivider {
Layout.fillWidth: true
}
NCheckbox {
Layout.fillWidth: true
label: I18n.tr("panels.notifications.toast-keyboard-label")
description: I18n.tr("panels.notifications.toast-keyboard-description")
checked: Settings.data.notifications.enableKeyboardLayoutToast
onToggled: checked => Settings.data.notifications.enableKeyboardLayoutToast = checked
defaultValue: Settings.getDefaultValue("notifications.enableKeyboardLayoutToast")
}
}
@@ -30,10 +30,6 @@ ColumnLayout {
{
type: OSD.Type.LockKey,
key: "types-lockkey"
},
{
type: OSD.Type.Media,
key: "types-media"
}
]
delegate: NCheckbox {
+77
View File
@@ -934,4 +934,81 @@ Singleton {
onDoNotDisturbChanged: {
ToastService.showNotice(doNotDisturb ? I18n.tr("toast.do-not-disturb.enabled") : I18n.tr("toast.do-not-disturb.disabled"), doNotDisturb ? I18n.tr("toast.do-not-disturb.enabled-desc") : I18n.tr("toast.do-not-disturb.disabled-desc"), doNotDisturb ? "bell-off" : "bell");
}
// Media toast functionality
property string previousMediaTitle: ""
property string previousMediaArtist: ""
property bool previousMediaIsPlaying: false
property bool mediaToastInitialized: false
Timer {
id: mediaToastInitTimer
interval: 3000 // Wait 3 seconds after startup to avoid initial toast
running: true
onTriggered: {
root.mediaToastInitialized = true;
root.previousMediaTitle = MediaService.trackTitle;
root.previousMediaArtist = MediaService.trackArtist;
root.previousMediaIsPlaying = MediaService.isPlaying;
}
}
Timer {
id: mediaToastDebounce
interval: 300 // Debounce rapid changes
onTriggered: {
if (!Settings.data.notifications.enableMediaToast || !mediaToastInitialized)
return;
if (doNotDisturb || PowerProfileService.noctaliaPerformanceMode)
return;
const title = MediaService.trackTitle || "";
const artist = MediaService.trackArtist || "";
const isPlaying = MediaService.isPlaying;
// Only show toast if something meaningful changed
const titleChanged = title !== previousMediaTitle && title !== "";
const playStateChanged = isPlaying !== previousMediaIsPlaying;
const hasMedia = title !== "" || artist !== "";
if (hasMedia && (titleChanged || playStateChanged)) {
const icon = isPlaying ? "player-play" : "player-pause";
let message = "";
if (artist && title) {
message = artist + " — " + title;
} else if (title) {
message = title;
} else if (artist) {
message = artist;
}
if (message !== "") {
const toastTitle = isPlaying ? I18n.tr("common.play") : I18n.tr("common.pause");
ToastService.showNotice(toastTitle, message, icon, 3000);
}
}
previousMediaTitle = title;
previousMediaArtist = artist;
previousMediaIsPlaying = isPlaying;
}
}
Connections {
target: MediaService
function onTrackTitleChanged() {
mediaToastDebounce.restart();
}
function onTrackArtistChanged() {
mediaToastDebounce.restart();
}
function onIsPlayingChanged() {
mediaToastDebounce.restart();
}
}
}