feat: retry opening network locations after mounting

This commit is contained in:
Ashley Wulber 2025-07-12 19:42:04 -04:00 committed by Jeremy Soller
parent 7711b4bcc0
commit c7e9828d7b
9 changed files with 333 additions and 56 deletions

View file

@ -334,6 +334,12 @@ pub enum Message {
NavMenuAction(NavMenuAction),
NetworkAuth(MounterKey, String, MounterAuth, mpsc::Sender<MounterAuth>),
NetworkDriveInput(String),
NetworkDriveOpenEntityAfterMount {
entity: Entity,
},
NetworkDriveOpenTabAfterMount {
location: Location,
},
NetworkDriveSubmit,
NetworkResult(MounterKey, String, Result<bool, String>),
NewItem(Option<Entity>, bool),
@ -885,6 +891,58 @@ impl App {
activate: bool,
selection_paths: Option<Vec<PathBuf>>,
) -> (Entity, Task<Message>) {
#[cfg(feature = "gvfs")]
if let Location::Network(ref uri, ref name, Some(ref path)) = location {
dbg!(path, self.mounter_items.len());
let mut found = false;
if let Some(key) = self
.mounter_items
.iter()
.find_map(|(k, items)| {
items.iter().find_map(|item| {
found |= item.path().is_some_and(|p| path.starts_with(p))
|| item.name() == *name
|| item.uri() == *uri;
dbg!(
item.is_mounted(),
item.path(),
path,
name,
item.name(),
item.uri(),
uri
);
(!item.is_mounted() && found).then(|| *k)
})
})
.or(if found {
dbg!("found so skip...");
None
} else {
dbg!("not found...");
// TODO do we need to choose the correct mounter?
self.mounter_items.iter().map(|(k, _)| *k).next()
})
{
if let Some(mounter) = MOUNTERS.get(&key) {
let location = location.clone();
dbg!(&location);
return (
Entity::null(),
mounter.network_drive(uri.clone()).map(move |_| {
cosmic::Action::App(Message::NetworkDriveOpenTabAfterMount {
location: location.clone(),
})
}),
);
}
} else {
dbg!("huh...");
}
}
dbg!(&location);
let mut tab = Tab::new(
location.clone(),
self.config.tab,
@ -1061,6 +1119,7 @@ impl App {
location: Location,
selection_paths: Option<Vec<PathBuf>>,
) -> Task<Message> {
dbg!("rescan", &location);
log::info!("rescan_tab {entity:?} {location:?} {selection_paths:?}");
let icon_sizes = self.config.tab.icon_sizes;
let mounter_items = self.mounter_items.clone();
@ -1303,7 +1362,12 @@ impl App {
})
.size(16),
)
.data(Location::Path(path.clone()))
.data(match favorite {
Favorite::Network { uri, name, path } => {
Location::Network(uri.clone(), name.clone(), Some(path.to_owned()))
}
_ => Location::Path(path.clone()),
})
.data(FavoriteIndex(favorite_i))
});
}
@ -1327,6 +1391,7 @@ impl App {
.data(Location::Network(
"network:///".to_string(),
fl!("networks"),
None,
))
.divider_above()
});
@ -1346,7 +1411,13 @@ impl App {
nav_model = nav_model.insert(|mut b| {
b = b.text(item.name()).data(MounterData(key, item.clone()));
if let Some(path) = item.path() {
b = b.data(Location::Path(path.clone()));
b = b.data(Location::Network(
item.uri().to_string(),
item.name(),
Some(path),
));
} else {
b = b.data(Location::Network(item.uri().to_string(), item.name(), None));
}
if let Some(icon) = item.icon(true) {
b = b.icon(widget::icon::icon(icon).size(16));
@ -2155,35 +2226,85 @@ impl Application for App {
fn on_nav_select(&mut self, entity: Entity) -> Task<Self::Message> {
self.nav_model.activate(entity);
if let Some(location) = self.nav_model.data::<Location>(entity) {
dbg!(&location);
let should_open = match location {
Location::Path(path) => match path.try_exists() {
Ok(true) => true,
Ok(false) => {
log::warn!("failed to open favorite, path does not exist: {:?}", path);
self.dialog_pages.push_back(DialogPage::FavoritePathError {
path: path.clone(),
entity,
});
false
#[cfg(feature = "gvfs")]
Location::Network(uri, name, Some(path))
if !path.try_exists().unwrap_or_default() =>
{
dbg!(&location, path, self.mounter_items.len(), uri, path);
let mut found = false;
if let Some(key) = self
.mounter_items
.iter()
.find_map(|(k, items)| {
items.iter().find_map(|item| {
found |= item.path().is_some_and(|p| path.starts_with(&p))
|| item.name() == *name
|| item.uri() == *uri;
dbg!(item.is_mounted(), item.path());
(!item.is_mounted() && found).then(|| *k)
})
})
.or(if found {
None
} else {
// TODO do we need to choose the correct mounter?
self.mounter_items.iter().map(|(k, _)| *k).next()
})
{
if let Some(mounter) = MOUNTERS.get(&key) {
dbg!(&location);
// TODO can we detect an error and handle failure?
let location = location.clone();
return mounter.network_drive(uri.clone()).map(move |_| {
cosmic::Action::App(Message::NetworkDriveOpenEntityAfterMount {
entity,
})
});
}
}
Err(err) => {
log::warn!("failed to open favorite for path: {:?}, {}", path, err);
self.dialog_pages.push_back(DialogPage::FavoritePathError {
path: path.clone(),
entity,
});
false
log::warn!("failed to open favorite, path does not exist: {:?}", path);
self.dialog_pages.push_back(DialogPage::FavoritePathError {
path: path.clone(),
entity,
});
false
}
Location::Path(path) | Location::Network(_, _, Some(path)) => {
match path.try_exists() {
Ok(true) => true,
Ok(false) => {
log::warn!("failed to open favorite, path does not exist: {:?}", path);
self.dialog_pages.push_back(DialogPage::FavoritePathError {
path: path.clone(),
entity,
});
false
}
Err(err) => {
log::warn!("failed to open favorite for path: {:?}, {}", path, err);
self.dialog_pages.push_back(DialogPage::FavoritePathError {
path: path.clone(),
entity,
});
false
}
}
},
}
_ => true,
};
dbg!(should_open);
if should_open {
let message = Message::TabMessage(None, tab::Message::Location(location.clone()));
return self.update(message);
}
}
if let Some(data) = self.nav_model.data::<MounterData>(entity) {
if let Some(mounter) = MOUNTERS.get(&data.0) {
return mounter
@ -2296,10 +2417,45 @@ impl Application for App {
match message {
Message::AddToSidebar(entity_opt) => {
let mut favorites = self.config.favorites.clone();
// check if the selected entity is in the current tab
// else just use the selected entity and check its location
let entity = entity_opt.unwrap_or_else(|| self.tab_model.active());
for path in self.selected_paths(entity_opt) {
let favorite = Favorite::from_path(path);
dbg!(&path);
let is_network = self.tab_model.data::<Tab>(entity).and_then(|tab| {
let in_current_tab =
tab.location.path_opt().zip(path.parent()).is_some_and(
|(t_path, parent)| {
dbg!(&parent, &t_path);
parent == t_path
},
);
let tab = if in_current_tab {
self.tab_model
.data::<Tab>(self.tab_model.active())
.unwrap_or(tab)
} else {
tab
};
dbg!(in_current_tab, &tab.location);
let name = Location::Path(path.clone()).title();
if let Location::Network(uri, _, _) = tab.location.clone() {
Some((uri, name, path.clone()))
} else {
None
}
});
dbg!(&is_network);
let name = Location::Path(path.clone()).title();
let favorite = if let Some((uri, _, _)) = is_network.clone() {
Favorite::Network { uri, name, path }
} else {
Favorite::from_path(path)
};
if !favorites.iter().any(|f| f == &favorite) {
favorites.push(favorite);
dbg!(&favorites);
}
}
config_set!(favorites, favorites);
@ -2991,6 +3147,7 @@ impl Application for App {
Message::OpenInNewTab(entity_opt) => {
return Task::batch(self.selected_paths(entity_opt).into_iter().filter_map(
|path| {
dbg!(&path);
if path.is_dir() {
Some(self.open_tab(Location::Path(path), false, None))
} else {
@ -3510,6 +3667,7 @@ impl Application for App {
config.show_hidden = !config.show_hidden;
return self.update(Message::TabConfig(config));
}
Message::TabMessage(entity_opt, tab_message) => {
let entity = entity_opt.unwrap_or_else(|| self.tab_model.active());
@ -3528,6 +3686,7 @@ impl Application for App {
for tab_command in tab_commands {
match tab_command {
tab::Command::Action(action) => {
dbg!(&action);
commands.push(self.update(action.message(Some(entity))));
}
tab::Command::AddNetworkDrive => {
@ -3535,6 +3694,7 @@ impl Application for App {
self.set_show_context(true);
}
tab::Command::AddToSidebar(path) => {
dbg!("add to sidebar");
let mut favorites = self.config.favorites.clone();
let favorite = Favorite::from_path(path);
if !favorites.iter().any(|f| f == &favorite) {
@ -3580,6 +3740,7 @@ impl Application for App {
}
tab::Command::OpenFile(paths) => self.open_file(&paths),
tab::Command::OpenInNewTab(path) => {
dbg!(&path);
commands.push(self.open_tab(Location::Path(path.clone()), false, None));
}
tab::Command::OpenInNewWindow(path) => match env::current_exe() {
@ -4037,14 +4198,15 @@ impl Application for App {
}
NavMenuAction::OpenInNewTab(entity) => {
match self.nav_model.data::<Location>(entity) {
Some(Location::Network(ref uri, ref display_name)) => {
Some(Location::Network(ref uri, ref display_name, path)) => {
return self.open_tab(
Location::Network(uri.clone(), display_name.clone()),
Location::Network(uri.clone(), display_name.clone(), path.clone()),
false,
None,
);
}
Some(Location::Path(ref path)) => {
dbg!(path);
return self.open_tab(Location::Path(path.clone()), false, None);
}
Some(Location::Recents) => {
@ -4304,6 +4466,13 @@ impl Application for App {
Message::DragId(id) => {
return window::drag(id);
}
Message::NetworkDriveOpenEntityAfterMount { entity } => {
return self.on_nav_select(entity);
}
Message::NetworkDriveOpenTabAfterMount { location } => {
dbg!("location");
return self.open_tab(location, false, None);
}
}
Task::none()
@ -5880,6 +6049,7 @@ pub(crate) mod test_utils {
nested: usize,
name_len: usize,
) -> io::Result<(TempDir, Tab)> {
dbg!("new tab...");
let fs = simple_fs(files, hidden, dirs, nested, name_len)?;
let path = fs.path();