From 39b509e1b253c1ab2cbc16a8c31d07e97108243e Mon Sep 17 00:00:00 2001 From: marc2332 Date: Sun, 15 Oct 2023 12:04:10 +0200 Subject: [PATCH 1/4] feat: use_clipboard --- examples/clipboard/Cargo.toml | 9 +++ examples/clipboard/src/main.rs | 51 ++++++++++++ src/clipboard/mod.rs | 142 ++++++++++++++------------------- 3 files changed, 118 insertions(+), 84 deletions(-) create mode 100644 examples/clipboard/Cargo.toml create mode 100644 examples/clipboard/src/main.rs diff --git a/examples/clipboard/Cargo.toml b/examples/clipboard/Cargo.toml new file mode 100644 index 0000000..bdb2257 --- /dev/null +++ b/examples/clipboard/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "clipboard" +version = "0.1.0" +edition = "2021" + +[dependencies] +dioxus-std = { path="../../", features = ["clipboard"] } +dioxus = "0.4" +dioxus-desktop = "0.4" diff --git a/examples/clipboard/src/main.rs b/examples/clipboard/src/main.rs new file mode 100644 index 0000000..77561a8 --- /dev/null +++ b/examples/clipboard/src/main.rs @@ -0,0 +1,51 @@ +use dioxus::prelude::*; +use dioxus_std::clipboard::{use_clipboard, use_init_clipboard}; + +fn main() { + dioxus_desktop::launch(app); +} + +fn app(cx: Scope) -> Element { + use_init_clipboard(cx); + let clipboard = use_clipboard(cx); + let text = use_state(cx, String::new); + + let oninput = |e: FormEvent | { + text.set(e.data.value.clone()); + }; + + let oncopy = { + to_owned![clipboard]; + move |_| { + match clipboard.set(text.get().clone()) { + Ok(_) => println!("Copied to clipboard: {}", text.get()), + Err(err) => println!("Error on copy: {err:?}") + } + } + }; + + let onpaste = move |_| { + match clipboard.get() { + Ok(contents) => { + println!("Pasted from clipboard: {contents}"); + text.set(contents); + }, + Err(err) => println!("Error on paste: {err:?}") + } + }; + + render!( + input { + oninput: oninput, + value: "{text}" + } + button { + onclick: oncopy, + "Copy" + } + button { + onclick: onpaste, + "Paste" + } + ) +} diff --git a/src/clipboard/mod.rs b/src/clipboard/mod.rs index 5bd98af..9f009a1 100644 --- a/src/clipboard/mod.rs +++ b/src/clipboard/mod.rs @@ -1,100 +1,74 @@ //! Provides a clipboard abstraction to access the target system's clipboard. use copypasta::{ClipboardContext, ClipboardProvider}; -use std::fmt; +use dioxus::prelude::{RefCell, ScopeState}; +use std::rc::Rc; -/// Contains the context for interacting with the clipboard. +pub fn use_init_clipboard(cx: &ScopeState) { + cx.use_hook(|| { + if let Ok(clipboard) = ClipboardContext::new() { + cx.provide_context(Rc::new(RefCell::new(clipboard))); + } + }); +} + +#[derive(Debug, PartialEq, Clone)] +pub enum ClipboardError { + FailedToRead, + FailedToSet, +} + +/// Handle to access the ClipboardContent. +#[derive(Clone)] +pub struct UseClipboard { + clipboard: Rc>, +} + +impl UseClipboard { + // Read from the clipboard + pub fn get(&self) -> Result { + self.clipboard + .borrow_mut() + .get_contents() + .map_err(|_| ClipboardError::FailedToRead) + } + + // Write to the clipboard + pub fn set(&self, contents: String) -> Result<(), ClipboardError> { + self.clipboard + .borrow_mut() + .set_contents(contents) + .map_err(|_| ClipboardError::FailedToSet) + } +} + +/// Access the clipboard. /// /// # Examples /// -/// ``` +/// ```no_run /// use dioxus_std; /// -/// // Access the clipboard abstraction -/// let mut clipboard = dioxus_std::clipboard::Clipboard::new().unwrap(); +/// // Initialize the clipboard +/// use_init_clipboard(cx); +/// +/// // Get a handle to the clipboard +/// let clipboard = use_clipboard(cx); /// -/// // Get clipboard content -/// if let Ok(content) = clipboard.get_content() { +/// // Read the clipboard content +/// if let Ok(content) = clipboard.get() { /// println!("{}", content); /// } /// -/// // Set clipboard content -/// clipboard.set_content("Hello, Dioxus!".to_string());; +/// // Write to the clipboard +/// clipboard.set("Hello, Dioxus!".to_string());; /// /// ``` -pub struct Clipboard { - ctx: ClipboardContext, -} - -impl Clipboard { - /// Creates a new struct to utilize the clipboard abstraction. - pub fn new() -> Result { - let ctx = match ClipboardContext::new() { - Ok(ctx) => ctx, - Err(e) => return Err(ClipboardError::FailedToInit(e.to_string())), - }; - - Ok(Self { ctx }) - } - - /// Provides a [`String`] of the target system's current clipboard content. - pub fn get_content(&mut self) -> Result { - match self.ctx.get_contents() { - Ok(content) => Ok(content), - Err(e) => Err(ClipboardError::FailedToFetchContent(e.to_string())), - } - } - - /// Set the clipboard's content to the provided [`String`] - pub fn set_content(&mut self, value: String) -> Result<(), ClipboardError> { - match self.ctx.set_contents(value) { - Ok(()) => Ok(()), - Err(e) => Err(ClipboardError::FailedToSetContent(e.to_string())), - } - } +pub fn use_clipboard(cx: &ScopeState) -> UseClipboard { + let clipboard = cx + .consume_context::>>() + .expect( + "Clipboard was not detected. Make sure you initialized it with 'use_init_clipboard'.", + ); + UseClipboard { clipboard } } - -/// Represents errors when utilizing the clipboard abstraction. -#[derive(Debug)] -pub enum ClipboardError { - /// Failure when initializing the clipboard. - FailedToInit(String), - /// Failure to retrieve clipboard content. - FailedToFetchContent(String), - /// Failure to set clipboard content. - FailedToSetContent(String), -} - -impl std::error::Error for ClipboardError {} -impl fmt::Display for ClipboardError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - ClipboardError::FailedToInit(s) => write!(f, "{}", s), - ClipboardError::FailedToFetchContent(s) => write!(f, "{}", s), - ClipboardError::FailedToSetContent(s) => write!(f, "{}", s), - } - } -} - -// Tests -// This doesn't work in CI. -/*#[test] -fn test_clipboard() { - let mut clipboard = Clipboard::new().unwrap(); - - // Preserve user's clipboard contents when testing - let initial_content = clipboard.get_content().unwrap(); - - // Set the content - let new_content = String::from("Hello, Dioxus!"); - clipboard.set_content(new_content.clone()).unwrap(); - - // Get the new content - let content = clipboard.get_content().unwrap(); - - // Return previous content - For some reason this only works if the test panics..? - clipboard.set_content(initial_content).unwrap(); - - // Check if the abstraction worked - assert_eq!(new_content, content); -}*/ From 7f9afdf4fa4d38c162c838ffa307faee7e899cc7 Mon Sep 17 00:00:00 2001 From: marc2332 Date: Thu, 26 Oct 2023 20:09:32 +0200 Subject: [PATCH 2/4] remove use_init_clipboard --- examples/clipboard/src/main.rs | 29 ++++++++++++----------------- src/clipboard/mod.rs | 20 +++++++------------- 2 files changed, 19 insertions(+), 30 deletions(-) diff --git a/examples/clipboard/src/main.rs b/examples/clipboard/src/main.rs index 77561a8..e3c7d68 100644 --- a/examples/clipboard/src/main.rs +++ b/examples/clipboard/src/main.rs @@ -1,37 +1,32 @@ use dioxus::prelude::*; -use dioxus_std::clipboard::{use_clipboard, use_init_clipboard}; +use dioxus_std::clipboard::use_clipboard; fn main() { dioxus_desktop::launch(app); } fn app(cx: Scope) -> Element { - use_init_clipboard(cx); let clipboard = use_clipboard(cx); let text = use_state(cx, String::new); - let oninput = |e: FormEvent | { + let oninput = |e: FormEvent| { text.set(e.data.value.clone()); }; let oncopy = { to_owned![clipboard]; - move |_| { - match clipboard.set(text.get().clone()) { - Ok(_) => println!("Copied to clipboard: {}", text.get()), - Err(err) => println!("Error on copy: {err:?}") - } + move |_| match clipboard.set(text.get().clone()) { + Ok(_) => println!("Copied to clipboard: {}", text.get()), + Err(err) => println!("Error on copy: {err:?}"), } }; - let onpaste = move |_| { - match clipboard.get() { - Ok(contents) => { - println!("Pasted from clipboard: {contents}"); - text.set(contents); - }, - Err(err) => println!("Error on paste: {err:?}") + let onpaste = move |_| match clipboard.get() { + Ok(contents) => { + println!("Pasted from clipboard: {contents}"); + text.set(contents); } + Err(err) => println!("Error on paste: {err:?}"), }; render!( @@ -40,11 +35,11 @@ fn app(cx: Scope) -> Element { value: "{text}" } button { - onclick: oncopy, + onclick: oncopy, "Copy" } button { - onclick: onpaste, + onclick: onpaste, "Paste" } ) diff --git a/src/clipboard/mod.rs b/src/clipboard/mod.rs index 9f009a1..367b279 100644 --- a/src/clipboard/mod.rs +++ b/src/clipboard/mod.rs @@ -4,14 +4,6 @@ use copypasta::{ClipboardContext, ClipboardProvider}; use dioxus::prelude::{RefCell, ScopeState}; use std::rc::Rc; -pub fn use_init_clipboard(cx: &ScopeState) { - cx.use_hook(|| { - if let Ok(clipboard) = ClipboardContext::new() { - cx.provide_context(Rc::new(RefCell::new(clipboard))); - } - }); -} - #[derive(Debug, PartialEq, Clone)] pub enum ClipboardError { FailedToRead, @@ -65,10 +57,12 @@ impl UseClipboard { /// /// ``` pub fn use_clipboard(cx: &ScopeState) -> UseClipboard { - let clipboard = cx - .consume_context::>>() - .expect( - "Clipboard was not detected. Make sure you initialized it with 'use_init_clipboard'.", - ); + let clipboard = match cx.consume_context() { + Some(rt) => rt, + None => { + let clipboard = ClipboardContext::new().expect("Cannot create Clipboard."); + cx.provide_root_context(Rc::new(RefCell::new(clipboard))) + } + }; UseClipboard { clipboard } } From 8bcae625c508d64ff37e20f779a5ce27b360c969 Mon Sep 17 00:00:00 2001 From: marc2332 Date: Thu, 26 Oct 2023 20:15:35 +0200 Subject: [PATCH 3/4] clean up --- src/clipboard/mod.rs | 69 +--------------------------------- src/clipboard/use_clipboard.rs | 65 ++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 67 deletions(-) create mode 100644 src/clipboard/use_clipboard.rs diff --git a/src/clipboard/mod.rs b/src/clipboard/mod.rs index 367b279..f51ee17 100644 --- a/src/clipboard/mod.rs +++ b/src/clipboard/mod.rs @@ -1,68 +1,3 @@ -//! Provides a clipboard abstraction to access the target system's clipboard. +mod use_clipboard; -use copypasta::{ClipboardContext, ClipboardProvider}; -use dioxus::prelude::{RefCell, ScopeState}; -use std::rc::Rc; - -#[derive(Debug, PartialEq, Clone)] -pub enum ClipboardError { - FailedToRead, - FailedToSet, -} - -/// Handle to access the ClipboardContent. -#[derive(Clone)] -pub struct UseClipboard { - clipboard: Rc>, -} - -impl UseClipboard { - // Read from the clipboard - pub fn get(&self) -> Result { - self.clipboard - .borrow_mut() - .get_contents() - .map_err(|_| ClipboardError::FailedToRead) - } - - // Write to the clipboard - pub fn set(&self, contents: String) -> Result<(), ClipboardError> { - self.clipboard - .borrow_mut() - .set_contents(contents) - .map_err(|_| ClipboardError::FailedToSet) - } -} - -/// Access the clipboard. -/// -/// # Examples -/// -/// ```no_run -/// use dioxus_std; -/// -/// // Initialize the clipboard -/// use_init_clipboard(cx); -/// -/// // Get a handle to the clipboard -/// let clipboard = use_clipboard(cx); -/// -/// // Read the clipboard content -/// if let Ok(content) = clipboard.get() { -/// println!("{}", content); -/// } -/// -/// // Write to the clipboard -/// clipboard.set("Hello, Dioxus!".to_string());; -/// -/// ``` -pub fn use_clipboard(cx: &ScopeState) -> UseClipboard { - let clipboard = match cx.consume_context() { - Some(rt) => rt, - None => { - let clipboard = ClipboardContext::new().expect("Cannot create Clipboard."); - cx.provide_root_context(Rc::new(RefCell::new(clipboard))) - } - }; - UseClipboard { clipboard } -} +pub use use_clipboard::*; diff --git a/src/clipboard/use_clipboard.rs b/src/clipboard/use_clipboard.rs new file mode 100644 index 0000000..23c127a --- /dev/null +++ b/src/clipboard/use_clipboard.rs @@ -0,0 +1,65 @@ +//! Provides a clipboard abstraction to access the target system's clipboard. + +use copypasta::{ClipboardContext, ClipboardProvider}; +use dioxus::prelude::{RefCell, ScopeState}; +use std::rc::Rc; + +#[derive(Debug, PartialEq, Clone)] +pub enum ClipboardError { + FailedToRead, + FailedToSet, +} + +/// Handle to access the ClipboardContext. +#[derive(Clone)] +pub struct UseClipboard { + clipboard: Rc>, +} + +impl UseClipboard { + // Read from the clipboard + pub fn get(&self) -> Result { + self.clipboard + .borrow_mut() + .get_contents() + .map_err(|_| ClipboardError::FailedToRead) + } + + // Write to the clipboard + pub fn set(&self, contents: String) -> Result<(), ClipboardError> { + self.clipboard + .borrow_mut() + .set_contents(contents) + .map_err(|_| ClipboardError::FailedToSet) + } +} + +/// Access the clipboard. +/// +/// # Examples +/// +/// ```no_run +/// use dioxus_std; +/// +/// // Get a handle to the clipboard +/// let clipboard = use_clipboard(cx); +/// +/// // Read the clipboard content +/// if let Ok(content) = clipboard.get() { +/// println!("{}", content); +/// } +/// +/// // Write to the clipboard +/// clipboard.set("Hello, Dioxus!".to_string());; +/// +/// ``` +pub fn use_clipboard(cx: &ScopeState) -> UseClipboard { + let clipboard = match cx.consume_context() { + Some(rt) => rt, + None => { + let clipboard = ClipboardContext::new().expect("Cannot create Clipboard."); + cx.provide_root_context(Rc::new(RefCell::new(clipboard))) + } + }; + UseClipboard { clipboard } +} From d6958caad2acf1c6ccf27c43d94baee5e1e9d45a Mon Sep 17 00:00:00 2001 From: marc2332 Date: Thu, 26 Oct 2023 20:30:28 +0200 Subject: [PATCH 4/4] clean up x2 --- src/clipboard/use_clipboard.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/clipboard/use_clipboard.rs b/src/clipboard/use_clipboard.rs index 23c127a..e90d631 100644 --- a/src/clipboard/use_clipboard.rs +++ b/src/clipboard/use_clipboard.rs @@ -38,8 +38,8 @@ impl UseClipboard { /// /// # Examples /// -/// ```no_run -/// use dioxus_std; +/// ```ignore +/// use dioxus_std::clipboard::use_clipboard; /// /// // Get a handle to the clipboard /// let clipboard = use_clipboard(cx);