wip: enable more diffing

This commit is contained in:
Jonathan Kelley committed 2021-07-05 01:11:49 -04:00
1 parent b5e5ef171a
commit e8f29a8f8a
26 files changed
+1326 -367

No files matched your search

+42 -27
View File
@@ -4,51 +4,54 @@
//! Some components benefit through the use of "Models". Models are a single block of encapsulated state that allow mutative
//! methods to be performed on them. Dioxus exposes the ability to use the model pattern through the "use_model" hook.
//!
//! Models are commonly used in the "Model-View-Component" approach for building UI state.
//!
//! `use_model` is basically just a fancy wrapper around set_state, but saves a "working copy" of the new state behind a
//! RefCell. To modify the working copy, you need to call "modify" which returns the RefMut. This makes it easy to write
//! RefCell. To modify the working copy, you need to call "get_mut" which returns the RefMut. This makes it easy to write
//! fully encapsulated apps that retain a certain feel of native Rusty-ness. A calculator app is a good example of when this
//! is useful.
//!
//! Do note that "get_mut" returns a `RefMut` (a lock over a RefCell). If two `RefMut`s are held at the same time (ie in a loop)
//! the RefCell will panic and crash. You can use `try_get_mut` or `.modify` to avoid this problem, or just not hold two
//! RefMuts at the same time.
use dioxus::events::on::*;
use dioxus::prelude::*;
use std::{
cell::RefCell,
ops::{Deref, DerefMut},
};
fn main() {
dioxus::webview::launch(App)
}
static App: FC<()> = |cx| {
let state = use_model(&cx, || CalculatorState::new());
let calc = use_model(&cx, || Calculator::new());
let clear_display = state.display_value.eq("0");
let clear_display = calc.display_value.eq("0");
let clear_text = if clear_display { "C" } else { "AC" };
let formatted = state.formatted();
let formatted = calc.formatted();
cx.render(rsx! {
div { class: "calculator", onkeydown: move |evt| state.modify().handle_keydown(evt),
div { class: "calculator-display", "{formatted}"}
div { class: "calculator", onkeydown: move |evt| calc.get_mut().handle_keydown(evt),
div { class: "calculator-display","{formatted}"}
div { class: "input-keys"
div { class: "function-keys"
CalculatorKey { name: "key-clear", onclick: move |_| state.modify().clear_display() "{clear_text}" }
CalculatorKey { name: "key-sign", onclick: move |_| state.modify().toggle_sign(), "±"}
CalculatorKey { name: "key-percent", onclick: move |_| state.modify().toggle_percent() "%"}
// All there ways that the calculator may be modified:
CalculatorKey { name: "key-clear", onclick: move |_| calc.get_mut().clear_display() "{clear_text}" }
CalculatorKey { name: "key-sign", onclick: move |_| calc.modify(Calculator::toggle_sign), "±"}
CalculatorKey { name: "key-percent", onclick: move |_| calc.modify(|f| f.toggle_percent()) "%"}
}
div { class: "digit-keys"
CalculatorKey { name: "key-0", onclick: move |_| state.modify().input_digit(0), "0" }
CalculatorKey { name: "key-dot", onclick: move |_| state.modify().input_dot(), "●" }
{(1..9).map(|k| rsx!{
CalculatorKey { key: "{k}", name: "key-{k}", onclick: move |_| state.modify().input_digit(k), "{k}" }
CalculatorKey { name: "key-0", onclick: move |_| calc.get_mut().input_digit(0), "0" }
CalculatorKey { name: "key-dot", onclick: move |_| calc.get_mut().input_dot(), "●" }
{(1..9).map(move |k| rsx!{
CalculatorKey { key: "{k}", name: "key-{k}", onclick: move |_| calc.get_mut().input_digit(k), "{k}" }
})}
}
div { class: "operator-keys"
CalculatorKey { name:"key-divide", onclick: move |_| state.modify().set_operator(Operator::Div) "÷" }
CalculatorKey { name:"key-multiply", onclick: move |_| state.modify().set_operator(Operator::Mul) "×" }
CalculatorKey { name:"key-subtract", onclick: move |_| state.modify().set_operator(Operator::Sub) "−" }
CalculatorKey { name:"key-add", onclick: move |_| state.modify().set_operator(Operator::Add) "+" }
CalculatorKey { name:"key-equals", onclick: move |_| state.modify().perform_operation() "=" }
CalculatorKey { name:"key-divide", onclick: move |_| calc.get_mut().set_operator(Operator::Div) "÷" }
CalculatorKey { name:"key-multiply", onclick: move |_| calc.get_mut().set_operator(Operator::Mul) "×" }
CalculatorKey { name:"key-subtract", onclick: move |_| calc.get_mut().set_operator(Operator::Sub) "−" }
CalculatorKey { name:"key-add", onclick: move |_| calc.get_mut().set_operator(Operator::Add) "+" }
CalculatorKey { name:"key-equals", onclick: move |_| calc.get_mut().perform_operation() "=" }
}
}
}
@@ -56,7 +59,7 @@ static App: FC<()> = |cx| {
};
#[derive(Clone)]
struct CalculatorState {
struct Calculator {
display_value: String,
operator: Option<Operator>,
cur_val: f64,
@@ -68,9 +71,10 @@ enum Operator {
Mul,
Div,
}
impl CalculatorState {
impl Calculator {
fn new() -> Self {
CalculatorState {
Calculator {
display_value: "0".to_string(),
operator: None,
cur_val: 0.0,
@@ -118,7 +122,9 @@ impl CalculatorState {
self.display_value.pop();
}
}
fn set_operator(&mut self, operator: Operator) {}
fn set_operator(&mut self, operator: Operator) {
self.operator = Some(operator)
}
fn handle_keydown(&mut self, evt: KeyboardEvent) {
match evt.key_code() {
KeyCode::Backspace => self.backspace(),
@@ -160,6 +166,10 @@ fn CalculatorKey<'a, 'r>(cx: Context<'a, CalculatorKeyProps<'r>>) -> VNode<'a> {
use odl::use_model;
mod odl {
use super::*;
use std::{
cell::RefCell,
ops::{Deref, DerefMut},
};
/// Use model makes it easy to use "models" as state for components. To modify the model, call "modify" and a clone of the
/// current model will be made, with a RefMut lock on it. Dioxus will never run your components multithreaded, so you can
/// be relatively sure that this won't fail in practice
@@ -208,9 +218,14 @@ mod odl {
wip: RefCell::new(t),
}
}
pub fn modify(&self) -> RefMut<'_, T> {
pub fn get_mut(&self) -> RefMut<'_, T> {
self.wip.borrow_mut()
}
pub fn modify(&self, f: impl FnOnce(&mut T)) {
let mut g = self.get_mut();
let r = g.deref_mut();
todo!()
}
}
#[derive(Clone, Copy)]