Skip to content

Commit

Permalink
better error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
LegitCamper committed Oct 30, 2024
1 parent 95c427c commit 86df012
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 62 deletions.
32 changes: 16 additions & 16 deletions examples/embedded_webview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ fn main() -> iced::Result {
#[derive(Debug, Clone)]
enum Message {
WebView(Action),
ToggleWebviewVisibility,
ToggleWebview,
UrlChanged(String),
NewWebViewCreated,
WebviewCreated,
CreateWebview,
SwitchWebview,
CycleWebview,
}

struct App {
Expand All @@ -35,7 +35,7 @@ struct App {
impl App {
fn new() -> (Self, Task<Message>) {
let webview = WebView::new()
.on_create_view(Message::NewWebViewCreated)
.on_create_view(Message::WebviewCreated)
.on_url_change(Message::UrlChanged);
(
Self {
Expand All @@ -52,28 +52,27 @@ impl App {

fn update(&mut self, message: Message) -> Task<Message> {
match message {
Message::NewWebViewCreated => {
Message::WebView(msg) => self.webview.update(msg),
Message::CreateWebview => self
.webview
.update(Action::CreateView(PageType::Url(URL.to_string()))),
Message::WebviewCreated => {
if self.current_view == None {
self.current_view = Some(0);
// if its the first tab change to it, after that require switching manually
return Task::done(Action::ChangeView(0)).map(Message::WebView);
return Task::done(Message::CycleWebview);
}
self.num_views += 1;
Task::none()
}
Message::WebView(msg) => self.webview.update(msg),
Message::ToggleWebviewVisibility => {
Message::ToggleWebview => {
self.show_webview = !self.show_webview;
Task::none()
}
Message::UrlChanged(new_url) => {
self.webview_url = Some(new_url);
Task::none()
}
Message::CreateWebview => self
.webview
.update(Action::CreateView(PageType::Url(URL.to_string()))),
Message::SwitchWebview => {
Message::CycleWebview => {
if let Some(current_view) = self.current_view.as_mut() {
if *current_view + 1 > self.num_views {
*current_view = 0;
Expand All @@ -82,7 +81,8 @@ impl App {
};
self.webview.update(Action::ChangeView(*current_view))
} else {
Task::none()
self.current_view = Some(0);
self.webview.update(Action::ChangeView(0))
}
}
}
Expand All @@ -96,9 +96,9 @@ impl App {
"Iced docs can be pulled up inside an iced app?! Whoa!"
}),
container(row![
button("Toggle web view(s)").on_press(Message::ToggleWebviewVisibility),
button("Toggle web view(s)").on_press(Message::ToggleWebview),
button("New web view").on_press(Message::CreateWebview),
button("Switch views").on_press(Message::SwitchWebview),
button("Switch views").on_press(Message::CycleWebview),
])
.align_right(Length::Fill)
]];
Expand Down
19 changes: 14 additions & 5 deletions src/engines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ pub enum PixelFormat {
Bgra,
}

/// Result type for get_url, get_title, get_view, and get_cursor
/// This is because they can fail by the wrong id, and the requested view, may not be loaded yet
#[derive(Debug, Clone)]
pub enum EngineResult<T> {
IdDoesNotExist,
NotLoaded,
Success(T),
}

/// Alias of usize used for controlling specific views
/// Only used by advanced to get views, basic simply uses u32
pub type ViewId = usize;
Expand All @@ -35,7 +44,7 @@ pub trait Engine {
/// Can fail if requested id does not exist
fn remove_view(&mut self, id: ViewId) -> Option<()>;

// window changes - no id needed they work for all views
// window changes - no id needed they work for all views(gloabally)
fn focus(&mut self);
fn unfocus(&self);
fn resize(&mut self, size: Size<u32>);
Expand All @@ -59,13 +68,13 @@ pub trait Engine {
fn scroll(&mut self, id: ViewId, delta: mouse::ScrollDelta) -> Option<()>;

/// Can fail if requested id does not exist or page has not loaded and therfore has no url
fn get_url(&self, id: ViewId) -> Option<String>;
fn get_url(&self, id: ViewId) -> EngineResult<String>;
/// Can fail if requested id does not exist or page has not loaded and therfore has no title
fn get_title(&self, id: ViewId) -> Option<String>;
fn get_title(&self, id: ViewId) -> EngineResult<String>;
/// Can fail if requested id does not exist
fn get_view(&self, id: ViewId) -> Option<&ImageInfo>;
fn get_cursor(&self, id: ViewId) -> EngineResult<Interaction>;
/// Can fail if requested id does not exist
fn get_cursor(&self, id: ViewId) -> Option<Interaction>;
fn get_view(&self, id: ViewId) -> EngineResult<&ImageInfo>;
}

/// Allows users to create new views with url or custom html
Expand Down
54 changes: 38 additions & 16 deletions src/engines/ultralight.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@ use ul_next::{
Surface,
};

use super::{Engine, EngineResult, PageType, PixelFormat, ViewId};
use crate::ImageInfo;

use super::{Engine, PageType, PixelFormat, ViewId};

struct UlClipboard {
ctx: ClipboardContext,
}
Expand Down Expand Up @@ -386,26 +385,49 @@ impl Engine for Ultralight {
Some(())
}

fn get_url(&self, id: ViewId) -> Option<String> {
self.get_view(id)?.view.url().ok()
fn get_url(&self, id: ViewId) -> EngineResult<String> {
if let Some(view) = self.get_view(id) {
match view.view.url() {
Ok(url) => EngineResult::Success(url),
Err(_) => EngineResult::NotLoaded,
}
} else {
EngineResult::IdDoesNotExist
}
}

fn get_title(&self, id: ViewId) -> Option<String> {
self.get_view(id)?.view.title().ok()
fn get_title(&self, id: ViewId) -> EngineResult<String> {
if let Some(view) = self.get_view(id) {
match view.view.title() {
Ok(title) => EngineResult::Success(title),
Err(_) => EngineResult::NotLoaded,
}
} else {
EngineResult::IdDoesNotExist
}
}

fn get_view(&self, id: ViewId) -> Option<&ImageInfo> {
Some(&self.get_view(id)?.last_frame)
fn get_cursor(&self, id: ViewId) -> EngineResult<mouse::Interaction> {
if let Some(view) = self.get_view(id) {
match view.cursor.read() {
Ok(cursor) => EngineResult::Success(*cursor),
Err(_) => EngineResult::NotLoaded,
}
} else {
EngineResult::IdDoesNotExist
}
}

fn get_cursor(&self, id: ViewId) -> Option<mouse::Interaction> {
Some(
*self
.get_view(id)?
.cursor
.read()
.expect("Failed to get Ultraights cursor status"),
)
fn get_view(&self, id: ViewId) -> EngineResult<&ImageInfo> {
if let Some(view) = self.get_view(id) {
if self.get_view(id).unwrap().view.is_loading() {
EngineResult::NotLoaded
} else {
EngineResult::Success(&view.last_frame)
}
} else {
EngineResult::IdDoesNotExist
}
}
}

Expand Down
43 changes: 30 additions & 13 deletions src/webview/advanced.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use iced::{Element, Point, Size, Task};
use url::Url;

use crate::{engines, ImageInfo, PageType, ViewId};
use engines::EngineResult;

#[derive(Debug, Clone, PartialEq)]
pub enum Action {
Expand Down Expand Up @@ -99,7 +100,7 @@ impl<Engine: engines::Engine + Default, Message: Send + Clone + 'static> WebView
// Check url & title for changes and callback if so
for (id, url) in self.urls.iter_mut() {
if let Some(on_url_change) = &self.on_url_change {
if let Some(engine_url) = self.engine.get_url(*id) {
if let EngineResult::Success(engine_url) = self.engine.get_url(*id) {
if *url != engine_url {
*url = engine_url.clone();
tasks.push(Task::done(on_url_change(*id, engine_url)));
Expand All @@ -109,7 +110,7 @@ impl<Engine: engines::Engine + Default, Message: Send + Clone + 'static> WebView
}
for (id, title) in self.titles.iter_mut() {
if let Some(on_title_change) = &self.on_title_change {
if let Some(engine_title) = self.engine.get_title(*id) {
if let EngineResult::Success(engine_title) = self.engine.get_title(*id) {
if *title != engine_title {
*title = engine_title.clone();
tasks.push(Task::done(on_title_change(*id, engine_title)));
Expand Down Expand Up @@ -186,17 +187,33 @@ impl<Engine: engines::Engine + Default, Message: Send + Clone + 'static> WebView

/// Like a normal `view()` method in iced, but takes an id of the desired view
pub fn view(&self, id: usize) -> Element<Action> {
WebViewWidget::new(
id,
self.view_size,
self.engine
.get_view(id)
.expect("Failed to get view with that id"),
self.engine
.get_cursor(id)
.expect("Failed to get view with that id"),
)
.into()
let view = match self.engine.get_view(id) {
EngineResult::IdDoesNotExist => panic!("Requested Id does not exist"),
EngineResult::NotLoaded => {
return WebViewWidget::new(
id,
self.view_size,
&ImageInfo::default(),
Interaction::None,
)
.into()
}
EngineResult::Success(view) => view,
};
let cursor = match self.engine.get_cursor(id) {
EngineResult::IdDoesNotExist => panic!("Requested Id does not exist"),
EngineResult::NotLoaded => {
return WebViewWidget::new(
id,
self.view_size,
&ImageInfo::default(),
Interaction::None,
)
.into()
}
EngineResult::Success(cursor) => cursor,
};
WebViewWidget::new(id, self.view_size, view, cursor).into()
}
}

Expand Down
35 changes: 23 additions & 12 deletions src/webview/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use iced::{Element, Point, Size, Task};
use url::Url;

use crate::{engines, ImageInfo, PageType, ViewId};
use engines::EngineResult;

#[derive(Debug, Clone, PartialEq)]
pub enum Action {
Expand Down Expand Up @@ -127,15 +128,18 @@ impl<Engine: engines::Engine + Default, Message: Send + Clone + 'static> WebView

if self.current_view_index.is_some() {
if let Some(on_url_change) = &self.on_url_change {
if let Some(url) = self.engine.get_url(self.get_current_view_id()) {
if let EngineResult::Success(url) = self.engine.get_url(self.get_current_view_id())
{
if self.url != url {
self.url = url.clone();
tasks.push(Task::done(on_url_change(url)))
}
}
}
if let Some(on_title_change) = &self.on_title_change {
if let Some(title) = self.engine.get_title(self.get_current_view_id()) {
if let EngineResult::Success(title) =
self.engine.get_title(self.get_current_view_id())
{
if self.title != title {
self.title = title.clone();
tasks.push(Task::done(on_title_change(title)))
Expand Down Expand Up @@ -225,16 +229,23 @@ impl<Engine: engines::Engine + Default, Message: Send + Clone + 'static> WebView

/// Returns webview widget for the current view
pub fn view(&self) -> Element<Action> {
WebViewWidget::new(
self.view_size,
self.engine
.get_view(self.get_current_view_id())
.expect("failed to get view, because current view id does not exist"),
self.engine
.get_cursor(self.get_current_view_id())
.expect("failed to get view, because current view id does not exist"),
)
.into()
let view = match self.engine.get_view(self.get_current_view_id()) {
EngineResult::IdDoesNotExist => panic!("Requested Id does not exist"),
EngineResult::NotLoaded => {
return WebViewWidget::new(self.view_size, &ImageInfo::default(), Interaction::None)
.into()
}
EngineResult::Success(view) => view,
};
let cursor = match self.engine.get_cursor(self.get_current_view_id()) {
EngineResult::IdDoesNotExist => panic!("Requested Id does not exist"),
EngineResult::NotLoaded => {
return WebViewWidget::new(self.view_size, &ImageInfo::default(), Interaction::None)
.into()
}
EngineResult::Success(cursor) => cursor,
};
WebViewWidget::new(self.view_size, view, cursor).into()
}
}

Expand Down

0 comments on commit 86df012

Please sign in to comment.