Yoda/src/app/browser/window/tab/item/client/driver/file.rs
2026-03-08 03:02:00 +02:00

216 lines
10 KiB
Rust

mod directory;
mod image;
mod status;
mod text;
use super::{Feature, Page};
use gtk::{gio::Cancellable, glib::Uri};
use std::rc::Rc;
/// Local files client driver
pub struct File {
page: Rc<Page>,
}
impl File {
// Constructors
/// Create new `Self`
pub fn init(page: &Rc<Page>) -> Self {
Self { page: page.clone() } // @TODO
}
pub fn handle(
&self,
uri: Uri,
feature: Rc<Feature>,
cancellable: Cancellable,
is_snap_history: bool,
) {
use directory::Directory;
use gtk::{
gio::{File, FileQueryInfoFlags, FileType},
glib::Priority,
prelude::FileExt,
};
use image::Image;
use status::Status;
use text::Text;
{
let mut i = self.page.navigation.request.info.borrow_mut();
i.set_request(Some(uri.to_string()));
self.page.navigation.request.update_secondary_icon(&i)
}
let url = uri.to_string();
let file = File::for_uri(&url);
let page = self.page.clone();
match file.query_file_type(FileQueryInfoFlags::NONE, Some(&cancellable)) {
FileType::Directory => Directory { file }.handle(&page, is_snap_history),
_ => file.clone().query_info_async(
"standard::content-type,standard::size",
FileQueryInfoFlags::NONE,
Priority::DEFAULT,
Some(&cancellable.clone()),
move |result| match result {
Ok(file_info) => {
page.navigation
.request
.info
.borrow_mut()
.set_size(Some(file_info.size() as usize));
match file_info.content_type() {
Some(content_type) => {
{
page.navigation
.request
.info
.borrow_mut()
.set_mime(Some(content_type.to_string()));
}
match content_type.as_str() {
"text/gemini" => {
if matches!(*feature, Feature::Source) {
load_contents_async(file, cancellable, move |result| {
match result {
Ok(data) => {
Text::Source(uri, data).handle(&page)
}
Err(message) => {
Status::Failure(message).handle(&page)
}
}
})
} else {
load_contents_async(file, cancellable, move |result| {
match result {
Ok(data) => {
Text::Gemini(uri, data).handle(&page)
}
Err(message) => {
Status::Failure(message).handle(&page)
}
}
})
}
}
"text/plain" => {
if matches!(*feature, Feature::Source) {
load_contents_async(file, cancellable, move |result| {
match result {
Ok(data) => {
Text::Source(uri, data).handle(&page)
}
Err(message) => {
Status::Failure(message).handle(&page)
}
}
})
} else if url.ends_with(".txt") {
load_contents_async(file, cancellable, move |result| {
match result {
Ok(data) => {
Text::Plain(uri, data).handle(&page)
}
Err(message) => {
Status::Failure(message).handle(&page)
}
}
});
} else if url.ends_with(".md") || url.ends_with(".markdown")
{
load_contents_async(file, cancellable, move |result| {
match result {
Ok(data) => {
Text::Markdown(uri, data).handle(&page)
}
Err(message) => {
Status::Failure(message).handle(&page)
}
}
})
} else {
load_contents_async(file, cancellable, move |result| {
match result {
Ok(data) => {
Text::Gemini(uri, data).handle(&page)
}
Err(message) => {
Status::Failure(message).handle(&page)
}
}
})
}
}
"text/markdown" => {
if matches!(*feature, Feature::Source) {
load_contents_async(file, cancellable, move |result| {
match result {
Ok(data) => {
Text::Source(uri, data).handle(&page)
}
Err(message) => {
Status::Failure(message).handle(&page)
}
}
})
} else {
load_contents_async(file, cancellable, move |result| {
match result {
Ok(data) => {
Text::Markdown(uri, data).handle(&page)
}
Err(message) => {
Status::Failure(message).handle(&page)
}
}
})
}
}
"image/png" | "image/gif" | "image/jpeg" | "image/webp" => {
match gtk::gdk::Texture::from_file(&file) {
Ok(texture) => {
Image::Bitmap(uri, texture).handle(&page)
}
Err(e) => Status::Failure(e.to_string()).handle(&page),
}
}
mime => Status::Failure(format!(
"Content type `{mime}` yet not supported"
))
.handle(&page),
}
}
None => Status::Failure("Undetectable content type".to_string())
.handle(&page),
}
}
Err(e) => Status::Failure(e.to_string()).handle(&page),
},
),
}
}
}
// Tools
fn load_contents_async(
file: gtk::gio::File,
cancellable: Cancellable,
callback: impl FnOnce(Result<String, String>) + 'static,
) {
use gtk::prelude::FileExtManual;
file.load_contents_async(Some(&cancellable), {
move |result| {
callback(match result {
Ok((ref buffer, _)) => match String::from_utf8(buffer.to_vec()) {
Ok(data) => Ok(data),
Err(e) => Err(e.to_string()),
},
Err(e) => Err(e.to_string()),
})
}
})
}