]> uap-core.de Git - note.git/commitdiff
add webview preview to file notes
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Sat, 1 Aug 2026 07:34:46 +0000 (09:34 +0200)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Sat, 1 Aug 2026 07:34:46 +0000 (09:34 +0200)
Cargo.lock
application/note/Cargo.toml
application/note/src/file.rs
application/note/src/window.rs
ui-rs/src/ui/toolkit.rs
ui-rs/src/ui/webview.rs

index 9c387f4523e22af34d46f3f4e1ef2862f7b65ef7..8fe770825aba73e0e7c9b849bbc7086f88d7f5ad 100644 (file)
@@ -1581,6 +1581,7 @@ dependencies = [
  "sea-orm",
  "tokio",
  "ui-rs",
+ "url",
 ]
 
 [[package]]
index 4a7e28f42b378ef11ee4c606665298249b6c2647..5bd627c51484bb2b4a993db4efbb574c8c65519b 100644 (file)
@@ -10,3 +10,4 @@ ui-rs = { path = "../../ui-rs" }
 tokio = { version = "1.52.1", features = ["rt-multi-thread"] }
 sea-orm = { version = "2.0.0-rc", features = [ "sqlx-sqlite", "sqlx-postgres", "runtime-tokio-native-tls", "macros" ] }
 notify = "9.0.0-rc.4"
+url = "2"
index a84be063968bd81f9cb858cdafd218d602d796ed..bf357bbd17b0d5677023125acd4a411732266836 100644 (file)
@@ -29,6 +29,7 @@ use std::ffi::{OsStr};
 use std::mem;
 use std::path::{Path, PathBuf};
 use std::rc::Rc;
+use url::Url;
 use backend::backend::{BackendHandle, BroadcastMessage, NoteId, NoteTitleUpdate, OpenExternResult};
 use ui_rs::{action, doc_cast, ui_actions, UiModel};
 use ui_rs::ui::*;
@@ -61,6 +62,9 @@ pub struct FileNote {
 
     #[bind("filenote_image")]
     pub image: UiImage,
+
+    #[bind("filenote_webview")]
+    pub webview: UiWeb,
 }
 
 #[ui_actions]
@@ -82,6 +86,7 @@ impl FileNote {
             preview_tab: Default::default(),
             note_nodename: Default::default(),
             image: Default::default(),
+            webview: Default::default()
         }
     }
 
@@ -117,13 +122,21 @@ impl FileNote {
                             // TODO: implement better file type detection
                             //       idealy save content type in the note
                             match path.extension().and_then(OsStr::to_str) {
-                                Some("png") => {
+                                Some("png" | "jpeg" | "jpg" | "webp") => {
                                     let result = note.image.load_image_file(path.as_path());
                                     if result.is_ok() {
                                         // TODO: replace 1 with enum value
                                         note.preview_tab.set(1);
                                     }
                                 },
+                                Some("html" | "htm" | "pdf") => {
+                                    let url = Url::from_file_path(&path);
+                                    if let Ok(url) = url {
+                                        note.webview.load_url(url.as_str());
+                                        // TODO: replace 1 with enum value
+                                        note.preview_tab.set(2);
+                                    }
+                                }
                                 _ => {}
                             }
 
index 3e20493a1f88a2d89bcbaff66cad7142e043d8ec..2ca11a53e0ea0dcf2c51a847bd31663741a53d67 100644 (file)
@@ -28,7 +28,7 @@
 
 use std::any::Any;
 use backend::backend::{BackendHandle, BroadcastMessage, NoteId};
-use ui_rs::{action, button, grid, hbox, imageviewer, label, sourcelist, tableview, tabview, textarea, textfield, ui_actions, UiModel};
+use ui_rs::{action, button, grid, hbox, imageviewer, label, sourcelist, tableview, tabview, textarea, textfield, ui_actions, webview, UiModel};
 use ui_rs::ui::*;
 use crate::{App, AppStates};
 use entity::collection::{CollectionType, Model as Collection, Node};
@@ -284,6 +284,11 @@ pub fn create_window(app: &App, ctx: &AppContext<MainWindow>) -> UiObject<MainWi
                                         scrollview = true,
                                         autoscale = true);
                                 });
+                                tabview.tab("webview", |obj| {
+                                    webview!(obj,
+                                        varname = "filenote_webview",
+                                        fill = true);
+                                });
                             });
                         });
                     });
