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

1
Cargo.lock generated
View file

@ -1482,6 +1482,7 @@ dependencies = [
name = "cosmic-files"
version = "0.1.0"
dependencies = [
"anyhow",
"bzip2",
"chrono",
"compio",

View file

@ -10,6 +10,7 @@ rust-version = "1.85.0"
vergen = { version = "8", features = ["git", "gitcl"] }
[dependencies]
anyhow = "1"
chrono = { version = "0.4", features = ["unstable-locales"] }
icu = { version = "1.5.0", features = [
"experimental",

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();

View file

@ -64,6 +64,11 @@ pub enum Favorite {
Pictures,
Videos,
Path(PathBuf),
Network {
uri: String,
name: String,
path: PathBuf,
},
}
impl Favorite {
@ -95,6 +100,7 @@ impl Favorite {
Self::Pictures => dirs::picture_dir(),
Self::Videos => dirs::video_dir(),
Self::Path(path) => Some(path.clone()),
Self::Network { path, .. } => Some(path.clone()),
}
}
}

View file

@ -107,7 +107,7 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
} else if &arg == "--recents" {
Location::Recents
} else if &arg == "--network" {
Location::Network("network:///".to_string(), fl!("networks"))
Location::Network("network:///".to_string(), fl!("networks"), None)
} else {
//TODO: support more URLs
let path = match url::Url::parse(&arg) {

View file

@ -152,7 +152,11 @@ pub fn context_menu<'a>(
match (&tab.mode, &tab.location) {
(
tab::Mode::App | tab::Mode::Desktop,
Location::Desktop(..) | Location::Path(..) | Location::Search(..) | Location::Recents,
Location::Desktop(..)
| Location::Path(..)
| Location::Search(..)
| Location::Recents
| Location::Network(_, _, Some(_)),
) => {
if selected_trash_only {
children.push(menu_item(fl!("open"), Action::Open).into());
@ -298,7 +302,11 @@ pub fn context_menu<'a>(
}
(
tab::Mode::Dialog(dialog_kind),
Location::Desktop(..) | Location::Path(..) | Location::Search(..) | Location::Recents,
Location::Desktop(..)
| Location::Path(..)
| Location::Search(..)
| Location::Recents
| Location::Network(_, _, Some(_)),
) => {
if selected > 0 {
if selected_dir == 1 && selected == 1 || selected_dir == 0 {
@ -327,6 +335,7 @@ pub fn context_menu<'a>(
}
}
(_, Location::Network(..)) => {
dbg!(selected, &tab.mode);
if selected > 0 {
if selected_dir == 1 && selected == 1 || selected_dir == 0 {
children.push(menu_item(fl!("open"), Action::Open).into());

View file

@ -3,7 +3,13 @@ use cosmic::{
widget, Task,
};
use gio::{glib, prelude::*};
use std::{any::TypeId, cell::Cell, future::pending, path::PathBuf, sync::Arc};
use std::{
any::TypeId,
cell::Cell,
future::pending,
path::{Path, PathBuf},
sync::Arc,
};
use tokio::sync::{mpsc, Mutex};
use super::{Mounter, MounterAuth, MounterItem, MounterItems, MounterMessage};
@ -30,6 +36,7 @@ fn items(monitor: &gio::VolumeMonitor, sizes: IconSizes) -> MounterItems {
let mut items = MounterItems::new();
for (i, mount) in monitor.mounts().into_iter().enumerate() {
items.push(MounterItem::Gvfs(Item {
uri: MountExt::root(&mount).uri().to_string(),
kind: ItemKind::Mount,
index: i,
name: MountExt::name(&mount).to_string(),
@ -44,7 +51,12 @@ fn items(monitor: &gio::VolumeMonitor, sizes: IconSizes) -> MounterItems {
// Volumes with mounts are already listed by mount
continue;
}
let uri = VolumeExt::activation_root(&volume)
.map(|f| f.uri().to_string())
.unwrap_or_default();
items.push(MounterItem::Gvfs(Item {
// TODO can we get URI for volumes with no mount?
uri,
kind: ItemKind::Volume,
index: i,
name: VolumeExt::name(&volume).to_string(),
@ -57,7 +69,11 @@ fn items(monitor: &gio::VolumeMonitor, sizes: IconSizes) -> MounterItems {
items
}
fn network_scan(uri: &str, sizes: IconSizes) -> Result<Vec<tab::Item>, String> {
fn network_scan(
uri: &str,
sizes: IconSizes,
path: Option<&Path>,
) -> Result<Vec<tab::Item>, String> {
let file = gio::File::for_uri(uri);
let mut items = Vec::new();
for info_res in file
@ -77,6 +93,7 @@ fn network_scan(uri: &str, sizes: IconSizes) -> Result<Vec<tab::Item>, String> {
file.child(info.name()).uri().to_string()
},
display_name.clone(),
file.child(info.name()).path(),
);
//TODO: support dir or file
@ -193,11 +210,15 @@ fn mount_op(uri: String, event_tx: mpsc::UnboundedSender<Event>) -> gio::MountOp
enum Cmd {
Items(IconSizes, mpsc::Sender<MounterItems>),
Rescan,
Mount(MounterItem),
NetworkDrive(String),
Mount(
MounterItem,
tokio::sync::oneshot::Sender<anyhow::Result<()>>,
),
NetworkDrive(String, tokio::sync::oneshot::Sender<anyhow::Result<()>>),
NetworkScan(
String,
IconSizes,
Option<PathBuf>,
mpsc::Sender<Result<Vec<tab::Item>, String>>,
),
Unmount(MounterItem),
@ -220,6 +241,7 @@ enum ItemKind {
//TODO: better method of matching items
#[derive(Clone, Debug)]
pub struct Item {
uri: String,
kind: ItemKind,
index: usize,
name: String,
@ -238,6 +260,10 @@ impl Item {
self.is_mounted
}
pub fn uri(&self) -> String {
self.uri.clone()
}
pub fn icon(&self, symbolic: bool) -> Option<widget::icon::Handle> {
if symbolic {
self.icon_symbolic_opt.as_ref()
@ -318,9 +344,15 @@ impl Gvfs {
Cmd::Rescan => {
event_tx.send(Event::Items(items(&monitor, IconSizes::default()))).unwrap();
}
Cmd::Mount(mounter_item) => {
let MounterItem::Gvfs(ref item) = mounter_item else { continue };
let ItemKind::Volume = item.kind else { continue };
Cmd::Mount(mounter_item, complete_tx) => {
let MounterItem::Gvfs(ref item) = mounter_item else {
_ = complete_tx.send(Err(anyhow::anyhow!("No mounter item")));
continue
};
let ItemKind::Volume = item.kind else {
_ = complete_tx.send(Err(anyhow::anyhow!("No mounter volume")));
continue
};
for (i, volume) in monitor.volumes().into_iter().enumerate() {
if i != item.index {
continue;
@ -345,17 +377,23 @@ impl Gvfs {
move |res| {
log::info!("mount {}: result {:?}", name, res);
event_tx.send(Event::MountResult(mounter_item, match res {
Ok(()) => Ok(true),
Err(err) => match err.kind::<gio::IOErrorEnum>() {
Ok(()) => {
_ = complete_tx.send(Ok(()));
Ok(true)
},
Err(err) => {
_ = complete_tx.send(Err(anyhow::anyhow!("{err:?}")));
match err.kind::<gio::IOErrorEnum>() {
Some(gio::IOErrorEnum::FailedHandled) => Ok(false),
_ => Err(format!("{}", err))
}
}}
})).unwrap();
},
);
break;
}
}
Cmd::NetworkDrive(uri) => {
Cmd::NetworkDrive(uri, result_tx) => {
let file = gio::File::for_uri(&uri);
let mount_op = mount_op(uri.clone(), event_tx.clone());
let event_tx = event_tx.clone();
@ -366,16 +404,20 @@ impl Gvfs {
move |res| {
log::info!("network drive {}: result {:?}", uri, res);
event_tx.send(Event::NetworkResult(uri, match res {
Ok(()) => Ok(true),
Err(err) => match err.kind::<gio::IOErrorEnum>() {
Ok(()) => {
_ = result_tx.send(Ok(()));
Ok(true)},
Err(err) => {
_ = result_tx.send(Err(anyhow::anyhow!("{err:?}")));
match err.kind::<gio::IOErrorEnum>() {
Some(gio::IOErrorEnum::FailedHandled) => Ok(false),
_ => Err(format!("{}", err))
}
}}
})).unwrap();
}
);
}
Cmd::NetworkScan(uri, sizes, items_tx) => {
Cmd::NetworkScan(uri, sizes, path, items_tx) => {
let file = gio::File::for_uri(&uri);
let needs_mount = match file.find_enclosing_mount(gio::Cancellable::NONE) {
Ok(_) => false,
@ -468,9 +510,16 @@ impl Mounter for Gvfs {
let command_tx = self.command_tx.clone();
Task::perform(
async move {
command_tx.send(Cmd::Mount(item)).unwrap();
let (res_tx, res_rx) = tokio::sync::oneshot::channel();
command_tx.send(Cmd::Mount(item, res_tx)).unwrap();
res_rx.await
},
|x| {
if let Err(err) = x {
log::error!("{err:?}");
}
},
|x| x,
)
}
@ -478,16 +527,33 @@ impl Mounter for Gvfs {
let command_tx = self.command_tx.clone();
Task::perform(
async move {
command_tx.send(Cmd::NetworkDrive(uri)).unwrap();
let (res_tx, res_rx) = tokio::sync::oneshot::channel();
command_tx.send(Cmd::NetworkDrive(uri, res_tx)).unwrap();
res_rx.await
},
|x| {
if let Err(err) = x {
log::error!("{err:?}");
}
},
|x| x,
)
}
fn network_scan(&self, uri: &str, sizes: IconSizes) -> Option<Result<Vec<tab::Item>, String>> {
fn network_scan(
&self,
uri: &str,
sizes: IconSizes,
path: Option<&Path>,
) -> Option<Result<Vec<tab::Item>, String>> {
let (items_tx, mut items_rx) = mpsc::channel(1);
self.command_tx
.send(Cmd::NetworkScan(uri.to_string(), sizes, items_tx))
.send(Cmd::NetworkScan(
uri.to_string(),
sizes,
path.map(|p| p.to_owned()),
items_tx,
))
.unwrap();
items_rx.blocking_recv()
}

View file

@ -1,6 +1,11 @@
use cosmic::{iced::Subscription, widget, Task};
use once_cell::sync::Lazy;
use std::{collections::BTreeMap, fmt, path::PathBuf, sync::Arc};
use std::{
collections::BTreeMap,
fmt,
path::{Path, PathBuf},
sync::Arc,
};
use tokio::sync::mpsc;
use crate::{config::IconSizes, tab};
@ -55,6 +60,14 @@ impl MounterItem {
}
}
pub fn uri(&self) -> String {
match self {
#[cfg(feature = "gvfs")]
Self::Gvfs(item) => item.uri(),
Self::None => unreachable!(),
}
}
pub fn is_mounted(&self) -> bool {
match self {
#[cfg(feature = "gvfs")]
@ -95,7 +108,12 @@ pub trait Mounter: Send + Sync {
//TODO: send result
fn mount(&self, item: MounterItem) -> Task<()>;
fn network_drive(&self, uri: String) -> Task<()>;
fn network_scan(&self, uri: &str, sizes: IconSizes) -> Option<Result<Vec<tab::Item>, String>>;
fn network_scan(
&self,
uri: &str,
sizes: IconSizes,
path: Option<&Path>,
) -> Option<Result<Vec<tab::Item>, String>>;
fn unmount(&self, item: MounterItem) -> Task<()>;
fn subscription(&self) -> Subscription<MounterMessage>;
}

View file

@ -1205,9 +1205,9 @@ pub fn scan_recents(sizes: IconSizes) -> Vec<Item> {
recents.into_iter().take(50).map(|(item, _)| item).collect()
}
pub fn scan_network(uri: &str, sizes: IconSizes) -> Vec<Item> {
pub fn scan_network(uri: &str, sizes: IconSizes, path: Option<&Path>) -> Vec<Item> {
for (_key, mounter) in MOUNTERS.iter() {
match mounter.network_scan(uri, sizes) {
match mounter.network_scan(uri, sizes, path) {
Some(Ok(items)) => return items,
Some(Err(err)) => {
log::warn!("failed to scan {:?}: {}", uri, err);
@ -1361,7 +1361,7 @@ impl From<Location> for EditLocation {
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum Location {
Desktop(PathBuf, String, DesktopConfig),
Network(String, String),
Network(String, String, Option<PathBuf>),
Path(PathBuf),
Recents,
Search(PathBuf, String, bool, Instant),
@ -1413,6 +1413,7 @@ impl Location {
Self::Desktop(path, ..) => Some(path),
Self::Path(path) => Some(path),
Self::Search(path, ..) => Some(path),
Self::Network(_, _, path) => path.as_ref(),
_ => None,
}
}
@ -1426,6 +1427,8 @@ impl Location {
Self::Search(_, term, show_hidden, time) => {
Self::Search(path, term.clone(), *show_hidden, *time)
}
Self::Network(id, name, path) => Self::Network(id.clone(), name.clone(), path.clone()),
other => other.clone(),
}
}
@ -1442,7 +1445,7 @@ impl Location {
}
Self::Trash => scan_trash(sizes),
Self::Recents => scan_recents(sizes),
Self::Network(uri, _) => scan_network(uri, sizes),
Self::Network(uri, _, path) => scan_network(uri, sizes, path.as_deref()),
};
let parent_item_opt = match self.path_opt() {
Some(path) => match item_from_path(path, sizes) {
@ -1479,7 +1482,7 @@ impl Location {
Self::Recents => {
fl!("recents")
}
Self::Network(_uri, display_name) => display_name.clone(),
Self::Network(display_name, ..) => display_name.clone(),
}
}
}
@ -3033,6 +3036,7 @@ impl Tab {
}
if !item.selected {
self.clicked = click_i_opt;
dbg!(&item.location_opt);
item.selected = true;
}
self.select_range = Some((i, i));
@ -3133,6 +3137,7 @@ impl Tab {
}
LocationMenuAction::AddToSidebar(ancestor_index) => {
if let Some(path) = path_for_index(ancestor_index) {
dbg!(&path);
commands.push(Command::AddToSidebar(path));
} else {
log::warn!(
@ -4512,13 +4517,14 @@ impl Tab {
.into(),
);
}
Location::Network(uri, display_name) => {
Location::Network(uri, display_name, path) => {
children.push(
widget::button::custom(widget::text::heading(display_name))
.padding(space_xxxs)
.on_press(Message::Location(Location::Network(
uri.clone(),
display_name.clone(),
path.clone(),
)))
.class(theme::Button::Text)
.into(),
@ -5421,7 +5427,7 @@ impl Tab {
}
}
}
Location::Network(uri, _display_name) if uri == "network:///" => {
Location::Network(uri, _display_name, path) if uri == "network:///" => {
tab_column = tab_column.push(
widget::layer_container(widget::row::with_children(vec![
widget::horizontal_space().into(),