mirror of
https://github.com/YGGverse/Yoda.git
synced 2026-03-31 16:45:27 +00:00
implement file handlers
This commit is contained in:
parent
93da67aa7e
commit
8a4689fc0a
1 changed files with 139 additions and 36 deletions
|
|
@ -1,5 +1,9 @@
|
||||||
use super::{Feature, Page};
|
use super::{Feature, Page};
|
||||||
use gtk::{gio::Cancellable, glib::Uri};
|
use gtk::{
|
||||||
|
gio::Cancellable,
|
||||||
|
glib::{GString, Uri},
|
||||||
|
};
|
||||||
|
use sourceview::prelude::FileExt;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
/// Local files client driver
|
/// Local files client driver
|
||||||
|
|
@ -15,49 +19,148 @@ impl File {
|
||||||
Self { page: page.clone() } // @TODO
|
Self { page: page.clone() } // @TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle(&self, uri: Uri, _feature: Rc<Feature>, cancellable: Cancellable) {
|
pub fn handle(&self, uri: Uri, feature: Rc<Feature>, cancellable: Cancellable) {
|
||||||
use gtk::{
|
use gtk::{
|
||||||
gio::{File, FileQueryInfoFlags, FileType},
|
gio::{File, FileQueryInfoFlags, FileType},
|
||||||
glib::Priority,
|
glib::Priority,
|
||||||
prelude::FileExtManual,
|
prelude::FileExtManual,
|
||||||
};
|
};
|
||||||
|
|
||||||
// try handle as file
|
let url = uri.to_string();
|
||||||
File::for_uri(&uri.to_string()).load_contents_async(Some(&cancellable), {
|
|
||||||
let cancellable = cancellable.clone();
|
match File::for_uri(&url).query_file_type(FileQueryInfoFlags::NONE, Some(&cancellable)) {
|
||||||
let uri = uri.clone();
|
FileType::Directory => File::for_uri(&url).enumerate_children_async(
|
||||||
let _page = self.page.clone();
|
"standard::content-type",
|
||||||
move |result| match result {
|
FileQueryInfoFlags::NONE,
|
||||||
Ok(_) => todo!(),
|
Priority::DEFAULT,
|
||||||
// is not a file, try handle as directory
|
Some(&cancellable),
|
||||||
Err(_) => File::for_uri(&uri.to_string()).enumerate_children_async(
|
|result| match result {
|
||||||
"standard::content-type",
|
Ok(file_enumerator) => {
|
||||||
FileQueryInfoFlags::NONE,
|
for entry in file_enumerator {
|
||||||
Priority::DEFAULT,
|
match entry {
|
||||||
Some(&cancellable),
|
Ok(file_info) => match file_info.file_type() {
|
||||||
|result| match result {
|
FileType::Unknown => todo!(),
|
||||||
Ok(file_enumerator) => {
|
FileType::Regular => todo!(),
|
||||||
for entry in file_enumerator {
|
FileType::Directory => todo!(),
|
||||||
match entry {
|
FileType::SymbolicLink => todo!(),
|
||||||
Ok(file_info) => match file_info.file_type() {
|
FileType::Special => todo!(),
|
||||||
FileType::Unknown => todo!(),
|
FileType::Shortcut => todo!(),
|
||||||
FileType::Regular => todo!(),
|
FileType::Mountable => todo!(),
|
||||||
FileType::Directory => todo!(),
|
_ => todo!(),
|
||||||
FileType::SymbolicLink => todo!(),
|
},
|
||||||
FileType::Special => todo!(),
|
Err(_) => todo!(),
|
||||||
FileType::Shortcut => todo!(),
|
|
||||||
FileType::Mountable => todo!(),
|
|
||||||
_ => todo!(),
|
|
||||||
},
|
|
||||||
Err(_) => todo!(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Err(_) => todo!(),
|
Err(_) => todo!(),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
_ => {
|
||||||
|
if url.ends_with(".gmi") || url.ends_with(".gemini") {
|
||||||
|
if matches!(*feature, Feature::Source) {
|
||||||
|
text_source(&self.page, uri, cancellable)
|
||||||
|
} else {
|
||||||
|
text_gemini(&self.page, uri, cancellable)
|
||||||
|
}
|
||||||
|
} else if url.ends_with(".txt") {
|
||||||
|
text_plain(&self.page, uri, cancellable)
|
||||||
|
} else if !url.ends_with("/") {
|
||||||
|
text_gemini(&self.page, uri, cancellable)
|
||||||
|
} else {
|
||||||
|
status_failure(&self.page, "Unsupported content type")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tools
|
||||||
|
|
||||||
|
/// Handle as `text/source`
|
||||||
|
fn text_source(page: &Rc<Page>, uri: Uri, cancellable: Cancellable) {
|
||||||
|
load_contents_async(&uri.to_string(), cancellable, {
|
||||||
|
let page = page.clone();
|
||||||
|
let uri = uri.clone();
|
||||||
|
move |data| text(page, uri, Text::Source(data))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handle as `text/gemini`
|
||||||
|
fn text_gemini(page: &Rc<Page>, uri: Uri, cancellable: Cancellable) {
|
||||||
|
load_contents_async(&uri.to_string(), cancellable, {
|
||||||
|
let page = page.clone();
|
||||||
|
let uri = uri.clone();
|
||||||
|
move |data| text(page, uri, Text::Gemini(data))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handle as `text/plain`
|
||||||
|
fn text_plain(page: &Rc<Page>, uri: Uri, cancellable: Cancellable) {
|
||||||
|
load_contents_async(&uri.to_string(), cancellable, {
|
||||||
|
let page = page.clone();
|
||||||
|
let uri = uri.clone();
|
||||||
|
move |data| text(page, uri, Text::Plain(data))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handle as failure status page
|
||||||
|
fn status_failure(page: &Rc<Page>, message: &str) {
|
||||||
|
let status = page.content.to_status_failure();
|
||||||
|
status.set_description(Some(message));
|
||||||
|
page.set_title(&status.title());
|
||||||
|
page.set_progress(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_contents_async(
|
||||||
|
url: &str,
|
||||||
|
cancellable: Cancellable,
|
||||||
|
on_success: impl FnOnce(String) + 'static,
|
||||||
|
) {
|
||||||
|
use gtk::prelude::FileExtManual;
|
||||||
|
gtk::gio::File::for_uri(url).load_contents_async(Some(&cancellable), {
|
||||||
|
move |result| match result {
|
||||||
|
Ok((ref buffer, _)) => match String::from_utf8(buffer.to_vec()) {
|
||||||
|
Ok(data) => on_success(data),
|
||||||
|
Err(_) => todo!(),
|
||||||
|
},
|
||||||
|
Err(_) => todo!(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Text {
|
||||||
|
Gemini(String),
|
||||||
|
Plain(String),
|
||||||
|
Source(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handle as text
|
||||||
|
fn text(page: Rc<Page>, uri: Uri, text: Text) {
|
||||||
|
let widget = match text {
|
||||||
|
Text::Gemini(data) => page.content.to_text_gemini(&uri, &data),
|
||||||
|
Text::Plain(data) => page.content.to_text_plain(&data),
|
||||||
|
Text::Source(data) => page.content.to_text_source(&data),
|
||||||
|
};
|
||||||
|
page.search.set(Some(widget.text_view));
|
||||||
|
page.set_title(&match widget.meta.title {
|
||||||
|
Some(title) => title.into(), // @TODO
|
||||||
|
None => uri_to_title(&uri),
|
||||||
|
});
|
||||||
|
page.set_progress(0.0);
|
||||||
|
page.window_action.find.simple_action.set_enabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper function, extract readable title from [Uri](https://docs.gtk.org/glib/struct.Uri.html)
|
||||||
|
/// * useful as common placeholder when page title could not be detected
|
||||||
|
/// * this feature may be improved and moved outside @TODO
|
||||||
|
fn uri_to_title(uri: &Uri) -> GString {
|
||||||
|
let path = uri.path();
|
||||||
|
if path.split('/').last().unwrap_or_default().is_empty() {
|
||||||
|
match uri.host() {
|
||||||
|
Some(host) => host,
|
||||||
|
None => "Untitled".into(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue