feat: dynamically load pages when their sections are searched
This commit is contained in:
parent
6463983745
commit
51bd56d8d3
6 changed files with 117 additions and 10 deletions
|
|
@ -49,12 +49,14 @@ use desktop::{
|
|||
#[cfg(feature = "wayland")]
|
||||
use event::wayland;
|
||||
use page::Entity;
|
||||
use std::collections::BTreeSet;
|
||||
use std::{borrow::Cow, str::FromStr};
|
||||
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[allow(clippy::module_name_repetitions)]
|
||||
pub struct SettingsApp {
|
||||
active_page: page::Entity,
|
||||
loaded_pages: BTreeSet<page::Entity>,
|
||||
config: Config,
|
||||
core: Core,
|
||||
nav_model: nav_bar::Model,
|
||||
|
|
@ -167,6 +169,7 @@ impl cosmic::Application for SettingsApp {
|
|||
fn init(core: Core, flags: Self::Flags) -> (Self, Task<Self::Message>) {
|
||||
let mut app = SettingsApp {
|
||||
active_page: page::Entity::default(),
|
||||
loaded_pages: BTreeSet::new(),
|
||||
config: Config::new(),
|
||||
core,
|
||||
nav_model: nav_bar::Model::default(),
|
||||
|
|
@ -337,7 +340,7 @@ impl cosmic::Application for SettingsApp {
|
|||
Message::SetWindowTitle => return self.set_title(),
|
||||
|
||||
Message::SearchChanged(phrase) => {
|
||||
self.search_changed(phrase);
|
||||
return self.search_changed(phrase);
|
||||
}
|
||||
|
||||
Message::SearchActivate => {
|
||||
|
|
@ -781,6 +784,7 @@ impl SettingsApp {
|
|||
let mut leave_task = iced::Task::none();
|
||||
|
||||
if current_page != page {
|
||||
self.loaded_pages.remove(¤t_page);
|
||||
leave_task = self
|
||||
.pages
|
||||
.on_leave(current_page)
|
||||
|
|
@ -801,6 +805,8 @@ impl SettingsApp {
|
|||
.clone()
|
||||
.expect("sender should be available");
|
||||
|
||||
self.loaded_pages.insert(page);
|
||||
|
||||
let page_task = self
|
||||
.pages
|
||||
.on_enter(page, sender)
|
||||
|
|
@ -920,13 +926,15 @@ impl SettingsApp {
|
|||
.into()
|
||||
}
|
||||
|
||||
fn search_changed(&mut self, phrase: String) {
|
||||
fn search_changed(&mut self, phrase: String) -> Task<crate::Message> {
|
||||
// If the text was cleared, clear the search results too.
|
||||
if phrase.is_empty() {
|
||||
self.search_clear();
|
||||
return;
|
||||
return Task::none();
|
||||
}
|
||||
|
||||
let mut tasks = Vec::new();
|
||||
|
||||
// Create a case-insensitive regular expression for the search function.
|
||||
let search_expression = regex::RegexBuilder::new(&phrase)
|
||||
.case_insensitive(true)
|
||||
|
|
@ -942,10 +950,51 @@ impl SettingsApp {
|
|||
// Use the results if results were found.
|
||||
if !results.is_empty() {
|
||||
self.search_selections = results;
|
||||
|
||||
let mut unload = BTreeSet::new();
|
||||
let mut load = BTreeSet::new();
|
||||
|
||||
'outer: for loaded_page in &self.loaded_pages {
|
||||
for (page, _) in &self.search_selections {
|
||||
if loaded_page == page {
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
|
||||
unload.insert(*loaded_page);
|
||||
}
|
||||
|
||||
for (page, _) in &self.search_selections {
|
||||
if !self.loaded_pages.contains(page) {
|
||||
load.insert(*page);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref sender) = self.page_sender {
|
||||
for page in load {
|
||||
eprintln!("loading {page:?}");
|
||||
self.loaded_pages.insert(page);
|
||||
tasks.push(self.pages.on_enter(page, sender.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
for page in unload {
|
||||
eprintln!("unloading {page:?}");
|
||||
self.loaded_pages.remove(&page);
|
||||
self.pages.on_leave(page);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.search_input = phrase;
|
||||
|
||||
if tasks.is_empty() {
|
||||
Task::none()
|
||||
} else {
|
||||
cosmic::command::batch(tasks)
|
||||
.map(Message::PageMessage)
|
||||
.map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
/// Clears the search results so that the search page will not be shown.
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ enum ContextView {
|
|||
}
|
||||
|
||||
pub struct Page {
|
||||
on_enter_handle: Option<cosmic::iced::task::Handle>,
|
||||
can_reset: bool,
|
||||
no_custom_window_hint: bool,
|
||||
context_view: Option<ContextView>,
|
||||
|
|
@ -152,6 +153,7 @@ impl
|
|||
});
|
||||
|
||||
Self {
|
||||
on_enter_handle: None,
|
||||
can_reset: if theme_mode.is_dark {
|
||||
theme_builder == ThemeBuilder::dark()
|
||||
} else {
|
||||
|
|
@ -1431,7 +1433,7 @@ impl page::Page<crate::pages::Message> for Page {
|
|||
_: page::Entity,
|
||||
_sender: tokio::sync::mpsc::Sender<crate::pages::Message>,
|
||||
) -> Task<crate::pages::Message> {
|
||||
cosmic::command::batch(vec![
|
||||
let (task, handle) = cosmic::command::batch(vec![
|
||||
// Load icon themes
|
||||
cosmic::command::future(icon_themes::fetch()).map(crate::pages::Message::Appearance),
|
||||
// Load font families
|
||||
|
|
@ -1441,9 +1443,17 @@ impl page::Page<crate::pages::Message> for Page {
|
|||
})
|
||||
.map(crate::pages::Message::Appearance),
|
||||
])
|
||||
.abortable();
|
||||
|
||||
self.on_enter_handle = Some(handle);
|
||||
task
|
||||
}
|
||||
|
||||
fn on_leave(&mut self) -> Task<crate::pages::Message> {
|
||||
if let Some(handle) = self.on_enter_handle.take() {
|
||||
handle.abort();
|
||||
}
|
||||
|
||||
cosmic::command::message(crate::pages::Message::Appearance(Message::Left))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -137,6 +137,9 @@ enum ContextView {
|
|||
|
||||
/// The page struct for the wallpaper view.
|
||||
pub struct Page {
|
||||
/// Abort handle to the on_enter task.
|
||||
on_enter_handle: Option<cosmic::iced::task::Handle>,
|
||||
|
||||
/// Whether to show a context drawer.
|
||||
context_view: Option<ContextView>,
|
||||
|
||||
|
|
@ -207,11 +210,16 @@ impl page::Page<crate::pages::Message> for Page {
|
|||
_page: page::Entity,
|
||||
_sender: tokio::sync::mpsc::Sender<crate::pages::Message>,
|
||||
) -> Task<crate::pages::Message> {
|
||||
// Check if the page is already being loaded.
|
||||
if self.on_enter_handle.is_some() {
|
||||
return Task::none();
|
||||
}
|
||||
|
||||
let current_folder = self.config.current_folder().to_owned();
|
||||
|
||||
let recurse = self.categories.selected == Some(Category::Wallpapers);
|
||||
|
||||
Task::future(async move {
|
||||
let (task, on_enter_handle) = Task::future(async move {
|
||||
let (service_config, displays) = wallpaper::config().await;
|
||||
|
||||
let mut selection = change_folder(current_folder, recurse).await;
|
||||
|
|
@ -245,6 +253,19 @@ impl page::Page<crate::pages::Message> for Page {
|
|||
selection,
|
||||
})))
|
||||
})
|
||||
.abortable();
|
||||
|
||||
self.on_enter_handle = Some(on_enter_handle);
|
||||
task
|
||||
}
|
||||
|
||||
fn on_leave(&mut self) -> Task<crate::pages::Message> {
|
||||
// Cancel the on_enter task if it was running.
|
||||
if let Some(handle) = self.on_enter_handle.take() {
|
||||
handle.abort();
|
||||
}
|
||||
|
||||
Task::none()
|
||||
}
|
||||
|
||||
fn context_drawer(&self) -> Option<Element<'_, crate::pages::Message>> {
|
||||
|
|
@ -265,6 +286,7 @@ impl page::AutoBind<crate::pages::Message> for Page {}
|
|||
impl Default for Page {
|
||||
fn default() -> Self {
|
||||
let mut page = Page {
|
||||
on_enter_handle: None,
|
||||
context_view: None,
|
||||
show_tab_bar: false,
|
||||
active_output: None,
|
||||
|
|
|
|||
|
|
@ -194,7 +194,6 @@ pub struct Page {
|
|||
dialog: Option<VpnDialog>,
|
||||
view_more_popup: Option<ConnectionId>,
|
||||
known_connections: IndexMap<UUID, ConnectionSettings>,
|
||||
wireguard_connections: IndexMap<UUID, String>,
|
||||
/// Withhold device update if the view more popup is shown.
|
||||
withheld_devices: Option<Vec<network_manager::devices::DeviceInfo>>,
|
||||
/// Withhold active connections update if the view more popup is shown.
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use slotmap::SlotMap;
|
|||
pub struct Page {
|
||||
battery: Battery,
|
||||
connected_devices: Vec<ConnectedDevice>,
|
||||
on_enter_handle: Option<cosmic::iced::task::Handle>,
|
||||
}
|
||||
|
||||
impl page::Page<crate::pages::Message> for Page {
|
||||
|
|
@ -54,7 +55,20 @@ impl page::Page<crate::pages::Message> for Page {
|
|||
}),
|
||||
];
|
||||
|
||||
cosmic::Task::batch(futures).map(crate::pages::Message::Power)
|
||||
let (task, handle) = cosmic::Task::batch(futures)
|
||||
.map(crate::pages::Message::Power)
|
||||
.abortable();
|
||||
|
||||
self.on_enter_handle = Some(handle);
|
||||
task
|
||||
}
|
||||
|
||||
fn on_leave(&mut self) -> Task<crate::pages::Message> {
|
||||
if let Some(handle) = self.on_enter_handle.take() {
|
||||
handle.abort();
|
||||
}
|
||||
|
||||
Task::none()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ pub enum Message {
|
|||
pub struct Page {
|
||||
editing_device_name: bool,
|
||||
info: Info,
|
||||
on_enter_handle: Option<cosmic::iced::task::Handle>,
|
||||
}
|
||||
|
||||
impl page::AutoBind<crate::pages::Message> for Page {}
|
||||
|
|
@ -48,9 +49,21 @@ impl page::Page<crate::pages::Message> for Page {
|
|||
_page: page::Entity,
|
||||
_sender: tokio::sync::mpsc::Sender<crate::pages::Message>,
|
||||
) -> Task<crate::pages::Message> {
|
||||
Task::future(
|
||||
async move { crate::pages::Message::About(Message::Info(Box::new(Info::load()))) },
|
||||
)
|
||||
let (task, handle) = Task::future(async move {
|
||||
crate::pages::Message::About(Message::Info(Box::new(Info::load())))
|
||||
})
|
||||
.abortable();
|
||||
|
||||
self.on_enter_handle = Some(handle);
|
||||
task
|
||||
}
|
||||
|
||||
fn on_leave(&mut self) -> Task<crate::pages::Message> {
|
||||
if let Some(handle) = self.on_enter_handle.take() {
|
||||
handle.abort();
|
||||
}
|
||||
|
||||
Task::none()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue