Monday, November 23, 2015

Rightpoint Labs Peeps App – VisualStateManager in UWP

Joe Meyer, Solutions Architect

It's that special time of year where everyone is thinking about what makes them thankful. Here at Rightpoint, we’re especially thankful for the people at our company (or “Peeps” as Rightpoint jargon goes). As a company we strive to keep that “everyone knows everyone” atmosphere of a small startup, even as we grow and expand. To that effort, we wanted a convenient way to highlight new additions to our team in a way that is accessible,  unobtrusive, and could be deployed to a handful of otherwise vacant screens around the office. That, coupled with the eagerness of my peers Jason Sears, Brandon Barnett, and myself to jump into the Windows 10 Universal Windows Platform space back when it launched, led to the birth of the Peep App for Windows 10 (available for all your Peeps needs free and open source on GitHub). So let’s talk Peeps!

clip_image001

I (really) love Peeps

Peeps Features

The Peeps App is fairly elegant in principle: a simple rotator cycles through a list of Peeps who are new to the company, showing a photo, and some basic information like department and geographical office. We want the app to be as light as possible (so that it can run on minimal hardware, such as the Raspberry Pi – I’ll get to that later) and usable on desktop-sized screens, as well as compatible phones. We also display the local time on the app; We set up Peeps in the kitchen and by the elevators, both places where people might be idle, but interested in the current time while they browse. The end result? Something like this:

 

imageDesktop (left) and Phone portrait (right)

 

Neat! Now that we’ve seen the end result, let’s see what makes it work.

Technical Design

The solution consists of three main parts: a Client project, a Server project, and a “Sync” console app that we use to populate data that dries the app. For this post, I’ll be focusing on what’s going on in the Client project and how we achieved what you see and interact with. The details of the supporting infrastructure will have to wait for another blog post. While the supporting projects are somewhat more platform agnostic, it’s important to note that to develop the client app for Windows 10, you’ll need a Windows 10 machine in some capacity. The advantage is that unlike Windows 8, win Windows 10 we can create a single executable with an adaptive UI that can be distributed to any W10 device – desktops tablets, phones, and  Internet of Things embedded devices (like the Pi previously mentioned)!

There’s a lot of magic happening behind the curtain to make that happen, but here’s how we achieve an adaptive UI in the new UWP space.

        <VisualStateManager.VisualStateGroups>

            <VisualStateGroup>

 

                <!-- Wide state applies in devices above 720 effective pixels wide -->

                <VisualState x:Name="WideState">

                    <VisualState.StateTriggers>

                        <AdaptiveTrigger MinWindowWidth="720" />

                    </VisualState.StateTriggers>

 

                    <VisualState.Setters>

                        <Setter Target="PeepsFrame.Background" Value="{StaticResource DefaultBackgroundBrush}" />

                        <Setter Target="LayoutRoot.Background" Value="{StaticResource PeepsGray}" />

                        <Setter Target="PeepsFlipView.ItemTemplate" Value="{StaticResource PeepsTemplateWide}"/>

 

 

                        <Setter Target="PeepsStamp.(RelativePanel.AlignBottomWithPanel)" Value="True"/>

                        <Setter Target="PeepsStamp.(RelativePanel.AlignRightWithPanel)" Value="True"/>

 

                        <Setter Target="PeepsTime.(RelativePanel.AlignVerticalCenterWith)" Value="PeepsStamp"/>

                       

                    </VisualState.Setters>

                </VisualState>

 

                <!-- Wide state applies in devices less than 719 effective pixels wide -->

                <VisualState x window.addEventListener('DOMContentLoaded', (event) => { var curLoc = window.location.href.substr(window.location.href.lastIndexOf('#')); if (curLoc === "#cookiePolicy") { $([document.documentElement, document.body]).animate({ scrollTop: ($("#cookiePolicyId").offset().top)-100 }); $('.text-multiple-columns').removeClass("in-viewport--fade-in"); } });