index 3e494db0865f8029f6e78c4f6733fa72a5095c9f..79a0d4df5be667245dae8c3aeab3c88640f3b27b 100644 (file)
@@ -732,6 +732,10 @@ pub struct UiImage {
     pub ptr: *mut ffi::UiGeneric
 }
 
+pub struct UiWeb {
+    pub ptr: *mut ffi::UiGeneric
+}
+
 /* -------------------------------- Default implementation -------------------------------- */
 
 macro_rules! value_default_impl {
@@ -758,6 +762,7 @@ value_default_impl!(UiInteger);
 value_default_impl!(UiDouble);
 value_default_impl!(UiString);
 value_default_impl!(UiImage);
+value_default_impl!(UiWeb);
 value_default_impl2!(UiText);
 
 impl<T> Default for UiList<T> {
index 1ddaa9de9080315e758e7b5600497f2681754b4f..8d572f7762b90016d672045f3d5ae620c5656198 100644 (file)
 
 #![allow(dead_code)]
 
+#[macro_export]
+macro_rules! webview {
+    ($parent:expr, $($tt:tt)*) => {
+        $crate::widget!($parent, webview, $($tt)*)
+    };
+}
+
+impl UiWeb {
+    pub fn init(&mut self, ctx: &UiContext, name: Option<&str>) {
+        let c_string = name.map(|n| CString::new(n).unwrap());
+        let c_str = c_string.as_ref().map_or(std::ptr::null(), |s| s.as_ptr());
+        unsafe {
+            self.ptr = toolkit::ui_generic_new(ctx.ptr, c_str);
+        }
+    }
+    
+    pub fn load_url(&self, url: &str) {
+        let cstr = CString::new(url).unwrap();
+        unsafe {
+            ui_webview_load_url(self.ptr, cstr.as_ptr());
+        }
+    }
+    
+    pub fn load_content(&self, uri: Option<&str>, content: &[u8], mimetype: Option<&str>, encoding: Option<&str>) {
+        let cstr_uri = uri.map(|n| CString::new(n).unwrap());
+        let uri_ptr = cstr_uri.as_ref().map_or(std::ptr::null(), |s| s.as_ptr());
+
+        let cstr_mime = mimetype.map(|n| CString::new(n).unwrap());
+        let mime_ptr = cstr_mime.as_ref().map_or(std::ptr::null(), |s| s.as_ptr());
+
+        let cstr_enc = encoding.map(|n| CString::new(n).unwrap());
+        let enc_ptr = cstr_enc.as_ref().map_or(std::ptr::null(), |s| s.as_ptr());
+        
+        unsafe {
+            ui_webview_load_content(self.ptr, uri_ptr, content.as_ptr().cast(), content.len() as libc::size_t, mime_ptr, enc_ptr);
+        }
+    }
+}
+
 pub struct WebView {
     ptr: *mut c_void
 }
@@ -163,7 +202,7 @@ impl<'a, T> WebViewBuilder<'a, T> {
         self
     }
 
-    pub fn value(&mut self, value: &toolkit::UiImage) -> &mut Self{
+    pub fn value(&mut self, value: &toolkit::UiWeb) -> &mut Self{
         unsafe {
             ui_webview_args_set_value(self.args, value.ptr);
         }
@@ -204,7 +243,7 @@ impl<T> toolkit::UiObject<T> {
 
 /* -------------------------------- C functions -------------------------------- */
 use std::ffi::{c_char, c_double, c_int, c_void, CString};
-use crate::ui::{ffi, toolkit};
+use crate::ui::{ffi, toolkit, UiContext, UiWeb};
 use crate::ui::ffi::UiWebviewArgs;
 use crate::ui::widget::Widget;
 
@@ -243,4 +282,13 @@ unsafe extern "C" {
     fn ui_webview_args_set_states(args: *mut UiWebviewArgs, states: *const c_int, numstates: c_int);
     fn ui_webview_args_set_visibility_states(args: *mut UiWebviewArgs, states: *const c_int, numstates: c_int);
     fn ui_webview_args_free(args: *mut UiWebviewArgs);
+
+    fn ui_webview_load_url(obj: *mut ffi::UiGeneric, url: *const c_char);
+    fn ui_webview_load_content(
+            obj: *mut ffi::UiGeneric,
+            uri: *const c_char,
+            content: *const c_char,
+            contentlen: libc::size_t,
+            mimetype: *const c_char,
+            encoding: *const c_char);
 }