implement local directory browser widget

This commit is contained in:
yggverse 2025-02-14 20:09:13 +02:00
parent 2a1f4a89ac
commit 7cd5555aa2
4 changed files with 131 additions and 27 deletions

View file

@ -1,3 +1,4 @@
mod directory;
mod image; mod image;
mod status; mod status;
mod text; mod text;
@ -20,10 +21,11 @@ impl File {
} }
pub fn handle(&self, uri: Uri, feature: Rc<Feature>, cancellable: Cancellable) { pub fn handle(&self, uri: Uri, feature: Rc<Feature>, cancellable: Cancellable) {
use directory::Directory;
use gtk::{ use gtk::{
gio::{File, FileQueryInfoFlags, FileType}, gio::{File, FileQueryInfoFlags, FileType},
glib::Priority, glib::Priority,
prelude::{FileExt, FileExtManual}, prelude::FileExt,
}; };
use image::Image; use image::Image;
use status::Status; use status::Status;
@ -34,32 +36,7 @@ impl File {
let page = self.page.clone(); let page = self.page.clone();
match file.query_file_type(FileQueryInfoFlags::NONE, Some(&cancellable)) { match file.query_file_type(FileQueryInfoFlags::NONE, Some(&cancellable)) {
FileType::Directory => file.enumerate_children_async( FileType::Directory => Directory { file }.handle(&page),
"standard::content-type",
FileQueryInfoFlags::NONE,
Priority::DEFAULT,
Some(&cancellable),
move |result| match result {
Ok(file_enumerator) => {
for entry in file_enumerator {
match entry {
Ok(file_info) => match file_info.file_type() {
FileType::Unknown => todo!(),
FileType::Regular => todo!(),
FileType::Directory => todo!(),
FileType::SymbolicLink => todo!(),
FileType::Special => todo!(),
FileType::Shortcut => todo!(),
FileType::Mountable => todo!(),
_ => todo!(),
},
Err(e) => Status::Failure(e.to_string()).handle(&page),
}
}
}
Err(e) => Status::Failure(e.to_string()).handle(&page),
},
),
_ => file.clone().query_info_async( _ => file.clone().query_info_async(
"standard::content-type", "standard::content-type",
FileQueryInfoFlags::NONE, FileQueryInfoFlags::NONE,

View file

@ -0,0 +1,14 @@
use gtk::{gio::File, prelude::FileExt};
pub struct Directory {
pub file: File,
}
impl Directory {
pub fn handle(&self, page: &super::Page) {
page.content.to_directory(&self.file);
page.set_title(&self.file.parse_name());
page.set_progress(0.0);
page.window_action.find.simple_action.set_enabled(false);
}
}

View file

@ -1,7 +1,9 @@
mod directory;
mod image; mod image;
mod status; mod status;
mod text; mod text;
use directory::Directory;
use image::Image; use image::Image;
use text::Text; use text::Text;
@ -129,6 +131,11 @@ impl Content {
text text
} }
pub fn to_directory(&self, file: &File) {
self.clean();
self.g_box.append(&Directory::for_file(file))
}
/// * system `source:` /// * system `source:`
pub fn to_text_source(&self, data: &str) -> Text { pub fn to_text_source(&self, data: &str) -> Text {
self.clean(); self.clean();

View file

@ -0,0 +1,106 @@
use gtk::{gio::File, ScrolledWindow};
pub struct Directory;
impl Directory {
// Constructors
pub fn for_file(file: &File) -> ScrolledWindow {
const ATTRIBUTES:&str = "standard::name,standard::display-name,standard::symbolic-icon,standard::size,standard::content-type";
ScrolledWindow::builder()
.child(
&adw::Clamp::builder()
.child(&{
let column_view = gtk::ColumnView::builder()
.model(
&gtk::SingleSelection::builder()
.model(
&gtk::DirectoryList::builder()
.file(file)
.attributes(ATTRIBUTES)
.build(),
)
.build(),
)
.build();
column_view.append_column(
&gtk::ColumnViewColumn::builder()
.title("Icon")
.factory(&{
use gtk::prelude::{BoxExt, Cast, ListItemExt, WidgetExt};
let factory = gtk::SignalListItemFactory::new();
factory.connect_bind(|_, this| {
use gtk::gio::FileType;
let list_item =
this.downcast_ref::<gtk::ListItem>().unwrap();
let image = gtk::Image::from_gicon(
&list_item
.item()
.unwrap()
.downcast_ref::<gtk::gio::FileInfo>()
.unwrap()
.symbolic_icon()
.unwrap(),
);
image.set_tooltip_text(
match list_item
.item()
.unwrap()
.downcast_ref::<gtk::gio::FileInfo>()
.unwrap()
.file_type()
{
FileType::Unknown => Some("Unknown"),
FileType::Regular => Some("File"),
FileType::Directory => Some("Directory"),
FileType::SymbolicLink => Some("SymbolicLink"),
FileType::Special => Some("Special"),
FileType::Shortcut => Some("Shortcut"),
FileType::Mountable => Some("Mountable"),
_ => None,
},
);
let container = gtk::Box::builder().build(); // prevents `gtk::Image` blur
container.append(&image);
list_item.set_child(Some(&container));
});
factory
})
.build(),
);
column_view.append_column(
&gtk::ColumnViewColumn::builder()
.expand(true)
.title("Name")
.factory(&{
let factory = gtk::SignalListItemFactory::new();
factory.connect_bind(|_, this| {
use gtk::prelude::{Cast, ListItemExt};
let list_item =
this.downcast_ref::<gtk::ListItem>().unwrap();
let item = list_item.item().unwrap();
let file_info =
item.downcast_ref::<gtk::gio::FileInfo>().unwrap();
list_item.set_child(Some(
&gtk::Label::builder()
.halign(gtk::Align::Start)
.ellipsize(gtk::pango::EllipsizeMode::Middle)
.label(file_info.display_name())
.tooltip_text(file_info.display_name())
.build(),
));
});
factory
})
.build(),
);
column_view
})
.css_classes(["view"])
.build(),
)
.vexpand(true)
.build()
}
}