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, } impl File { // Constructors /// Create new `Self` pub fn init(page: &Rc) -> Self { Self { page: page.clone() } // @TODO } pub fn handle( &self, uri: Uri, feature: Rc, 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) + '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()), }) } }) }