feat(notifications): migrate from notify-rust to ashpd XDG Portal
Replace direct D-Bus notifications (notify-rust) with XDG Desktop Portal notifications (ashpd) for Flathub compliance. Portal notifications use the app's .desktop file identity and don't require --talk-name=org.freedesktop.Notifications permission. - Replace notify-rust dep with ashpd (linux-only, tokio+notification) - Use NotificationProxy for portal-based notifications - Use stable ID "track-now-playing" to replace instead of stacking - Convert artwork path to file:// URI via ashpd::Uri - Graceful fallback when portal is unavailable
This commit is contained in:
2 files changed
+24
-20
No files matched your search
@@ -90,8 +90,7 @@ ebur128 = "0.1"
|
|||||||
# Media controls (MPRIS on Linux)
|
# Media controls (MPRIS on Linux)
|
||||||
souvlaki = "0.7"
|
souvlaki = "0.7"
|
||||||
|
|
||||||
# Desktop notifications
|
# Desktop notifications → ashpd in [target.linux] deps below
|
||||||
notify-rust = "4"
|
|
||||||
|
|
||||||
# Image processing (tray icon + thumbnails)
|
# Image processing (tray icon + thumbnails)
|
||||||
image = { version = "0.25", default-features = false, features = ["png", "jpeg", "webp"] }
|
image = { version = "0.25", default-features = false, features = ["png", "jpeg", "webp"] }
|
||||||
@@ -141,8 +140,8 @@ futures-util = "0.3"
|
|||||||
|
|
||||||
# Platform-specific dependencies
|
# Platform-specific dependencies
|
||||||
[target.'cfg(target_os = "linux")'.dependencies]
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
# Note: xdg-portal feature disabled due to ashpd/zbus version incompatibility
|
|
||||||
tauri-plugin-dialog = { version = "2.6.0" }
|
tauri-plugin-dialog = { version = "2.6.0" }
|
||||||
|
ashpd = { version = "0.13", default-features = false, features = ["tokio", "notification"] }
|
||||||
|
|
||||||
# Direct ALSA access for bit-perfect playback (bypasses CPAL limitations)
|
# Direct ALSA access for bit-perfect playback (bypasses CPAL limitations)
|
||||||
alsa = "0.9"
|
alsa = "0.9"
|
||||||
|
|||||||
@@ -61,7 +61,9 @@ use crate::runtime::{
|
|||||||
};
|
};
|
||||||
use crate::AppState;
|
use crate::AppState;
|
||||||
use md5::{Digest, Md5};
|
use md5::{Digest, Md5};
|
||||||
use notify_rust::Notification;
|
use ashpd::desktop::notification::{Notification as PortalNotification, NotificationProxy};
|
||||||
|
use ashpd::desktop::Icon;
|
||||||
|
use ashpd::Uri;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
@@ -9397,7 +9399,7 @@ pub async fn v2_uncache_favorite_artist(
|
|||||||
// ==================== Remaining Legacy-Equivalent V2 Commands ====================
|
// ==================== Remaining Legacy-Equivalent V2 Commands ====================
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn v2_show_track_notification(
|
pub async fn v2_show_track_notification(
|
||||||
title: String,
|
title: String,
|
||||||
artist: String,
|
artist: String,
|
||||||
album: String,
|
album: String,
|
||||||
@@ -9428,27 +9430,30 @@ pub fn v2_show_track_notification(
|
|||||||
lines.push(quality);
|
lines.push(quality);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut notification = Notification::new();
|
let body_text = lines.join("\n");
|
||||||
notification
|
let mut notification = PortalNotification::new(&title)
|
||||||
.summary(&title)
|
.body(Some(body_text.as_str()));
|
||||||
.body(&lines.join("\n"))
|
|
||||||
.appname("QBZ")
|
|
||||||
.timeout(4000);
|
|
||||||
|
|
||||||
if let Some(url) = artwork_url {
|
if let Some(ref url_str) = artwork_url {
|
||||||
if let Ok(path) = v2_cache_notification_artwork(&url) {
|
if let Ok(path) = v2_cache_notification_artwork(url_str) {
|
||||||
if let Some(path_str) = path.to_str() {
|
let file_uri_str = format!("file://{}", path.display());
|
||||||
notification.image_path(path_str);
|
if let Ok(uri) = Uri::parse(&file_uri_str) {
|
||||||
|
notification = notification.icon(Icon::Uri(uri));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(e) = notification.show() {
|
match NotificationProxy::new().await {
|
||||||
log::warn!(
|
Ok(proxy) => {
|
||||||
"Could not show notification (notification system may be unavailable): {}",
|
if let Err(e) = proxy.add_notification("track-now-playing", notification).await {
|
||||||
e
|
log::warn!("Could not show notification via XDG portal: {}", e);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("XDG notification portal unavailable: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user