feat: notification actions
This commit is contained in:
parent
104a608cf1
commit
ad656296e7
4 changed files with 269 additions and 159 deletions
|
|
@ -2,15 +2,20 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use cosmic::{
|
||||
iced::{futures, stream},
|
||||
iced::{
|
||||
futures::{self, FutureExt},
|
||||
stream,
|
||||
},
|
||||
iced_futures::Subscription,
|
||||
};
|
||||
use cosmic_notifications_util::Notification;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
future::pending,
|
||||
os::unix::io::{FromRawFd, RawFd},
|
||||
pin::pin,
|
||||
};
|
||||
|
||||
use tokio::sync::mpsc;
|
||||
use tracing::{error, trace};
|
||||
use zbus::{
|
||||
connection::Builder,
|
||||
|
|
@ -20,54 +25,95 @@ use zbus::{
|
|||
|
||||
#[derive(Debug)]
|
||||
pub enum State {
|
||||
WaitingForNotificationEvent(u8),
|
||||
WaitingForNotificationEvent,
|
||||
Finished,
|
||||
}
|
||||
|
||||
pub fn notifications(proxy: NotificationsAppletProxy<'static>) -> Subscription<Notification> {
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Input {
|
||||
Activated(u32, String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Output {
|
||||
Ready(mpsc::Sender<Input>),
|
||||
Notification(Notification),
|
||||
}
|
||||
|
||||
pub fn notifications(proxy: NotificationsAppletProxy<'static>) -> Subscription<Output> {
|
||||
struct SomeWorker;
|
||||
|
||||
Subscription::run_with_id(
|
||||
std::any::TypeId::of::<SomeWorker>(),
|
||||
stream::channel(50, |mut output| async move {
|
||||
let mut state = State::WaitingForNotificationEvent(0);
|
||||
let mut state = State::WaitingForNotificationEvent;
|
||||
let (sender, mut receiver) = mpsc::channel(10);
|
||||
_ = output.send(Output::Ready(sender)).await;
|
||||
|
||||
let mut signal;
|
||||
let mut fail_count: u8 = 0;
|
||||
loop {
|
||||
match proxy.receive_notify().await {
|
||||
Ok(s) => {
|
||||
signal = s;
|
||||
break;
|
||||
}
|
||||
Err(err) => {
|
||||
error!(
|
||||
"failed to get a stream of signals for notifications. {}",
|
||||
err
|
||||
);
|
||||
fail_count = fail_count.saturating_add(1);
|
||||
if fail_count > 5 {
|
||||
error!("Failed to receive notification events");
|
||||
_ = pending::<()>();
|
||||
} else {
|
||||
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
||||
};
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
loop {
|
||||
match &mut state {
|
||||
State::WaitingForNotificationEvent(mut fail_count) => {
|
||||
State::WaitingForNotificationEvent => {
|
||||
trace!("Waiting for notification events...");
|
||||
let mut signal = match proxy.receive_notify().await {
|
||||
Ok(s) => s,
|
||||
Err(err) => {
|
||||
error!(
|
||||
"failed to get a stream of signals for notifications. {}",
|
||||
err
|
||||
);
|
||||
fail_count = fail_count.saturating_add(1);
|
||||
if fail_count > 5 {
|
||||
error!("Failed to receive notification events");
|
||||
state = State::Finished;
|
||||
let mut next_signal = signal.next();
|
||||
let mut next_input = pin!(receiver.recv().fuse());
|
||||
cosmic::iced::futures::select! {
|
||||
v = next_signal => {
|
||||
if let Some(msg) = v {
|
||||
let Some(args) = msg.args().into_iter().next() else {
|
||||
break;
|
||||
};
|
||||
let notification = Notification::new(
|
||||
args.app_name,
|
||||
args.id,
|
||||
args.app_icon,
|
||||
args.summary,
|
||||
args.body,
|
||||
args.actions,
|
||||
args.hints,
|
||||
args.expire_timeout,
|
||||
);
|
||||
_ = output.send(Output::Notification(notification)).await;
|
||||
} else {
|
||||
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
||||
};
|
||||
continue;
|
||||
tracing::error!("Signal stream closed, ending notifications subscription");
|
||||
state = State::Finished;
|
||||
}
|
||||
}
|
||||
v = next_input => {
|
||||
if let Some(Input::Activated(id, action)) = v {
|
||||
if let Err(err) = proxy.invoke_action(id, action.clone()).await {
|
||||
tracing::error!("Failed to invoke action {id} {action}");
|
||||
} else {
|
||||
tracing::error!("Invoked {action} for {id}")
|
||||
}
|
||||
} else {
|
||||
tracing::error!("Channel closed, ending notifications subscription");
|
||||
state = State::Finished;
|
||||
}
|
||||
}
|
||||
};
|
||||
while let Some(msg) = signal.next().await {
|
||||
let Some(args) = msg.args().into_iter().next() else {
|
||||
break;
|
||||
};
|
||||
let notification = Notification::new(
|
||||
args.app_name,
|
||||
args.id,
|
||||
args.app_icon,
|
||||
args.summary,
|
||||
args.body,
|
||||
args.actions,
|
||||
args.hints,
|
||||
args.expire_timeout,
|
||||
);
|
||||
_ = output.send(notification).await;
|
||||
}
|
||||
}
|
||||
State::Finished => {
|
||||
|
|
@ -97,6 +143,8 @@ trait NotificationsApplet {
|
|||
hints: HashMap<&str, zbus::zvariant::Value<'_>>,
|
||||
expire_timeout: i32,
|
||||
) -> zbus::Result<()>;
|
||||
|
||||
fn invoke_action(&self, id: u32, action: String) -> zbus::Result<()>;
|
||||
}
|
||||
|
||||
pub async fn get_proxy() -> anyhow::Result<NotificationsAppletProxy<'static>> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue