-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: use_clipboard #18
Merged
Merged
Changes from 1 commit
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" | ||
} | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<RefCell<ClipboardContext>>, | ||
} | ||
|
||
impl UseClipboard { | ||
// Read from the clipboard | ||
pub fn get(&self) -> Result<String, ClipboardError> { | ||
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<Self, ClipboardError> { | ||
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<String, ClipboardError> { | ||
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::<Rc<RefCell<ClipboardContext>>>() | ||
.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); | ||
}*/ |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can remove the use_init method here by trying to read the context and then inserting the context at the root if we don't find it. Like the signals crate does here. Then you can just use use_clipboard directly without worrying about the context
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we though? Last I tried that, it didn't work in nested components. I think it got fixed on the master branch but not released. I might be wrong, I'll try it later
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nevermind, it seems to work just fine... weird 🤔 I'll revisit some of my hooks in freya then