improv: create subscription channel for pages to send messages to

This commit is contained in:
Michael Aaron Murphy 2024-05-08 12:59:35 +02:00 committed by Michael Murphy
parent 11de7cbd4a
commit b443dd5b53
12 changed files with 104 additions and 26 deletions

1
Cargo.lock generated
View file

@ -1349,6 +1349,7 @@ dependencies = [
"once_cell",
"regex",
"slotmap",
"tokio",
"url",
]

View file

@ -5,6 +5,8 @@ resolver = "2"
rust-version = "1.71.0"
sunrise_sunset = "1.0.1"
[workspace.dependencies]
tokio = { version = "1.37.0", features = ["macros"] }
[workspace.dependencies.libcosmic]
git = "https://github.com/pop-os/libcosmic"

View file

@ -6,7 +6,7 @@ license = "GPL-3.0"
rust-version = "1.65.0"
[dependencies]
tokio = { version = "1.35.1", features = ["macros"] }
tokio.workspace = true
async-channel = "2.1.1"
color-eyre = "0.6.2"
cosmic-bg-config = { workspace = true }

View file

@ -6,16 +6,17 @@ use crate::pages::desktop::{
self, appearance, dock,
panel::{
self,
applets_inner::{self, AppletsPage, APPLET_DND_ICON_ID},
applets_inner::{self, APPLET_DND_ICON_ID},
inner as _panel,
},
};
use crate::pages::input::{self, keyboard};
use crate::pages::{self, display, networking, sound, system, time};
use crate::pages::input::{self};
use crate::pages::{self, display, sound, system, time};
use crate::subscription::desktop_files;
use crate::widget::{page_title, search_header};
use crate::PageCommands;
use cosmic::app::DbusActivationMessage;
use cosmic::iced::futures::SinkExt;
use cosmic::iced::Subscription;
use cosmic::widget::{button, row, text_input};
use cosmic::{
@ -42,6 +43,7 @@ pub struct SettingsApp {
config: Config,
core: Core,
nav_model: nav_bar::Model,
page_sender: Option<tokio::sync::mpsc::Sender<crate::pages::Message>>,
pages: page::Binder<crate::pages::Message>,
search_active: bool,
search_id: cosmic::widget::Id,
@ -77,19 +79,21 @@ impl SettingsApp {
#[derive(Clone, Debug)]
pub enum Message {
CloseContextDrawer,
DelayedInit(page::Entity),
DesktopInfo,
Error(String),
OpenContextDrawer(Cow<'static, str>),
Page(page::Entity),
PageMessage(crate::pages::Message),
PanelConfig(CosmicPanelConfig),
RegisterSubscriptionSender(tokio::sync::mpsc::Sender<pages::Message>),
SearchActivate,
SearchChanged(String),
SearchClear,
SearchSubmit,
SetWindowTitle,
OpenContextDrawer(Cow<'static, str>),
CloseContextDrawer,
SetTheme(cosmic::theme::Theme),
SetWindowTitle,
}
impl cosmic::Application for SettingsApp {
@ -113,6 +117,7 @@ impl cosmic::Application for SettingsApp {
config: Config::new(),
core,
nav_model: nav_bar::Model::default(),
page_sender: None,
pages: page::Binder::default(),
search_active: false,
search_id: cosmic::widget::Id::unique(),
@ -136,9 +141,10 @@ impl cosmic::Application for SettingsApp {
}
.unwrap_or(desktop_id);
let command = app.activate_page(active_id);
(app, command)
(
app,
cosmic::command::message(cosmic::app::message::app(Message::DelayedInit(active_id))),
)
}
fn nav_model(&self) -> Option<&nav_bar::Model> {
@ -208,6 +214,23 @@ impl cosmic::Application for SettingsApp {
});
Subscription::batch(vec![
// Creates a channel that listens to messages from pages.
// The sender is given back to the application so that it may pass it on.
cosmic::iced::subscription::channel(
std::any::TypeId::of::<Self>(),
4,
move |mut output| async move {
let (tx, mut rx) = tokio::sync::mpsc::channel::<pages::Message>(4);
let _res = output.send(Message::RegisterSubscriptionSender(tx)).await;
while let Some(event) = rx.recv().await {
let _res = output.send(Message::PageMessage(event)).await;
}
futures::future::pending().await
},
),
crate::subscription::daytime().map(|daytime| {
Message::PageMessage(pages::Message::Appearance(appearance::Message::Daytime(
daytime,
@ -409,6 +432,21 @@ impl cosmic::Application for SettingsApp {
Message::Error(error) => {
tracing::error!(error, "error occurred");
}
Message::RegisterSubscriptionSender(sender) => {
self.page_sender = Some(sender);
}
// It is necessary to delay init to allow time for the page sender to be initialized
Message::DelayedInit(active_id) => {
if self.page_sender.is_none() {
return cosmic::command::message(cosmic::app::message::app(
Message::DelayedInit(active_id),
));
}
return self.activate_page(active_id);
}
}
Command::none()
@ -438,7 +476,7 @@ impl cosmic::Application for SettingsApp {
} else if let Some(sub_pages) = self.pages.sub_pages(self.active_page) {
self.sub_page_view(sub_pages)
} else {
panic!("page without sub-pages or content");
return row::row().into();
};
let padding = if self.core.is_condensed() {
@ -518,9 +556,14 @@ impl SettingsApp {
self.search_active = false;
self.activate_navbar(page);
let sender = self
.page_sender
.clone()
.expect("sender should be available");
let page_command = self
.pages
.page_reload(page)
.on_enter(page, sender)
.map(Message::PageMessage)
.map(cosmic::app::Message::App);

View file

@ -1087,7 +1087,11 @@ impl page::Page<crate::pages::Message> for Page {
.description(fl!("appearance", "desc"))
}
fn reload(&mut self, _: page::Entity) -> Command<crate::pages::Message> {
fn on_enter(
&mut self,
_: page::Entity,
sender: tokio::sync::mpsc::Sender<crate::pages::Message>,
) -> Command<crate::pages::Message> {
command::future(fetch_icon_themes()).map(crate::pages::Message::Appearance)
}

View file

@ -207,7 +207,11 @@ impl page::Page<crate::pages::Message> for Page {
.description(fl!("wallpaper", "desc"))
}
fn reload(&mut self, _page: page::Entity) -> Command<crate::pages::Message> {
fn on_enter(
&mut self,
_page: page::Entity,
sender: tokio::sync::mpsc::Sender<crate::pages::Message>,
) -> Command<crate::pages::Message> {
let current_folder = self.config.current_folder().to_owned();
let recurse = self.categories.selected == Some(Category::Wallpapers);

View file

@ -219,12 +219,20 @@ impl page::Page<crate::pages::Message> for Page {
}
#[cfg(not(feature = "test"))]
fn reload(&mut self, _page: page::Entity) -> Command<crate::pages::Message> {
command::future(reload())
fn on_enter(
&mut self,
_page: page::Entity,
sender: tokio::sync::mpsc::Sender<crate::pages::Message>,
) -> Command<crate::pages::Message> {
command::future(on_enter())
}
#[cfg(feature = "test")]
fn reload(&mut self, _page: page::Entity) -> Command<crate::pages::Message> {
fn on_enter(
&mut self,
_page: page::Entity,
sender: tokio::sync::mpsc::Sender<crate::pages::Message>,
) -> Command<crate::pages::Message> {
command::future(async move {
let mut randr = List::default();
@ -287,7 +295,7 @@ impl Page {
}
return cosmic::command::future(async {
crate::Message::PageMessage(reload().await)
crate::Message::PageMessage(on_enter().await)
});
}
@ -805,7 +813,7 @@ fn cache_rates(cached_rates: &mut Vec<String>, rates: &[u32]) {
.collect();
}
pub async fn reload() -> crate::pages::Message {
pub async fn on_enter() -> crate::pages::Message {
let graphics_fut = graphics::fetch();
let randr_fut = cosmic_randr_shell::list();
let (graphics, randr) = futures::future::zip(graphics_fut, randr_fut).await;

View file

@ -250,7 +250,11 @@ impl page::Page<crate::pages::Message> for Page {
}
}
fn reload(&mut self, _page: page::Entity) -> Command<crate::pages::Message> {
fn on_enter(
&mut self,
_page: page::Entity,
sender: tokio::sync::mpsc::Sender<crate::pages::Message>,
) -> Command<crate::pages::Message> {
self.xkb = super::get_config(&self.config, "xkb_config");
match xkb_data::keyboard_layouts() {
Ok(keyboard_layouts) => {

View file

@ -43,7 +43,11 @@ impl page::Page<crate::pages::Message> for Page {
.description(fl!("about", "desc"))
}
fn reload(&mut self, _page: page::Entity) -> Command<crate::pages::Message> {
fn on_enter(
&mut self,
_page: page::Entity,
sender: tokio::sync::mpsc::Sender<crate::pages::Message>,
) -> Command<crate::pages::Message> {
command::future(async move {
crate::pages::Message::About(Message::Info(Box::new(Info::load())))
})

View file

@ -11,4 +11,5 @@ libcosmic = { workspace = true }
generator = "0.7.5"
downcast-rs = "1.2.0"
once_cell = "1.19.0"
url = "2.5.0"
tokio.workspace = true
url = "2.5.0"

View file

@ -166,9 +166,13 @@ impl<Message: 'static> Binder<Message> {
}
/// Calls a page's load function to refresh its data.
pub fn page_reload(&mut self, id: crate::Entity) -> Command<Message> {
pub fn on_enter(
&mut self,
id: crate::Entity,
sender: tokio::sync::mpsc::Sender<Message>,
) -> Command<Message> {
if let Some(page) = self.page.get_mut(id) {
return page.reload(id);
return page.on_enter(id, sender);
}
Command::none()

View file

@ -59,9 +59,12 @@ pub trait Page<Message: 'static>: Downcast {
}
/// Reload page metadata via a Command.
#[must_use]
#[allow(unused)]
fn reload(&mut self, page: crate::Entity) -> Command<Message> {
fn on_enter(
&mut self,
page: crate::Entity,
sender: tokio::sync::mpsc::Sender<Message>,
) -> Command<Message> {
Command::none()
}