Do I actually need a native app for that?

s1hofmann

Simon Hofmann

Posted on December 27, 2018

Do I actually need a native app for that?

TL;DR;

I created a planning-poker PWA.

Here's the source
and here’s the deployed prototype.

A little case study

When discussing new features, our distributed team makes heavy use of planning-poker apps. Everyone of us is sitting in front of a webcam with his phone equipped and on the count of three, everyone reveals his estimation by either tapping the screen or shaking the phone. It’s a nice way for us to socialize and get things done at the same time.

Depending on the task at hand, we’re using different types of decks, but most of the time it’s either “Fibonacci” or “T-Shirt sizes”.

So, when talking about features of a (very) basic planning-poker app, it should provide the following things:

  1. Provide different decks of planning-poker cards to chose from
  2. Allow the user to pick a card
  3. Display the card, upside-down
  4. Tapping the screen or shaking the phone flips the card

Sounds fairly straight-forward, but …

Size matters?

The last time I scanned my phone for things I could get rid of (I’m constantly living on the edge of device memory), I recognized that my simple planning-poker app takes up almost 20 MB of storage, just to provide the above mentioned feature set.

“20 MB? Really? For something I could build with a few lines of CSS and JS?” - Me, right when I decided to build a prototype for a planning-poker PWA over the holidays.

In case you’ve read any of my previous posts, you might already know that I’m a fan of PWAs. In my opinion, countless native apps out there could also be realized as a PWA, and I hope that the amount of PWAs out there will continue to grow! On the other hand, whenever I do projects like this, I’m also focussing on learning new things. Frontend projects are the perfect fit for this, since I’m mostly doing backend development, so here are some of my key takeaways after building this React-based PWA.

1. Can I do it with CSS?

When I started to implement a Card component, I thought about possible ways to flip it. My first approach was to flip the card body via CSS and render either the Front or Back child, depending on the cards state. That was when I learned more about perspective in CSS. The basic idea is simple:

  • Rotate the back-faceing component by 180 degrees, keep the front-faceing
.card-front, .card-back {
    ...
}

.card-front {
  transform: rotateY(0deg);
}

.card-back {
  transform: rotateY(180deg);
}
Enter fullscreen mode Exit fullscreen mode
  • Flip the parent container to switch back and forth between front / back
  • Render either Front or Back component, depending on flipped state

The reason why I ditched this approach at the end was timing. As soon as the state changes, a different component is rendered. This means that during the actual flip we could already see the “other side”. I simply didn’t want to mess with timeouts aligned to CSS transition durations to properly switch between components, so I chose another solution which does not involve component switching after reading this article.

We keep the rotation stuff just like before, but instead of rendering different components depending on the state, we overlay front- and backside via absolute positioning. Now both sides of the Card are rendered at once, so we additionally have to turn off backface-visibility. This way we don’t have to deal with timing and our Card flips just fine! :) In combination with classnames, we can seamlessly wire our flipping mechanism to our component state:

<div
className={classNames(
    "card-body",
    { flipped: this.state.flipped },
    this.props.className
)}
onClick={this.props.onSelect || this.flip}
>
    <Front ... />
    <Back ... />
</div>
Enter fullscreen mode Exit fullscreen mode

2. Device motion

Getting my cards to flip on device motion was easier than I thought. A quick search on codepen.io for “devicemotion” gave me this pen. So, depending on the phone tilt I get either positive or negative values. Perfect!

Reading either DeviceMotionEvent.acceleration or DeviceMotionEvent.accelerationIncludingGravity I’m detecting shakes by checking the amplitude and whether there’s been a change in sign or not. When the threshold is met, the onShake callback gets executed. There’s also an additional timeout to keep the Seismograph from fireing non-stop.

Seeing my cards flip on device motion and realizing how easy it was to use native device features in a web application made me smile big time! :)

3. Hosting? GitHub pages!

A while ago I created another PWA to randomly browse xkcd comics. Back then, hosting a React-based PWA on GitHub pages required some configuration to get everything to work.

Things have changed since then! :)

  • Configure a homepage in your package.json
"homepage": "https://s1hofmann.github.io/planning-poker",
Enter fullscreen mode Exit fullscreen mode
  • Install the gh-pages package
yarn add -D gh-pages
Enter fullscreen mode Exit fullscreen mode
  • Add two scripts:
"predeploy": "npm run build",
"deploy": "gh-pages -d build"
Enter fullscreen mode Exit fullscreen mode
  • Run yarn deploy

Following these four steps everything should run out of the box and your PWA is online.

4. Useful things

I created just a single base icon for my application. This tool did the heavy lifting for me and created all the other sizes for me. Nice!

Sooo …

As you can see here, my little experiment turned out pretty well. (Ehm… pretty… At least according to me)

I already ditched my native planning-poker app and maybe there will be more in the near future!

So long

Simon

💖 💪 🙅 🚩
s1hofmann
Simon Hofmann

Posted on December 27, 2018

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related