Skip to content
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

Add Calculator demo #174

Merged
merged 21 commits into from
Jan 8, 2019
Merged

Add Calculator demo #174

merged 21 commits into from
Jan 8, 2019

Conversation

OhadRau
Copy link
Collaborator

@OhadRau OhadRau commented Jan 2, 2019

Still a few things left to do, but this is a mostly working calculator.

Stuff (maybe) left to go:

  • Make operators show up in the display window before evaluation
  • Change font so we can have a backspace symbol
  • Figure out how to get relative sizing to work (is this possible with Revery yet?)
  • Scale font size along with buttons so that it doesn't look tiny (maybe?)

I'm also not sure how great my use of state was here, but I guess since we don't do state the same way as ReasonReact (i.e. state+action) this would be pretty typical of a Revery app. Regardless, would like any suggestions for how to make this easier to understand or improve the code in general.

image

@OhadRau
Copy link
Collaborator Author

OhadRau commented Jan 3, 2019

Relative spacing is currently really weird to do with the <Clickable> tag, since we can't override it's style. We might want to block this PR on a change that'll allow us to override the Clickable's flex-grow and such. With flex-grow on the <view> inside the button we grow vertically. flex-grow on a view outside almost works, but the clickable area stays within the <Clickable> tag which isn't growing horizontally.

@bryphe
Copy link
Member

bryphe commented Jan 3, 2019

@OhadRau - this is awesome work! It's great to finally see an interactive demo come together.

Testing on Windows:

calculator-demo

Like, it feels like you could build a usable app with this now! So cool!

I'm also not sure how great my use of state was here, but I guess since we don't do state the same way as ReasonReact (i.e. state+action) this would be pretty typical of a Revery app. Regardless, would like any suggestions for how to make this easier to understand or improve the code in general.

I think the way you used state here is perfectly appropriate (and highlights the usage of hooks within revery). We do have a concept of a redux-like state store, but I don't think it's necessary to use that in here. The nice thing about encapsulating the state the way that you did is the <Calculator /> could be easily extracted as a component and embedded into other apps. It might be the case that we don't need the concept of an app-wide state store at all, and can just delegate to useReducer/useState. (One thing I'm interested in is introducing time-travel debugging like the redux dev tools have - but I'm thinking that, with some of the thinking @cristianoc and @jchavarri have done on revery-ui/reason-reactify#47, we could get that for component state too. It's totally a tangent so I'll log a separate issue to track this).

Relative spacing is currently really weird to do with the tag, since we can't override it's style. We might want to block this PR on a change that'll allow us to override the Clickable's flex-grow and such.

Good point. This was an oversight by me, we should have a style property exposed on <Clickable />. I'm happy to either bring this PR in as-is (and then we can fix <Clickable /> but update this example), or fix <Clickable /> prior to merging this - whatever you'd prefer @OhadRau .

Sorry about the CI build issues - fixing this in #178

Awesome example and thanks again! 👍

@bryphe
Copy link
Member

bryphe commented Jan 3, 2019

Change font so we can have a backspace symbol

For this, we could bring in font-awesome, and render the backspace icon: https://fontawesome.com/icons/backspace?style=solid

I had some prototype code for this that I just ported over to the Oni2 repo: onivim/oni2@2260c99

Copy link
Member

@bryphe bryphe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code looks good to me! I'm happy to tackle the remaining bullet points in separate PRs - whatever you'd prefer, @OhadRau .

@bryphe
Copy link
Member

bryphe commented Jan 3, 2019

(Also, if you bring in latest master, the build should succeed)

@OhadRau
Copy link
Collaborator Author

OhadRau commented Jan 3, 2019

Awesome, I believe that @bmathews was working on exactly that in his clickable-styles branch, so I guess I'll just wait until we have that merged in (unless you'd prefer to have this in master now so we have an interactive demo).

@bmathews
Copy link

bmathews commented Jan 3, 2019

@OhadRau @bryphe

That is what I was going for, yep, but I'm not a reason expert so there might be a better way to do it:

https://github.com/revery-ui/revery/compare/master...bmathews:clickable-styles?expand=1

@jchavarri
Copy link
Member

Hey @OhadRau @bryphe I was looking at this calculator example (which is awesome!! 🚀 ) and wanted to explore how useReducer would look in this case, on one side because it's such a exemplary "state machine" case, plus it was a good chance to test that API that was added recently.

I created a PR from this branch in https://github.com/OhadRau/revery/pull/1/files but this is the gist of the different types:

type state = {
  operator, /* Current operator being applied */
  result: float, /* The actual numerical result */
  display: string, /* The equation displayed */
  number: string /* Current number being typed */
};

type action =
  | BackspaceKeyPressed
  | ClearKeyPressed(bool) /*AC pressed */
  | DotKeyPressed
  | NumberKeyPressed(string)
  | OperationKeyPressed(operator)
  | PlusMinusKeyPressed
  | ResultKeyPressed;

