examples: webview and async
This commit is contained in:
1 parent
99d94b69ab
commit
eb82051000
13 files changed
+355
-57
No files matched your search
Vendored
+1
@@ -61,3 +61,4 @@ wasm
|
|||||||
attr
|
attr
|
||||||
derefed
|
derefed
|
||||||
Tokio
|
Tokio
|
||||||
|
asynchronicity
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
//! Example: README.md showcase
|
||||||
|
//!
|
||||||
|
//! The example from the README.md
|
||||||
|
|
||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
use futures::Future;
|
||||||
|
fn main() {
|
||||||
|
dioxus::web::launch(App)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize)]
|
||||||
|
struct DogApi {
|
||||||
|
message: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
const ENDPOINT: &str = "https://dog.ceo/api/breeds/image/random";
|
||||||
|
|
||||||
|
static App: FC<()> = |cx| {
|
||||||
|
// let mut count = use_state(cx, || 0);
|
||||||
|
let mut fut = cx.use_hook(
|
||||||
|
move || {
|
||||||
|
Box::pin(async {
|
||||||
|
//
|
||||||
|
loop {
|
||||||
|
// repeatadly get new doggos
|
||||||
|
match surf::get(ENDPOINT).recv_json::<DogApi>().await {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(_) => (),
|
||||||
|
// Ok(res) => rsx!(in cx, img { src: "{res.message}" }),
|
||||||
|
// Err(_) => rsx!(in cx, div { "No doggos for you :(" }),
|
||||||
|
}
|
||||||
|
// wait one seconds
|
||||||
|
}
|
||||||
|
}) as Pin<Box<dyn Future<Output = ()> + 'static>>
|
||||||
|
},
|
||||||
|
|h| h,
|
||||||
|
|_| {},
|
||||||
|
);
|
||||||
|
|
||||||
|
cx.submit_task(fut);
|
||||||
|
|
||||||
|
todo!()
|
||||||
|
// cx.render(rsx! {
|
||||||
|
// div {
|
||||||
|
// h1 { "Hifive counter: {count}" }
|
||||||
|
// button { onclick: move |_| count += 1, "Up high!" }
|
||||||
|
// button { onclick: move |_| count -= 1, "Down low!" }
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
};
|
||||||
|
|
||||||
|
// #[derive(serde::Deserialize)]
|
||||||
|
// struct DogApi {
|
||||||
|
// message: String,
|
||||||
|
// }
|
||||||
|
// const ENDPOINT: &str = "https://dog.ceo/api/breeds/image/random";
|
||||||
|
|
||||||
|
// pub static App: FC<()> = |cx| {
|
||||||
|
// let doggo = use_future_effect(&cx, move || async move {
|
||||||
|
// match surf::get(ENDPOINT).recv_json::<DogApi>().await {
|
||||||
|
// Ok(res) => rsx!(in cx, img { src: "{res.message}" }),
|
||||||
|
// Err(_) => rsx!(in cx, div { "No doggos for you :(" }),
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
// cx.render(rsx!(
|
||||||
|
// div {
|
||||||
|
// h1 {"Waiting for a doggo..."}
|
||||||
|
// {doggo}
|
||||||
|
// }
|
||||||
|
// ))
|
||||||
|
// };
|
||||||
+9
-7
@@ -4,15 +4,17 @@
|
|||||||
|
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
fn main() {
|
fn main() {
|
||||||
dioxus::web::launch(Example)
|
dioxus::web::launch(App)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Example(cx: Context<()>) -> VNode {
|
static App: FC<()> = |cx| {
|
||||||
let name = use_state(cx, || "..?");
|
let mut count = use_state(cx, || 0);
|
||||||
|
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
h1 { "Hello, {name}" }
|
div {
|
||||||
button { "?", onclick: move |_| name.set("world!")}
|
h1 { "Hifive counter: {count}" }
|
||||||
button { "?", onclick: move |_| name.set("Dioxus 🎉")}
|
button { onclick: move |_| count += 1, "Up high!" }
|
||||||
|
button { onclick: move |_| count -= 1, "Down low!" }
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
};
|
||||||
+44
-10
@@ -16,9 +16,9 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static App: FC<()> = |cx| {
|
static App: FC<()> = |cx| {
|
||||||
let slide_id = use_state(cx, || 0);
|
let slides = use_state(cx, SlideController::new);
|
||||||
|
|
||||||
let slide = match *slide_id {
|
let slide = match slides.slide_id {
|
||||||
0 => cx.render(rsx!(Title {})),
|
0 => cx.render(rsx!(Title {})),
|
||||||
1 => cx.render(rsx!(Slide1 {})),
|
1 => cx.render(rsx!(Slide1 {})),
|
||||||
2 => cx.render(rsx!(Slide2 {})),
|
2 => cx.render(rsx!(Slide2 {})),
|
||||||
@@ -28,12 +28,15 @@ static App: FC<()> = |cx| {
|
|||||||
|
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div {
|
div {
|
||||||
|
style: {
|
||||||
|
background_color: "red"
|
||||||
|
}
|
||||||
div {
|
div {
|
||||||
div { h1 {"my awesome slideshow"} }
|
div { h1 {"my awesome slideshow"} }
|
||||||
div {
|
div {
|
||||||
button {"<-", onclick: move |_| if *slide_id != 0 { *slide_id.get_mut() -= 1}}
|
button {"<-", onclick: move |_| slides.get_mut().go_forward()}
|
||||||
h3 { "{slide_id}" }
|
h3 { "{slides.slide_id}" }
|
||||||
button {"->" onclick: move |_| if *slide_id != 4 { *slide_id.get_mut() += 1 }}
|
button {"->" onclick: move |_| slides.get_mut().go_backward()}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{slide}
|
{slide}
|
||||||
@@ -41,38 +44,69 @@ static App: FC<()> = |cx| {
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct SlideController {
|
||||||
|
slide_id: isize,
|
||||||
|
}
|
||||||
|
impl SlideController {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self { slide_id: 0 }
|
||||||
|
}
|
||||||
|
fn can_go_forward(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
fn can_go_backward(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
fn go_forward(&mut self) {
|
||||||
|
if self.can_go_forward() {
|
||||||
|
self.slide_id += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn go_backward(&mut self) {
|
||||||
|
if self.can_go_backward() {
|
||||||
|
self.slide_id -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const Title: FC<()> = |cx| {
|
const Title: FC<()> = |cx| {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div {
|
div {
|
||||||
|
h1 { "Title" }
|
||||||
|
p {}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
const Slide1: FC<()> = |cx| {
|
const Slide1: FC<()> = |cx| {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div {
|
div {
|
||||||
|
h1 { "Slide1" }
|
||||||
|
p {}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
const Slide2: FC<()> = |cx| {
|
const Slide2: FC<()> = |cx| {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div {
|
div {
|
||||||
|
h1 { "Slide2" }
|
||||||
|
p {}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
const Slide3: FC<()> = |cx| {
|
const Slide3: FC<()> = |cx| {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div {
|
div {
|
||||||
|
h1 { "Slide3" }
|
||||||
|
p {}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
const End: FC<()> = |cx| {
|
const End: FC<()> = |cx| {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div {
|
div {
|
||||||
|
h1 { "End" }
|
||||||
|
p {}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# Suspense, Async, and More
|
||||||
|
|
||||||
|
This doc goes into the design of asynchronicity in Dioxus.
|
||||||
|
|
||||||
|
|
||||||
|
## for UI elements
|
||||||
|
|
||||||
|
`suspend`-ing a future submits an &mut future to Dioxus. the future must return VNodes. the future is still waiting before the component renders, the `.await` is dropped and tried again. users will want to attach their future to a hook so the future doesn't really get dropped.
|
||||||
|
|
||||||
|
|
||||||
|
## for tasks
|
||||||
|
|
||||||
|
for more general tasks, we need some way of submitting a future or task into some sort of task system.
|
||||||
|
|
||||||
|
|
||||||
|
`use_task()` submits a future to Dioxus. the future is polled infinitely until it finishes. The caller of `use_task` may drop, pause, restart, or insert a new the task
|
||||||
|
|
||||||
|
```rust
|
||||||
|
|
||||||
|
let task = use_hook(|| {
|
||||||
|
// create the future
|
||||||
|
}, || {
|
||||||
|
update the future if it needs to be updated
|
||||||
|
}, || {
|
||||||
|
|
||||||
|
});
|
||||||
|
cx.poll_future()
|
||||||
|
// let recoil_event_loop = cx.use_task(move |_| async move {
|
||||||
|
// loop {
|
||||||
|
// let msg = receiver.await?;
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// where suspend wraps use_task
|
||||||
|
```
|
||||||
+18
-9
@@ -1,14 +1,14 @@
|
|||||||
- [] Move the builder API onto NodeFactory
|
- [x] Move the builder API onto NodeFactory
|
||||||
- [] Transition away from names and towards compile-time safe tags
|
- [x] Transition away from names and towards compile-time safe tags
|
||||||
- [] Fix diffing of fragments
|
- [x] Fix diffing of fragments
|
||||||
- [] Properly integrate memoization to prevent safety issues with children
|
- [x] Properly integrate memoization to prevent safety issues with children
|
||||||
- [] Understand and fix the issue with callbacks (outdated generations)
|
- [x] Understand and fix the issue with callbacks (outdated generations)
|
||||||
- [] Fix examples for core, web, ssr, and general
|
- [x] Fix examples for core, web, ssr, and general
|
||||||
- [] Finish up documentation
|
- [] Finish up documentation
|
||||||
- [] Polish the Recoil (Dirac?) API
|
- [] Polish the Recoil (Dirac?) API
|
||||||
- [] Find better names for things
|
- [x] Find better names for things
|
||||||
- [] get the html macro up to parity with the rsx! macro
|
- [] get the html macro up to parity with the rsx! macro
|
||||||
- [] put warnings in for iterating w/o keys
|
- [x] put warnings in for iterating w/o keys
|
||||||
- [] finish up the crate for generating code blocks
|
- [] finish up the crate for generating code blocks
|
||||||
- [] make progress on the docusarus-style crate for generating the websites
|
- [] make progress on the docusarus-style crate for generating the websites
|
||||||
- [] build the docsite
|
- [] build the docsite
|
||||||
@@ -17,4 +17,13 @@
|
|||||||
- [] Implement controlled inputs for select and textarea
|
- [] Implement controlled inputs for select and textarea
|
||||||
- [] ...somehow... noderefs....
|
- [] ...somehow... noderefs....
|
||||||
|
|
||||||
use_state(cx, )
|
- [x] soup of the use_state hook
|
||||||
|
- [ ] wire up inline css
|
||||||
|
- [ ] compile-time correct inline CSS
|
||||||
|
- [ ] signals
|
||||||
|
- [ ] cooperative scheduler
|
||||||
|
- [ ] suspense
|
||||||
|
- [ ] task system
|
||||||
|
- [] wire up events for webview
|
||||||
|
- [] JIT for class-based style engines
|
||||||
|
- []
|
||||||
@@ -41,6 +41,8 @@ slotmap = "1.0.3"
|
|||||||
futures = "0.3.15"
|
futures = "0.3.15"
|
||||||
|
|
||||||
|
|
||||||
|
async-std = { version="1.9.0", features=["attributes"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["serialize"]
|
default = ["serialize"]
|
||||||
# default = []
|
# default = []
|
||||||
|
|||||||
@@ -149,9 +149,9 @@ pub mod on {
|
|||||||
|
|
||||||
$(
|
$(
|
||||||
$(#[$method_attr])*
|
$(#[$method_attr])*
|
||||||
pub fn $name<'a>(
|
pub fn $name<'a, F: FnMut($wrapper) + 'a>(
|
||||||
c: NodeFactory<'a>,
|
c: NodeFactory<'a>,
|
||||||
mut callback: impl FnMut($wrapper) + 'a,
|
mut callback: F,
|
||||||
) -> Listener<'a> {
|
) -> Listener<'a> {
|
||||||
let bump = &c.bump();
|
let bump = &c.bump();
|
||||||
Listener {
|
Listener {
|
||||||
|
|||||||
@@ -401,7 +401,7 @@ pub struct Scope {
|
|||||||
// NEEDS TO BE PRIVATE
|
// NEEDS TO BE PRIVATE
|
||||||
pub(crate) listeners: RefCell<Vec<(*mut Cell<RealDomNode>, *mut dyn FnMut(VirtualEvent))>>,
|
pub(crate) listeners: RefCell<Vec<(*mut Cell<RealDomNode>, *mut dyn FnMut(VirtualEvent))>>,
|
||||||
|
|
||||||
pub(crate) suspended_tasks: Vec<Box<dyn Future<Output = VNode<'static>>>>,
|
pub(crate) suspended_tasks: Vec<*mut Pin<Box<dyn Future<Output = VNode<'static>>>>>,
|
||||||
// pub(crate) listeners: RefCell<nohash_hasher::IntMap<u32, *const dyn FnMut(VirtualEvent)>>,
|
// pub(crate) listeners: RefCell<nohash_hasher::IntMap<u32, *const dyn FnMut(VirtualEvent)>>,
|
||||||
// pub(crate) listeners: RefCell<Vec<*const dyn FnMut(VirtualEvent)>>,
|
// pub(crate) listeners: RefCell<Vec<*const dyn FnMut(VirtualEvent)>>,
|
||||||
// pub(crate) listeners: RefCell<Vec<*const dyn FnMut(VirtualEvent)>>,
|
// pub(crate) listeners: RefCell<Vec<*const dyn FnMut(VirtualEvent)>>,
|
||||||
@@ -871,8 +871,27 @@ Any function prefixed with "use" should not be called conditionally.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `submit_task` will submit the future to be polled.
|
||||||
|
/// Dioxus will step its internal event loop if the future returns if the future completes while waiting.
|
||||||
|
///
|
||||||
|
/// Tasks can't return anything, but they can be controlled with the returned handle
|
||||||
|
///
|
||||||
|
/// Tasks will only run until the component renders again. If you want your task to last longer than one frame, you'll need
|
||||||
|
/// to store it somehow.
|
||||||
|
///
|
||||||
|
pub fn submit_task(
|
||||||
|
&self,
|
||||||
|
task: &'src mut Pin<Box<dyn Future<Output = ()> + 'static>>,
|
||||||
|
) -> TaskHandle {
|
||||||
|
// the pointer to the task is stable - we guarantee stability of all &'src references
|
||||||
|
let task_ptr = task as *mut _;
|
||||||
|
|
||||||
|
TaskHandle {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct TaskHandle {}
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SuspendedContext {}
|
pub struct SuspendedContext {}
|
||||||
|
|
||||||
|
|||||||
@@ -9,17 +9,32 @@ use dioxus_core::{
|
|||||||
};
|
};
|
||||||
use DomEdit::*;
|
use DomEdit::*;
|
||||||
|
|
||||||
|
pub struct WebviewRegistry {}
|
||||||
|
|
||||||
|
impl WebviewRegistry {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct WebviewDom<'bump> {
|
pub struct WebviewDom<'bump> {
|
||||||
pub edits: Vec<DomEdit<'bump>>,
|
pub edits: Vec<DomEdit<'bump>>,
|
||||||
pub node_counter: u64,
|
pub node_counter: u64,
|
||||||
|
pub registry: WebviewRegistry,
|
||||||
}
|
}
|
||||||
impl WebviewDom<'_> {
|
impl WebviewDom<'_> {
|
||||||
pub fn new() -> Self {
|
pub fn new(registry: WebviewRegistry) -> Self {
|
||||||
Self {
|
Self {
|
||||||
edits: Vec::new(),
|
edits: Vec::new(),
|
||||||
node_counter: 0,
|
node_counter: 0,
|
||||||
|
registry,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Finish using the dom (for its edit list) and give back the node and event registry
|
||||||
|
pub fn consume(self) -> WebviewRegistry {
|
||||||
|
self.registry
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl<'bump> RealDom<'bump> for WebviewDom<'bump> {
|
impl<'bump> RealDom<'bump> for WebviewDom<'bump> {
|
||||||
fn push_root(&mut self, root: dioxus_core::virtual_dom::RealDomNode) {
|
fn push_root(&mut self, root: dioxus_core::virtual_dom::RealDomNode) {
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
use std::fmt::{self, Write};
|
||||||
|
|
||||||
|
/// Escape a string to pass it into JavaScript.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rust,no_run
|
||||||
|
/// # use web_view::WebView;
|
||||||
|
/// # use std::mem;
|
||||||
|
/// #
|
||||||
|
/// # let mut view: WebView<()> = unsafe { mem::uninitialized() };
|
||||||
|
/// #
|
||||||
|
/// let string = "Hello, world!";
|
||||||
|
///
|
||||||
|
/// // Calls the function callback with "Hello, world!" as its parameter.
|
||||||
|
///
|
||||||
|
/// view.eval(&format!("callback({});", web_view::escape(string)));
|
||||||
|
/// ```
|
||||||
|
pub fn escape(string: &str) -> Escaper {
|
||||||
|
Escaper(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// "All code points may appear literally in a string literal except for the
|
||||||
|
// closing quote code points, U+005C (REVERSE SOLIDUS), U+000D (CARRIAGE
|
||||||
|
// RETURN), U+2028 (LINE SEPARATOR), U+2029 (PARAGRAPH SEPARATOR), and U+000A
|
||||||
|
// (LINE FEED)." - ES6 Specification
|
||||||
|
|
||||||
|
pub struct Escaper<'a>(&'a str);
|
||||||
|
|
||||||
|
const SPECIAL: &[char] = &[
|
||||||
|
'\n', // U+000A (LINE FEED)
|
||||||
|
'\r', // U+000D (CARRIAGE RETURN)
|
||||||
|
'\'', // U+0027 (APOSTROPHE)
|
||||||
|
'\\', // U+005C (REVERSE SOLIDUS)
|
||||||
|
'\u{2028}', // U+2028 (LINE SEPARATOR)
|
||||||
|
'\u{2029}', // U+2029 (PARAGRAPH SEPARATOR)
|
||||||
|
];
|
||||||
|
|
||||||
|
impl<'a> fmt::Display for Escaper<'a> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let &Escaper(mut string) = self;
|
||||||
|
|
||||||
|
f.write_char('\'')?;
|
||||||
|
|
||||||
|
while !string.is_empty() {
|
||||||
|
if let Some(i) = string.find(SPECIAL) {
|
||||||
|
if i > 0 {
|
||||||
|
f.write_str(&string[..i])?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut chars = string[i..].chars();
|
||||||
|
|
||||||
|
f.write_str(match chars.next().unwrap() {
|
||||||
|
'\n' => "\\n",
|
||||||
|
'\r' => "\\r",
|
||||||
|
'\'' => "\\'",
|
||||||
|
'\\' => "\\\\",
|
||||||
|
'\u{2028}' => "\\u2028",
|
||||||
|
'\u{2029}' => "\\u2029",
|
||||||
|
_ => unreachable!(),
|
||||||
|
})?;
|
||||||
|
|
||||||
|
string = chars.as_str();
|
||||||
|
} else {
|
||||||
|
f.write_str(string)?;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f.write_char('\'')?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test() {
|
||||||
|
let plain = "ABC \n\r' abc \\ \u{2028} \u{2029}123";
|
||||||
|
let escaped = escape(plain).to_string();
|
||||||
|
assert!(escaped == "'ABC \\n\\r\\' abc \\\\ \\u2028 \\u2029123'");
|
||||||
|
}
|
||||||
@@ -5,9 +5,6 @@
|
|||||||
<!-- <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet" /> -->
|
<!-- <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet" /> -->
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div></div>
|
<div></div>
|
||||||
</body>
|
</body>
|
||||||
@@ -16,7 +13,9 @@
|
|||||||
class Interpreter {
|
class Interpreter {
|
||||||
constructor(root) {
|
constructor(root) {
|
||||||
this.stack = [root];
|
this.stack = [root];
|
||||||
this.listeners = {};
|
this.listeners = {
|
||||||
|
|
||||||
|
};
|
||||||
this.lastNodeWasText = false;
|
this.lastNodeWasText = false;
|
||||||
this.nodes = {
|
this.nodes = {
|
||||||
0: root
|
0: root
|
||||||
|
|||||||
+51
-23
@@ -1,4 +1,5 @@
|
|||||||
use std::borrow::BorrowMut;
|
use std::borrow::BorrowMut;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::sync::mpsc::channel;
|
use std::sync::mpsc::channel;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
@@ -10,6 +11,7 @@ use wry::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
mod dom;
|
mod dom;
|
||||||
|
mod escape;
|
||||||
|
|
||||||
static HTML_CONTENT: &'static str = include_str!("./index.html");
|
static HTML_CONTENT: &'static str = include_str!("./index.html");
|
||||||
|
|
||||||
@@ -59,33 +61,57 @@ impl<T: Properties + 'static> WebviewRenderer<T> {
|
|||||||
|
|
||||||
let window = user_builder(WindowBuilder::new()).build(&event_loop)?;
|
let window = user_builder(WindowBuilder::new()).build(&event_loop)?;
|
||||||
|
|
||||||
let mut vdom = VirtualDom::new_with_props(root, props);
|
let vir = VirtualDom::new_with_props(root, props);
|
||||||
let mut real_dom = dom::WebviewDom::new();
|
|
||||||
vdom.rebuild(&mut real_dom)?;
|
|
||||||
|
|
||||||
let edits = Arc::new(RwLock::new(Some(serde_json::to_value(real_dom.edits)?)));
|
// todo: combine these or something
|
||||||
|
let vdom = Arc::new(RwLock::new(vir));
|
||||||
// let ref_edits = Arc::new(serde_json::to_string(&real_dom.edits)?);
|
let registry = Arc::new(RwLock::new(Some(WebviewRegistry::new())));
|
||||||
|
|
||||||
let handler = move |window: &Window, mut req: RpcRequest| {
|
|
||||||
//
|
|
||||||
let d = edits.clone();
|
|
||||||
match req.method.as_str() {
|
|
||||||
"initiate" => {
|
|
||||||
let mut ed = d.write().unwrap();
|
|
||||||
let edits = match ed.as_mut() {
|
|
||||||
Some(ed) => Some(ed.take()),
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
Some(RpcResponse::new_result(req.id.take(), edits))
|
|
||||||
}
|
|
||||||
_ => todo!("this message failed"),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let webview = WebViewBuilder::new(window)?
|
let webview = WebViewBuilder::new(window)?
|
||||||
.with_url(&format!("data:text/html,{}", HTML_CONTENT))?
|
.with_url(&format!("data:text/html,{}", HTML_CONTENT))?
|
||||||
.with_rpc_handler(handler)
|
.with_rpc_handler(move |window: &Window, mut req: RpcRequest| {
|
||||||
|
match req.method.as_str() {
|
||||||
|
"initiate" => {
|
||||||
|
let mut lock = vdom.write().unwrap();
|
||||||
|
let mut reg_lock = registry.write().unwrap();
|
||||||
|
|
||||||
|
// Create the thin wrapper around the registry to collect the edits into
|
||||||
|
let mut real = dom::WebviewDom::new(reg_lock.take().unwrap());
|
||||||
|
|
||||||
|
// Serialize the edit stream
|
||||||
|
let edits = {
|
||||||
|
lock.rebuild(&mut real).unwrap();
|
||||||
|
serde_json::to_value(&real.edits).unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Give back the registry into its slot
|
||||||
|
*reg_lock = Some(real.consume());
|
||||||
|
|
||||||
|
// Return the edits into the webview runtime
|
||||||
|
Some(RpcResponse::new_result(req.id.take(), Some(edits)))
|
||||||
|
}
|
||||||
|
"user_event" => {
|
||||||
|
let mut lock = vdom.write().unwrap();
|
||||||
|
let mut reg_lock = registry.write().unwrap();
|
||||||
|
|
||||||
|
// Create the thin wrapper around the registry to collect the edits into
|
||||||
|
let mut real = dom::WebviewDom::new(reg_lock.take().unwrap());
|
||||||
|
|
||||||
|
// Serialize the edit stream
|
||||||
|
let edits = {
|
||||||
|
lock.rebuild(&mut real).unwrap();
|
||||||
|
serde_json::to_value(&real.edits).unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Give back the registry into its slot
|
||||||
|
*reg_lock = Some(real.consume());
|
||||||
|
|
||||||
|
// Return the edits into the webview runtime
|
||||||
|
Some(RpcResponse::new_result(req.id.take(), Some(edits)))
|
||||||
|
}
|
||||||
|
_ => todo!("this message failed"),
|
||||||
|
}
|
||||||
|
})
|
||||||
.build()?;
|
.build()?;
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| {
|
event_loop.run(move |event, _, control_flow| {
|
||||||
@@ -173,6 +199,8 @@ impl<T: Properties + 'static> WebviewRenderer<T> {
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
|
use crate::dom::WebviewRegistry;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
struct MessageParameters {
|
struct MessageParameters {
|
||||||
message: String,
|
message: String,
|
||||||
|
|||||||
Reference in new issue
Block a user