diff --git a/src/app/browser/window/tab/item.rs b/src/app/browser/window/tab/item.rs index 24e46cc1..85987fa3 100644 --- a/src/app/browser/window/tab/item.rs +++ b/src/app/browser/window/tab/item.rs @@ -63,6 +63,7 @@ impl Item { )); target_child.append(&page.navigation.g_box); + target_child.append(&page.notice); target_child.append(&page.content.g_box); target_child.append(&page.search.g_box); target_child.append(&page.input.clamp); diff --git a/src/app/browser/window/tab/item/client/driver/gemini.rs b/src/app/browser/window/tab/item/client/driver/gemini.rs index 15237450..f8f51d23 100644 --- a/src/app/browser/window/tab/item/client/driver/gemini.rs +++ b/src/app/browser/window/tab/item/client/driver/gemini.rs @@ -260,6 +260,9 @@ fn handle( _ => panic!() // unexpected } }; + if let Some(notice) = widget.meta.notice { + page.notice(¬ice) + } page.search.set(Some(widget.text_view)); page.set_title(&match widget.meta.title { Some(title) => title.into(), // @TODO diff --git a/src/app/browser/window/tab/item/page.rs b/src/app/browser/window/tab/item/page.rs index 72e4befb..a95f5b80 100644 --- a/src/app/browser/window/tab/item/page.rs +++ b/src/app/browser/window/tab/item/page.rs @@ -3,14 +3,16 @@ mod database; mod error; mod input; mod navigation; +mod notice; mod search; use super::{Action as ItemAction, BrowserAction, Profile, TabAction, WindowAction}; -use adw::TabPage; +use adw::{Banner, TabPage}; use content::Content; use error::Error; use input::Input; use navigation::Navigation; +use notice::Notice; use search::Search; use sqlite::Transaction; use std::rc::Rc; @@ -23,9 +25,10 @@ pub struct Page { pub window_action: Rc, // Components pub content: Rc, - pub search: Rc, pub input: Rc, pub navigation: Rc, + pub notice: Banner, + pub search: Rc, // System /// Reference to [TabPage](https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.TabPage.html) /// wanted to update title, loading status and other features related with page. @@ -56,6 +59,7 @@ impl Page { (window_action, tab_action, item_action), )); let input = Rc::new(Input::new()); + let notice = Banner::notice(); // Done Self { @@ -67,9 +71,10 @@ impl Page { window_action: window_action.clone(), // Components content, - search, input, navigation, + notice, + search, } } @@ -99,6 +104,11 @@ impl Page { self.search.show() } + /// Toggle `Notice` widget + pub fn notice(&self, title: &str) { + self.notice.show(title) + } + /// Cleanup session for `Self` pub fn clean( &self, diff --git a/src/app/browser/window/tab/item/page/content/text.rs b/src/app/browser/window/tab/item/page/content/text.rs index 968bf440..66497897 100644 --- a/src/app/browser/window/tab/item/page/content/text.rs +++ b/src/app/browser/window/tab/item/page/content/text.rs @@ -12,6 +12,7 @@ use std::rc::Rc; pub struct Meta { pub title: Option, + pub notice: Option, } // @TODO move to separated mod pub struct Text { @@ -27,7 +28,15 @@ impl Text { gemtext: &str, ) -> Self { // Init gemtext reader - let gemini = Gemini::build(actions, base, gemtext).unwrap(); // @TODO handle + let (gemini, notice) = match Gemini::build(actions, base, gemtext) { + Ok(gemini) => (gemini, None), + Err(e) => { + let notice = e.message(); + match e { + gemini::Error::Multiline(gemini) => (gemini, Some(notice)), + } + } + }; // Init container widget let clamp_scrollable = ClampScrollable::builder() @@ -42,6 +51,7 @@ impl Text { text_view: gemini.text_view, meta: Meta { title: gemini.title, + notice, }, scrolled_window: ScrolledWindow::builder().child(&clamp_scrollable).build(), } @@ -60,7 +70,10 @@ impl Text { Self { scrolled_window: ScrolledWindow::builder().child(&clamp_scrollable).build(), text_view, - meta: Meta { title: None }, + meta: Meta { + title: None, + notice: None, + }, } } @@ -69,7 +82,10 @@ impl Text { Self { scrolled_window: ScrolledWindow::builder().child(&source).build(), text_view: source.into_text_view(), - meta: Meta { title: None }, + meta: Meta { + title: None, + notice: None, + }, } } } diff --git a/src/app/browser/window/tab/item/page/content/text/gemini.rs b/src/app/browser/window/tab/item/page/content/text/gemini.rs index ac70950b..b7f60f48 100644 --- a/src/app/browser/window/tab/item/page/content/text/gemini.rs +++ b/src/app/browser/window/tab/item/page/content/text/gemini.rs @@ -234,7 +234,7 @@ impl Gemini { // Skip other actions for this line continue; } - Err(e) => return Err(Error::Gemtext(e.to_string())), + Err(_) => todo!(), } } } @@ -502,6 +502,10 @@ impl Gemini { }); // @TODO may be expensive for CPU, add timeout? // Result - Ok(Self { text_view, title }) + if is_multiline_enabled { + Ok(Self { text_view, title }) + } else { + Err(Error::Multiline(Self { text_view, title })) + } } } diff --git a/src/app/browser/window/tab/item/page/content/text/gemini/error.rs b/src/app/browser/window/tab/item/page/content/text/gemini/error.rs index 2a9f75cc..aa4cd8b0 100644 --- a/src/app/browser/window/tab/item/page/content/text/gemini/error.rs +++ b/src/app/browser/window/tab/item/page/content/text/gemini/error.rs @@ -1,15 +1,12 @@ -use std::fmt::{Display, Formatter, Result}; - -#[derive(Debug)] pub enum Error { - Gemtext(String), + Multiline(super::Gemini), } -impl Display for Error { - fn fmt(&self, f: &mut Formatter) -> Result { +impl Error { + pub fn message(&self) -> String { match self { - Self::Gemtext(e) => { - write!(f, "Gemtext error: {e}") + Self::Multiline(_) => { + "Invalid multiline markup! Gemtext format partially ignored.".to_string() } } } diff --git a/src/app/browser/window/tab/item/page/notice.rs b/src/app/browser/window/tab/item/page/notice.rs new file mode 100644 index 00000000..70e71153 --- /dev/null +++ b/src/app/browser/window/tab/item/page/notice.rs @@ -0,0 +1,24 @@ +use adw::Banner; + +pub trait Notice { + fn notice() -> Self; + fn show(&self, title: &str); +} + +impl Notice for Banner { + // Constructors + + /// Create new `Self` + fn notice() -> Self { + let banner = Banner::builder().button_label("Ok").revealed(false).build(); + banner.connect_button_clicked(|this| this.set_revealed(false)); + banner + } + + // Actions + + fn show(&self, title: &str) { + self.set_title(title); + self.set_revealed(true); + } +}