chore: updates after iced-rebase
This commit is contained in:
parent
bd0d180482
commit
71d9d6d5bb
41 changed files with 1786 additions and 2396 deletions
|
|
@ -16,18 +16,17 @@ use cosmic::{
|
|||
Alignment, Length, Subscription,
|
||||
advanced::text::{Ellipsize, EllipsizeHeightLimit},
|
||||
platform_specific::shell::wayland::commands::popup::{destroy_popup, get_popup},
|
||||
widget::{column, row},
|
||||
widget::{self, column, row},
|
||||
window,
|
||||
},
|
||||
surface, theme,
|
||||
widget::{Column, button, container, divider, icon, scrollable, text},
|
||||
widget::{Column, button, cards, container, divider, icon, scrollable, space, text, toggler},
|
||||
};
|
||||
|
||||
use cosmic::iced_futures::futures::executor::block_on;
|
||||
|
||||
use cosmic_notifications_config::NotificationsConfig;
|
||||
use cosmic_notifications_util::{ActionId, Image, Notification};
|
||||
use cosmic_time::{Instant, Timeline, anim, chain, id};
|
||||
use std::{borrow::Cow, collections::HashMap, path::PathBuf, sync::LazyLock};
|
||||
use subscriptions::notifications::{self, NotificationsAppletProxy};
|
||||
use tokio::sync::mpsc::Sender;
|
||||
|
|
@ -38,8 +37,6 @@ pub fn run() -> cosmic::iced::Result {
|
|||
cosmic::applet::run::<Notifications>(())
|
||||
}
|
||||
|
||||
static DO_NOT_DISTURB: LazyLock<id::Toggler> = LazyLock::new(id::Toggler::unique);
|
||||
|
||||
struct Notifications {
|
||||
core: cosmic::app::Core,
|
||||
config: NotificationsConfig,
|
||||
|
|
@ -47,27 +44,14 @@ struct Notifications {
|
|||
icon_name: String,
|
||||
popup: Option<window::Id>,
|
||||
// notifications: Vec<Notification>,
|
||||
timeline: Timeline,
|
||||
dbus_sender: Option<Sender<subscriptions::dbus::Input>>,
|
||||
cards: Vec<(id::Cards, Vec<Notification>, bool, String, String, String)>,
|
||||
cards: Vec<(widget::Id, Vec<Notification>, bool, String, String, String)>,
|
||||
token_tx: Option<calloop::channel::Sender<TokenRequest>>,
|
||||
proxy: NotificationsAppletProxy<'static>,
|
||||
notifications_tx: Option<Sender<notifications::Input>>,
|
||||
}
|
||||
|
||||
impl Notifications {
|
||||
fn update_cards(&mut self, id: id::Cards) {
|
||||
if let Some((id, _, card_value, ..)) = self.cards.iter().find(|c| c.0 == id) {
|
||||
let chain = if *card_value {
|
||||
chain::Cards::on(id.clone(), 1.)
|
||||
} else {
|
||||
chain::Cards::off(id.clone(), 1.)
|
||||
};
|
||||
self.timeline.set_chain(chain);
|
||||
self.timeline.start();
|
||||
}
|
||||
}
|
||||
|
||||
fn update_icon(&mut self) {
|
||||
self.icon_name = if self.config.do_not_disturb {
|
||||
"cosmic-applet-notification-disabled-symbolic"
|
||||
|
|
@ -84,8 +68,7 @@ impl Notifications {
|
|||
enum Message {
|
||||
TogglePopup,
|
||||
CloseRequested(window::Id),
|
||||
DoNotDisturb(chain::Toggler, bool),
|
||||
Frame(Instant),
|
||||
DoNotDisturb(bool),
|
||||
NotificationEvent(notifications::Output),
|
||||
Config(NotificationsConfig),
|
||||
DbusEvent(subscriptions::dbus::Output),
|
||||
|
|
@ -128,7 +111,6 @@ impl cosmic::Application for Notifications {
|
|||
config,
|
||||
icon_name: String::default(),
|
||||
popup: None,
|
||||
timeline: Timeline::default(),
|
||||
dbus_sender: Option::default(),
|
||||
cards: Vec::new(),
|
||||
token_tx: Option::default(),
|
||||
|
|
@ -148,7 +130,7 @@ impl cosmic::Application for Notifications {
|
|||
&mut self.core
|
||||
}
|
||||
|
||||
fn style(&self) -> Option<cosmic::iced_runtime::Appearance> {
|
||||
fn style(&self) -> Option<cosmic::iced::theme::Style> {
|
||||
Some(cosmic::applet::style())
|
||||
}
|
||||
|
||||
|
|
@ -162,9 +144,6 @@ impl cosmic::Application for Notifications {
|
|||
}
|
||||
Message::Config(res.config)
|
||||
}),
|
||||
self.timeline
|
||||
.as_subscription()
|
||||
.map(|(_, now)| Message::Frame(now)),
|
||||
subscriptions::dbus::proxy().map(Message::DbusEvent),
|
||||
subscriptions::notifications::notifications(self.proxy.clone())
|
||||
.map(Message::NotificationEvent),
|
||||
|
|
@ -174,16 +153,12 @@ impl cosmic::Application for Notifications {
|
|||
|
||||
fn update(&mut self, message: Self::Message) -> app::Task<Self::Message> {
|
||||
match message {
|
||||
Message::Frame(now) => {
|
||||
self.timeline.now(now);
|
||||
}
|
||||
Message::TogglePopup => {
|
||||
if let Some(p) = self.popup.take() {
|
||||
return destroy_popup(p);
|
||||
} else {
|
||||
let new_id = window::Id::unique();
|
||||
self.popup.replace(new_id);
|
||||
self.timeline = Timeline::new();
|
||||
|
||||
let popup_settings = self.core.applet.get_popup_settings(
|
||||
self.core.main_window_id().unwrap(),
|
||||
|
|
@ -196,8 +171,7 @@ impl cosmic::Application for Notifications {
|
|||
return get_popup(popup_settings);
|
||||
}
|
||||
}
|
||||
Message::DoNotDisturb(chain, b) => {
|
||||
self.timeline.set_chain(chain).start();
|
||||
Message::DoNotDisturb(b) => {
|
||||
self.config.do_not_disturb = b;
|
||||
if let Some(helper) = &self.config_helper {
|
||||
if let Err(err) = self.config.write_entry(helper) {
|
||||
|
|
@ -223,7 +197,7 @@ impl cosmic::Application for Notifications {
|
|||
}
|
||||
} else {
|
||||
self.cards.push((
|
||||
id::Cards::new(n.app_name.clone()),
|
||||
widget::Id::new(n.app_name.clone()),
|
||||
vec![n],
|
||||
false,
|
||||
fl!("show-more", HashMap::from([("more", "1")])),
|
||||
|
|
@ -315,7 +289,6 @@ impl cosmic::Application for Notifications {
|
|||
} else {
|
||||
return Task::none();
|
||||
};
|
||||
self.update_cards(id);
|
||||
}
|
||||
Message::CloseRequested(id) => {
|
||||
if Some(id) == self.popup {
|
||||
|
|
@ -412,15 +385,11 @@ impl cosmic::Application for Notifications {
|
|||
} = theme::active().cosmic().spacing;
|
||||
|
||||
let do_not_disturb = padded_control(row![
|
||||
anim!(
|
||||
DO_NOT_DISTURB,
|
||||
&self.timeline,
|
||||
fl!("do-not-disturb"),
|
||||
self.config.do_not_disturb,
|
||||
Message::DoNotDisturb
|
||||
)
|
||||
.text_size(14)
|
||||
.width(Length::Fill)
|
||||
toggler(self.config.do_not_disturb)
|
||||
.on_toggle(Message::DoNotDisturb)
|
||||
.text_size(14)
|
||||
.width(Length::Fill)
|
||||
.label(fl!("do-not-disturb"))
|
||||
]);
|
||||
|
||||
let notifications = if self.cards.is_empty() {
|
||||
|
|
@ -522,13 +491,12 @@ impl cosmic::Application for Notifications {
|
|||
Some(cosmic::widget::icon::from_name(n.app_icon.as_str()).handle())
|
||||
}
|
||||
});
|
||||
let card_list = anim!(
|
||||
let card_list = cards(
|
||||
//cards
|
||||
c.0.clone(),
|
||||
&self.timeline,
|
||||
notif_elems,
|
||||
Message::ClearAll(Some(name.clone())),
|
||||
Some(move |_, e| Message::CardsToggled(name.clone(), e)),
|
||||
Some(move |e| Message::CardsToggled(name.clone(), e)),
|
||||
Some(move |id| Message::ActivateNotification(ids[id])),
|
||||
&c.3,
|
||||
&c.4,
|
||||
|
|
@ -536,6 +504,7 @@ impl cosmic::Application for Notifications {
|
|||
show_more_icon,
|
||||
c.2,
|
||||
);
|
||||
// let card_list = space::horizontal().width(Length::Fixed(10.));
|
||||
notifs.push(card_list.into());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,73 +33,75 @@ pub enum Output {
|
|||
pub fn proxy() -> Subscription<Output> {
|
||||
struct SomeWorker;
|
||||
|
||||
Subscription::run_with_id(
|
||||
std::any::TypeId::of::<SomeWorker>(),
|
||||
stream::channel(50, |mut output| async move {
|
||||
let mut state = State::Ready;
|
||||
Subscription::run_with(std::any::TypeId::of::<SomeWorker>(), |_| {
|
||||
stream::channel(
|
||||
50,
|
||||
|mut output: futures::channel::mpsc::Sender<Output>| async move {
|
||||
let mut state = State::Ready;
|
||||
|
||||
loop {
|
||||
match &mut state {
|
||||
State::Ready => {
|
||||
let (sender, receiver) = channel(10);
|
||||
let Ok(conn) = Connection::session().await else {
|
||||
error!("Failed to connect to session bus");
|
||||
state = State::Finished;
|
||||
continue;
|
||||
};
|
||||
loop {
|
||||
match &mut state {
|
||||
State::Ready => {
|
||||
let (sender, receiver) = channel(10);
|
||||
let Ok(conn) = Connection::session().await else {
|
||||
error!("Failed to connect to session bus");
|
||||
state = State::Finished;
|
||||
continue;
|
||||
};
|
||||
|
||||
let Ok(proxy) = NotificationsProxy::new(&conn).await else {
|
||||
error!("Failed to create proxy from session connection");
|
||||
state = State::Finished;
|
||||
continue;
|
||||
};
|
||||
let tx = sender.clone();
|
||||
if let Err(err) = output.send(Output::Ready(sender)).await {
|
||||
error!("Failed to send sender: {}", err);
|
||||
state = State::Finished;
|
||||
continue;
|
||||
}
|
||||
state = match proxy.receive_notification_closed().await {
|
||||
Ok(mut s) => {
|
||||
tokio::spawn(async move {
|
||||
while let Some(msg) = s.next().await {
|
||||
let Ok(id) = msg.args().map(|args| args.id) else {
|
||||
continue;
|
||||
};
|
||||
_ = tx.send(Input::CloseEvent(id)).await;
|
||||
}
|
||||
});
|
||||
State::WaitingForNotificationEvent(proxy, receiver)
|
||||
let Ok(proxy) = NotificationsProxy::new(&conn).await else {
|
||||
error!("Failed to create proxy from session connection");
|
||||
state = State::Finished;
|
||||
continue;
|
||||
};
|
||||
let tx = sender.clone();
|
||||
if let Err(err) = output.send(Output::Ready(sender)).await {
|
||||
error!("Failed to send sender: {}", err);
|
||||
state = State::Finished;
|
||||
continue;
|
||||
}
|
||||
Err(err) => {
|
||||
error!(
|
||||
"failed to get a stream of signals for notifications. {}",
|
||||
err
|
||||
);
|
||||
State::Finished
|
||||
state = match proxy.receive_notification_closed().await {
|
||||
Ok(mut s) => {
|
||||
tokio::spawn(async move {
|
||||
while let Some(msg) = s.next().await {
|
||||
let Ok(id) = msg.args().map(|args| args.id) else {
|
||||
continue;
|
||||
};
|
||||
_ = tx.send(Input::CloseEvent(id)).await;
|
||||
}
|
||||
});
|
||||
State::WaitingForNotificationEvent(proxy, receiver)
|
||||
}
|
||||
Err(err) => {
|
||||
error!(
|
||||
"failed to get a stream of signals for notifications. {}",
|
||||
err
|
||||
);
|
||||
State::Finished
|
||||
}
|
||||
};
|
||||
}
|
||||
State::WaitingForNotificationEvent(proxy, rx) => match rx.recv().await {
|
||||
Some(Input::Dismiss(id)) => {
|
||||
if let Err(err) = proxy.close_notification(id).await {
|
||||
error!("Failed to close notification: {}", err);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
State::WaitingForNotificationEvent(proxy, rx) => match rx.recv().await {
|
||||
Some(Input::Dismiss(id)) => {
|
||||
if let Err(err) = proxy.close_notification(id).await {
|
||||
error!("Failed to close notification: {}", err);
|
||||
Some(Input::CloseEvent(id)) => {
|
||||
_ = output.send(Output::CloseEvent(id)).await;
|
||||
}
|
||||
None => {
|
||||
warn!("Notification event channel closed");
|
||||
state = State::Finished;
|
||||
continue;
|
||||
}
|
||||
},
|
||||
State::Finished => {
|
||||
let () = futures::future::pending().await;
|
||||
}
|
||||
Some(Input::CloseEvent(id)) => {
|
||||
_ = output.send(Output::CloseEvent(id)).await;
|
||||
}
|
||||
None => {
|
||||
warn!("Notification event channel closed");
|
||||
state = State::Finished;
|
||||
continue;
|
||||
}
|
||||
},
|
||||
State::Finished => {
|
||||
let () = futures::future::pending().await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
)
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use cosmic_notifications_util::Notification;
|
|||
use futures_util::{SinkExt, StreamExt};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
hash::Hash,
|
||||
os::unix::io::{FromRawFd, RawFd},
|
||||
pin::pin,
|
||||
};
|
||||
|
|
@ -37,89 +38,97 @@ pub enum Output {
|
|||
}
|
||||
|
||||
pub fn notifications(proxy: NotificationsAppletProxy<'static>) -> Subscription<Output> {
|
||||
struct SomeWorker;
|
||||
struct Wrapper(NotificationsAppletProxy<'static>);
|
||||
|
||||
Subscription::run_with_id(
|
||||
std::any::TypeId::of::<SomeWorker>(),
|
||||
stream::channel(50, |mut output| async move {
|
||||
let mut state = State::WaitingForNotificationEvent;
|
||||
let (sender, mut receiver) = mpsc::channel(10);
|
||||
_ = output.send(Output::Ready(sender)).await;
|
||||
impl Hash for Wrapper {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
std::any::TypeId::of::<NotificationsAppletProxy<'static>>().hash(state);
|
||||
}
|
||||
}
|
||||
Subscription::run_with(Wrapper(proxy), |Wrapper(proxy)| {
|
||||
let proxy = proxy.clone();
|
||||
stream::channel(
|
||||
50,
|
||||
move |mut output: futures::channel::mpsc::Sender<Output>| async move {
|
||||
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");
|
||||
// exit because the applet needs the notifications daemon in order to work properly
|
||||
std::process::exit(0);
|
||||
} else {
|
||||
tokio::time::sleep(std::time::Duration::from_secs(1)).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");
|
||||
// exit because the applet needs the notifications daemon in order to work properly
|
||||
std::process::exit(0);
|
||||
} else {
|
||||
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
loop {
|
||||
match &mut state {
|
||||
State::WaitingForNotificationEvent => {
|
||||
trace!("Waiting for notification events...");
|
||||
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 Ok(args) = msg.args() 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 {
|
||||
tracing::error!("Signal stream closed, ending notifications subscription");
|
||||
state = State::Finished;
|
||||
}
|
||||
}
|
||||
v = next_input => {
|
||||
if let Some(Input::Activated(id, action)) = v {
|
||||
if proxy.invoke_action(id, action.clone()).await.is_err() {
|
||||
tracing::error!("Failed to invoke action {id} {action}");
|
||||
loop {
|
||||
match &mut state {
|
||||
State::WaitingForNotificationEvent => {
|
||||
trace!("Waiting for notification events...");
|
||||
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 Ok(args) = msg.args() 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 {
|
||||
tracing::error!("Invoked {action} for {id}");
|
||||
tracing::error!("Signal stream closed, ending notifications subscription");
|
||||
state = State::Finished;
|
||||
}
|
||||
}
|
||||
v = next_input => {
|
||||
if let Some(Input::Activated(id, action)) = v {
|
||||
if proxy.invoke_action(id, action.clone()).await.is_err() {
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
tracing::error!("Channel closed, ending notifications subscription");
|
||||
state = State::Finished;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
State::Finished => {
|
||||
let () = futures::future::pending().await;
|
||||
State::Finished => {
|
||||
let () = futures::future::pending().await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
)
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
#[proxy(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue