Hello World (first phone app)
Summary
For this assignment (Adobe Gen Pro App Design course, Jun 2015, Class 1), we were to create a default PhoneGap Desktop app and then change its image and text, similar to what Mark Shufflebottom shows in his video (https://vimeo.com/126100493). We were then to show a screen shot of it running in PhoneGap Developer on a mobile device.
 
I added a few extra touches, both to have some fun and to push myself. I also recorded a video (rather than just a screen shot) of the app running on my phone, to show off what I learned.
 
The rest of this post discusses the differences between the default app’s coding and my changes.
Default PhoneGap App
The default PhoneGap app, created in PhoneGap Desktop via “Create new PhoneGap project”:
 
- Starts with a screen-centered image, a pair of text blocks underneath, and a background made up of a descending gradient from dark to light grey.
 
- On launch, attempts to connect to the PhoneGap app server on the desktop. The lower “status” text block appears with a black background and states that the app is “Connecting.”
 
- On a successful connection, switches the status text block from black to green and states that all is “Ready.” Both text block colors “pulse,” i.e. fade in and out via the CSS “animation” property and related keyframes.
 
One important caveat with this app is that on launch, you normally do not see the black text block; the connection completes too quickly for you to see the switch from black to green.
My Version
My version of the default app adds some elements and changes others:
 
- I changed the default image to the Android robot, and I dressed him up in Photoshop in a red, white, and blue descending gradient.
 
- I changed the background gradient to a multistep CSS blue, white, and red gradient, running diagonally from upper left to lower right.
 
- When launched, this app first displays a “Welcome” alert before connecting to the server; this delay allows you to see the status text block while it is still black.
 
- After you click OK, the status text block goes green, and the robot begins jumping vertically up and down on the screen, using an easing strategy to slow him at each peak and valley.
 
- If you turn the phone landscape, both text blocks shift to the right while the robot continues to jump up and down on the left. If you do a four-finger reset at this point, the robot restrains his jumping to the more restricted height of the landscape screen.
 
- I added a Menu button option, which triggers an alert stating that you have pressed that button.
Code Changes: Diagonal Gradient Background
This was perhaps the single most challenging concept in this app. One would think it would be a simple matter to code a diagonal CSS gradient; such a solution was actually straightforward when I tested it on my laptop browser, but I ran into a host of problems when testing the same code on my LG Volt phone, which runs Android 4.4.
 
1) The default app uses CSS “position: absolute” for the <div> that contains the robot and text blocks. This works fine for the default gradient, which runs top to bottom. It also works fine for diagonal gradients in a laptop browser. It does not work, however, for diagonal gradients on my Volt; it instead forces the gradient to run left to right and not diagonal at all. Therefore, I had to get rid of that line.
 
2) Getting rid of “position: absolute” forced me to use the positioning technique Mark S. uses in his video. Absolute positioning makes it possible to set the robot/text block position using “left” and “top” percentages to center the block regardless of screen size. You then simply adjust the margins based on the image size (the default image size is 170px x 200px):
    left:50%;                      /* (position UL corner of div in center of screen L-R) */
    top:50%;                       /* (position UL corner of div in center of screen T-B) */
    height:50px;                   /* text area height (50px = div height + 180 padding =
                                        230 * 0.5 = 115) */
    width:225px;                   /* text area width (225px = div width * 0.5 = 112) */
    ...
    padding:180px 0px 0px 0px;     /* image height is 200px (push text area 180px down, so
                                        it overlaps bottom 20px + extends 30px further) */
    margin:-115px 0px 0px -112px;  /* (offset: adjusts div position to dead center: T: half
                                        of text height + padding; L: half of text width) */
 
Without absolute positioning, you cannot use “left” and “top” to center the image and must instead rely on “auto” for L-R centering and then manually place the block T-B:
    margin:40px auto 20px;         /* (offset: 40px from T, centered L-R, 20px from B) */
 
You also have to make similar manual adjustments for any landscape layout.
 
3) Even the above changes are not enough. The gradient now runs diagonally, but it chops off halfway down the page and starts over. This is because the <body> is only as tall as its content. If you want a diagonal gradient to cover the entire page, regardless of height, you first have to tell <html> that it has no background color and that it has a “min-height” of 100%, and then you have to enclose the gradient in a <div> that also has a “min-height” and “min-width” of 100%.
 
With those pieces in place, the gradient finally ran across the entire page background on my phone.
 
4) I wanted to animate the gradient, i.e., have it flow back and forth. I did find a great site that automatically generates animated CSS gradients (http://www.gradient-animator.com/), but such code requires that you set the gradient background size at 200% or higher (so it can pan back and forth). I found that if I set it higher than that, this introduced ugly vertical lines in the gradient. In addition, the panning gradient was rather distracting. So, I chose to leave it out.
Code Changes: Bouncing Robot
Making the robot bounce would probably work better using JavaScript, since you can detect the exact screen size and set precise boundaries to contain the robot. However, after all the problems with the gradient, I wanted to get this project done and move on, so I settled on a simpler CSS solution.
 
I created a new class “bounce,” set its “animation” property, and added keyframes that change the “margin-top” value from 40px to 150px and back to 40px. As before, this would be much more accurate if I could set absolute positioning, for I could then set “top” values as percentages of screen height. But I wanted the diagonal gradient, so I’ll defer this point until I have more time to do it in JavaScript.
Code Changes: Alerts
I created the alerts in the JavaScript file. The Menu button gets an event handler that detects the “menubutton” event and fires the alert. The startup function simply runs an alert before allowing the app to check for the “deviceready” event, thereby making the app pause while still showing the black “Connecting” box.
Code Changes: Orientation Changes
The default PhoneGap app uses “min-width” to detect a switch between portrait and landscape orientation. I found it easier just to use the “orientation” property, and I made one block of CSS code for each orientation. The portrait code sets the robot/text block position at 40px and then bounces it between that and 150px. The landscape code sets it at 10px and bounces between that and 50px. This all works just fine as long as you force-reset the app (a four-finger press) with each orientation switch.
 
I did try setting up the JavaScript “orientationchange” event to detect the switch from portrait to landscape and back. This worked fine, in that showed that it actually triggered at each orientation change, but it did not automatically trigger a reset of the page to read the new position and keyframe values instead of the cached values. I am sure there is a way in JavaScript to force a new page read, but I need to move on.
Code: index.html
Below is my <body> code in the index.html file. I am including only this part of the code, as you can get the rest by creating a default app from the free PhoneGap Desktop program.
<body>
    <div class="d_gradient">
        <div class="app bounce">
            <h1>Hello, World!</h1>
            <div id="deviceready" class="blink">
                <p class="event listening">Connecting to Device</p>
                <p class="event received">Ready, Set, Go!</p>
            </div>
        </div>
    </div>
    <script type="text/javascript" src="cordova.js"></script>
    <script type="text/javascript" src="js/index.js"></script>
    <script type="text/javascript">
        app.initialize();
    </script>
</body>
Code: index.css
Same intro as above. Comments in parentheses () are my own; comments without () are from the default app.
html {
    /*
     * (See: https://css-tricks.com/just-one-of-those-weird-things-about-css-background-on-body/)
     *   (<body> is only as high as content)
     *   (<body> background will cover the page IF there is NO background on <html>)
     * (See: https://css-tricks.com/perfect-full-page-background-image/)
     *   (Must use min-height to force full-height coverage)
     */
    background: none;
    min-height: 100%;
}
 
body {
    /* (Moved all gradient elements to own <div>, with class d_gradient) */
    -webkit-touch-callout: none;     /* prevent callout to copy image, etc when tap to hold */
    -webkit-text-size-adjust: none;  /* prevent webkit from resizing text to fit */
    -webkit-user-select: none;       /* prevent copy paste, to allow, change 'none' to 'text' */
    font-family:'HelveticaNeue-Light', 'HelveticaNeue', Helvetica, Arial, sans-serif;
    font-size:12px;
    height:100%;
    margin:0px;
    padding:0px;
    text-transform:uppercase;
    width:100%;
}
 
h1 {
    font-size:24px;
    font-weight:normal;
    margin:0px;
    overflow:visible;
    padding:0px;
    text-align:center;
}
 
/* (Gradient setup) */
/* ------------------------------------ */
.d_gradient {
    background-color:#523cfd;       /* (Was #E4E4E4, now Blue) */
 
    /*
     * (Static gradient with CSS)
     * (See: http://www.w3schools.com/css/css3_gradients.asp)
     * (See: http://www.w3schools.com/cssref/pr_background-image.asp)
     * (See: https://css-tricks.com/just-one-of-those-weird-things-about-css-background-on-body/)
     * (See: https://css-tricks.com/perfect-full-page-background-image/)
     * (See: http://www.colorzilla.com/gradient-editor/)
     * (Gradient runs Blue-White-Red with a "soft" White middle)
     *   (Note the differences in syntax to send gradient from Top Left to Bottom Right)
     *   (Android does not handle diagonal gradients if set "absolute" positioning (see below).
            Makes the gradient only L->R.)
     */
 
     background:-webkit-linear-gradient(-45deg, #523cfd 0%, #efedff 40%, #ffffff 50%,
       #ffeded 60%, #ff0000 100%); /* (LG Volt uses this one) */
     background:-ms-linear-gradient(-45deg, #523cfd 0%, #efedff 40%, #ffffff 50%,
       #ffeded 60%, #ff0000 100%);
     background:-webkit-gradient(
        linear,
        left top,
        right bottom,
        color-stop(0, #523cfd),   /* (Blue #523cfd) */
        color-stop(0.4, #efedff), /* (Light Blue) */
        color-stop(0.5, #ffffff), /* (White) */
        color-stop(0.6, #ffeded), /* (Light Red Blue) */
        color-stop(1, #ff0000)    /* (Red) */
    );
    background:linear-gradient(135deg, #523cfd 0%, #efedff 40%, #ffffff 50%,
      #ffeded 60%, #ff0000 100%);
    background-attachment:fixed;
   
    height:auto;       /* (Per https://css-tricks.com/perfect-full-page-background-image/) */
    min-height: 100%;  /* (Per https://css-tricks.com/perfect-full-page-background-image/) */
    width:auto;        /* (100% in https://css-tricks.com/perfect-full-page-background-image/) */
    min-width:100%;    /* (Not in https://css-tricks.com/perfect-full-page-background-image/) */
    margin:0px;        /* (No margin, fill the page) */
    padding:0px;       /* (No padding, fill the page) */
    position: fixed;   /* (Per https://css-tricks.com/perfect-full-page-background-image/) */
}
 
/* ("Connecting...Ready" Text blocks) */
/* ----------------------------------- */
.event {
    border-radius:4px;
    -webkit-border-radius:4px;
    color:#FFFFFF; /* (Text color for both text block states = White) */
    font-size:12px;
    margin:0px 30px;
    padding:2px 0px;
}
 
.event.listening {
    background-color:#333333; /* (Black text block) */
    display:block;
}
 
.event.received {
    background-color:#4B946A; /* (Jade Green text block) */
    display:none;
}
 
/* (Pulsing "Connecting...Ready" block) */
/* ------------------------------------ */
.blink {
    animation:fade 3000ms infinite;
    -webkit-animation:fade 3000ms infinite;
}
 
@keyframes fade {
    from { opacity: 1.0; }
    50% { opacity: 0.4; }
    to { opacity: 1.0; }
}
 
@-webkit-keyframes fade {
    from { opacity: 1.0; }
    50% { opacity: 0.4; }
    to { opacity: 1.0; }
}
 
/*
 * (Make the Android robot bounce up and down)
 * (See: http://www.w3schools.com/css/css3_animations.asp)
 * (Using CSS to approximate bounce height; not using JS, e.g., to calculate exact screen height)
 * (If using absolute positioning, use "top: 35%" to "top: 65%")
 * (If using fixed positioning, use "margin-top" as outlined in portrait vs landscape below)
 */
.bounce {
    animation: bounce 2s ease-out 2s infinite;
    -webkit-animation: bounce 2s ease-out 2s infinite;
}
 
/* Portrait layout (default) */
/* ------------------------------------ */
@media all and (orientation: portrait) {
    .app {
        background:url(../img/Android_robot_RWB_s50.png) no-repeat center top; /* (256x300px) */
        background-color: transparent;
        height:50px;                   /* text area H */
        width:320px;                   /* text area W */
        text-align:center;
        padding:320px 0px 0px 0px;     /* (push text block below image, NO OVERLAP) */
        margin:40px auto 20px;         /* (offset: 40px from T, centered L-R, 20px from B) */
                                       /* (places it just down from T, but centered L-R) */
    }
 
    @keyframes bounce {
        from { margin-top: 40px; } /* (if using absolute positioning variations, use
                                         "top: 35%" to 65%, rather than "margin-top") */
        50% { margin-top: 150px; }
        to { margin-top: 40px; }
    }
 
    @-webkit-keyframes bounce {
        from { margin-top: 40px; } /* (if using absolute positioning variations, use
                                         "top: 35%" to 65%, rather than "margin-top") */
        50% { margin-top: 150px; }
        to { margin-top: 40px; }
    }
}
 
/* Landscape layout) */
/* ------------------------------------ */
/* (DEFAULT uses min-width, I am using orientation) */
/* @media screen and (min-aspect-ratio: 1/1) and (min-width:400px) { (DEFAULT) */
@media all and (orientation: landscape) {
    .app {
        background:url(../img/Android_robot_RWB_s50.png) no-repeat center top; /* (256x300px) */
        background-color: transparent;
        background-position:left center;
        height:50px;                   /* text area H */
        width:320px;                   /* text area W */
        text-align:center;
        padding:125px 0px 125px 300px; /* (padding-top (125) + padding-bottom (125) +
                                             text area (50) = image H (300)) */
        margin:10px auto 20px;         /* offsets: (modified variation of portrait, to account
                                            for smaller landscape screen) */
    }
 
    @keyframes bounce {
        from { margin-top: 10px; }     /* (modified to fit smaller landscape height) */
        50% { margin-top: 50px; }      /* (allowing robot to drop below bottom on <5" cell phone
                                             screen, otherwise too little bounce) */
        to { margin-top: 10px; }
    }
 
    @-webkit-keyframes bounce {
        from { margin-top: 10px; }     /* (modified to fit smaller landscape height) */
        50% { margin-top: 50px; }      /* (allowing robot to drop below bottom on <5" cell phone
                                             screen, otherwise too little bounce) */
        to { margin-top: 10px; }
    }
}
Code: index.js
Same intro as above.
var app = {
    // Application Constructor
    initialize: function() {
        this.bindEvents();
    },
 
    // Bind Event Listeners
    //
    // Bind any events that are required on startup. Common events are:
    // 'load', 'deviceready', 'offline', and 'online'.
    bindEvents: function() {
        document.addEventListener('deviceready', this.onDeviceReady, false);
 
        // (Menu key event handler)
        document.addEventListener('menubutton', this.onMenuKeyDown, false);
    },
 
    // deviceready Event Handler
    //
    // The scope of 'this' is the event. In order to call the 'receivedEvent'
    // function, we must explicitly call 'app.receivedEvent(...);'
    onDeviceReady: function() {
        // (The following line (alert) added before calling 'receivedEvent')
        // (See http://stackoverflow.com/questions/
        //    18627589/strange-phonegap-device-ready-event-behaviour)
        alert('Welcome to my Awesome App!!');
 
        app.receivedEvent('deviceready');
    },
 
    // (Handle the Menu button)
    // (See http://docs.phonegap.com/en/4.0.0/cordova_events_events.md.html#menubutton)
    onMenuKeyDown: function() {
        alert('You just pressed the Menu button!');
    },
   
    // Update DOM on a Received Event
    receivedEvent: function(id) {
        var parentElement = document.getElementById(id);
        var listeningElement = parentElement.querySelector('.listening');
        var receivedElement = parentElement.querySelector('.received');
 
        // (Comment out the listeningElement line to see both blocks at same time
        //    (both will have display:block))
        // (If leave as is, "listening" is first displayed and "received" is not;
        //    after connection, vice versa)
        listeningElement.setAttribute('style', 'display:none;');
        receivedElement.setAttribute('style', 'display:block;');
 
        console.log('Received Event: ' + id);
    },
};
Attributions
Android robot:
  https://en.wikipedia.org/wiki/File:Android_robot.svg
  CC BY-SA 3.0
  Created: 2014_0319 by Smashman2004~commonswiki
Hello World (first phone app)
3
153
2
Published:

Hello World (first phone app)

This project is my first phone app: The Android robot dons patriotic colors and bounces up and down for joy. Adobe Gen Pro Application Design (Ju Read More
3
153
2
Published:

Tools

Creative Fields