then the reducer (i'm skipping the eval function which would be almost 1:1 what exists already):

let reducer = (state, action) =>
  switch (action) {
  | BackspaceKeyPressed =>
    state.number == "" ?
      state :
      {
        ...state,
        number: String.sub(state.number, 0, String.length(state.number) - 1),
      }
  | ClearKeyPressed(ac) =>
    ac ?
      {...state, operator: `Nop, result: 0., display: ""} :
      {...state, number: ""}
  | DotKeyPressed =>
    String.contains(state.number, '.') ?
      state : {...state, number: state.number ++ "."}
  | NumberKeyPressed(n) => {...state, number: state.number ++ n}
  | OperationKeyPressed(o) =>
    let (result, display) = eval(state, o);
    {operator: o, result, display, number: ""};
  | PlusMinusKeyPressed =>
    if (state.number != "" && state.number.[0] == '-') {
      {
        ...state,
        number: String.sub(state.number, 1, String.length(state.number) - 1),
      };
    } else {
      {...state, number: "-" ++ state.number};
    }
  | ResultKeyPressed =>
    let (result, display) = eval(state, `Nop);
    {operator: `Nop, result, display, number: showFloat(result)};
  };

and finally the consumption in the component:

let ({display, number, _}, dispatch) =
  useReducer(
    reducer,
    {operator: `Nop, result: 0., display: "", number: ""},
  );

I think either useState or useReducer are fine, we can add useReducer to another example in the future 😄 Let me know what you think!

@OhadRau
Copy link
Collaborator Author

OhadRau commented Jan 3, 2019

Yeah that actually looks good to me @bmathews. In terms of functions to extend style that's probably the cleanest we can get it. The only alternative I can really think of would be to define styles without the Style.make function and to use the {...spread} syntax for records, but that's up to the user to do on their own.

@OhadRau
Copy link
Collaborator Author

OhadRau commented Jan 3, 2019

@jchavarri Awesome! Didn't realize we have a useReducer function but I think that'll actually help me clean up the current code a lot. Since that's not in any examples already this could be a good place to add it.


| _ => ()
};
/* TODO: Pretty sure this isn't supposed to go in the render() function.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good intuition, I think it is subscribing to the event on each re-render!

You could try this:

useEffect(() => {
let unsubscribe = Event.subscribe(window.onKeyDown, respondToKeys);
unsubscribe
});

On each re-render, it will unsubscribe from the previous event subscription.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bryphe Would this be a good opportunity to use the MountUnmount condition? Like in this test?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jchavarri - I think it'd be reasonable (and better for perf)! Not sure if we'd hit that long-lived setState issue though in revery-ui/reason-reactify#44 ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bryphe Is useEffect exposed right now? I don't see it in Hooks and doesn't look like there's access to UiReact anywhere. Want me to add this to the PR?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah sorry - it wasn't exposed! Thanks for adding it @OhadRau 👍

@bryphe
Copy link
Member

bryphe commented Jan 4, 2019

One other cool thing - with revery-ui/reason-fontkit#13, and aside from a minor glyph bug (revery-ui/reason-fontkit#14 - not related to this PR)... this calculator actually works and is usable in the browser too as a WebGL app! 😍

image

@OhadRau
Copy link
Collaborator Author

OhadRau commented Jan 4, 2019

@bmathews Actually, one thing I just thought of for clickable-styles is that it probably makes the most sense to extend a transform by concatenating two lists. For example, if <Clickable> were to have a rotation applied by default, extending it with a scale transform would cancel that. Instead, we'd probably want to take the old style and add to that since that seems more akin to what CSS styles would do. Regardless, feel free to open it as a PR or issue here (even if it's not done yet) so we can centralize discussion on it and track progress.

@OhadRau
Copy link
Collaborator Author

OhadRau commented Jan 7, 2019

Merged in @bmathews' clickable-styles branch & then used that to make the buttons scale. Might still investigate making the font size scale along with the buttons since it looks a little funny, but in the meantime would you mind reviewing this again since it's some new changes @bryphe?

@bryphe
Copy link
Member

bryphe commented Jan 7, 2019

Just grabbed the latest! Code looks great, and I love the way calculator works now (handling key input is a big plus!). Thanks for the clickable-styles work too @bmathews !

image

I really like the first-class icon we have for backspace too. Consider me signed-off @OhadRau 👍

@bryphe
Copy link
Member

bryphe commented Jan 8, 2019

Just checked the build - looks like it hit this error:

2019-01-08T00:05:40.8605848Z File "examples/dune", line 2, characters 4-227:
2019-01-08T00:05:40.8606706Z 2 |     (names Hello Autocomplete Flexbox Border Boxshadow DefaultButton Overflow)
2019-01-08T00:05:40.8607220Z 3 |     (preprocess (pps lwt_ppx))
2019-01-08T00:05:40.8607358Z 4 |     (package Revery)
2019-01-08T00:05:40.8607469Z 5 |     (public_names Hello Autocomplete Flexbox Border Boxshadow DefaultButton Calculator Overflow)

I fixed it inline - 🤞 it works!

@OhadRau
Copy link
Collaborator Author

OhadRau commented Jan 8, 2019

Thanks for the fix! Looks like the CI isn't working again, any chance you can restart it or merge this in without? @bryphe

@bryphe
Copy link
Member

bryphe commented Jan 8, 2019

Ah looks like there is still one more build failure:

File "src/UI/Style.re", line 122, characters 15-556:
Error: Some record fields are undefined: overflow

I pushed up a commit with the fix, you might just need to cherry-pick it (git cherry-pick 27970c37). Hopefully CI is green after that!

EDIT: Realized I could just update this line too - done - 🤞 the build is really green this time.

@OhadRau
Copy link
Collaborator Author

OhadRau commented Jan 8, 2019

Merging now! Thanks for all the help

@OhadRau OhadRau merged commit d969ac3 into revery-ui:master Jan 8, 2019
@OhadRau OhadRau mentioned this pull request Jan 8, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants