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)
|
||||
souvlaki = "0.7"
|
||||
|
||||
# Desktop notifications
|
||||
notify-rust = "4"
|
||||
# Desktop notifications → ashpd in [target.linux] deps below
|
||||
|
||||
# Image processing (tray icon + thumbnails)
|
||||
image = { version = "0.25", default-features = false, features = ["png", "jpeg", "webp"] }
|
||||
@@ -141,8 +140,8 @@ futures-util = "0.3"
|
||||
|
||||
# Platform-specific 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" }
|
||||
ashpd = { version = "0.13", default-features = false, features = ["tokio", "notification"] }
|
||||
|
||||
# Direct ALSA access for bit-perfect playback (bypasses CPAL limitations)
|
||||
alsa = "0.9"
|
||||
|
||||
@@ -61,7 +61,9 @@ use crate::runtime::{
|
||||
};
|
||||
use crate::AppState;
|
||||
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::fs;
|
||||
use std::io::Write;
|
||||
@@ -9397,7 +9399,7 @@ pub async fn v2_uncache_favorite_artist(
|
||||
// ==================== Remaining Legacy-Equivalent V2 Commands ====================
|
||||
|
||||
#[tauri::command]
|
||||
pub fn v2_show_track_notification(
|
||||
pub async fn v2_show_track_notification(
|
||||
title: String,
|
||||
artist: String,
|
||||
album: String,
|
||||
@@ -9428,27 +9430,30 @@ pub fn v2_show_track_notification(
|
||||
lines.push(quality);
|
||||
}
|
||||
|
||||
let mut notification = Notification::new();
|
||||
notification
|
||||
.summary(&title)
|
||||
.body(&lines.join("\n"))
|
||||
.appname("QBZ")
|
||||
.timeout(4000);
|
||||
let body_text = lines.join("\n");
|
||||
let mut notification = PortalNotification::new(&title)
|
||||
.body(Some(body_text.as_str()));
|
||||
|
||||
if let Some(url) = artwork_url {
|
||||
if let Ok(path) = v2_cache_notification_artwork(&url) {
|
||||
if let Some(path_str) = path.to_str() {
|
||||
notification.image_path(path_str);
|
||||
if let Some(ref url_str) = artwork_url {
|
||||
if let Ok(path) = v2_cache_notification_artwork(url_str) {
|
||||
let file_uri_str = format!("file://{}", path.display());
|
||||
if let Ok(uri) = Uri::parse(&file_uri_str) {
|
||||
notification = notification.icon(Icon::Uri(uri));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(e) = notification.show() {
|
||||
log::warn!(
|
||||
"Could not show notification (notification system may be unavailable): {}",
|
||||
e
|
||||
);
|
||||
match NotificationProxy::new().await {
|
||||
Ok(proxy) => {
|
||||
if let Err(e) = proxy.add_notification("track-now-playing", notification).await {
|
||||
log::warn!("Could not show notification via XDG portal: {}", e);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("XDG notification portal unavailable: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user