Building Designer News for Pebble

A few weeks ago, I got a Pebble Time smartwatch! I was looking into the developer documentation, and it turns out they have a Pebble.js library (although still in beta), which allows you to write apps for Pebble entirely in Javascript. So, I decided to try making a simple app for Pebble that pulls the top 10 stories from Designer News.

Here is the final product:

Pebble for DN App Screenshot Pebble for DN App Screenshot Pebble for DN App Screenshot

<br>

<a href="https://apps.getpebble.com/applications/55b75efd3d39bb179a00003d">Download from the Pebble App Store</a> / <a href="https://github.com/ireade/dn-for-pebble">View on Github</a>

Intro to Pebble.js #

Getting started developing apps and watchfaces for the Pebble is really simple. If you do not want to deal with the SDK, you can sign up for CloudPebble, their online IDE. This allows you to get right into the code without worrying about any setup.

Pebble.js, as you would imagine, is very similar to writing regular javascript, but with some additional features. There were three in-built Pebble.js libraries I used in making this application - UI, Vector2, and ajax.

UI Library #

This library allows us to create Pebble-specific UI elements. In this app, I used the following elements -

  • Window - creates a new screen
  • Menu - creates a menu-format screen with a list of actionable items
  • Rect - creates a rectangle object
  • Text - creates a text element

To create a new window, for example, all we need to do is write -

var windowName = new UI.Window({
  // options
});

Vector2 Library #

This library allows us to construct a 2 dimensional vector. So, to create a rectangle, we write -

var rectangle = new UI.Rect({
  size: new Vector2(100, 50) // (x, y)
  // more options
})

Ajax Library #

This library provides a simple way to make ajax requests. For example -

ajax({
  url: requestUrl,
  type: 'json'
}, function(data, status, request) {
  console.log(data);
}, function(error, status, request) {
  console.log('The ajax request failed: ' + error);
});

Designer News for Pebble #

Using these libraries, I was able to create this very simple application. Although I have made some improvements to the app recently, I thought it would be more useful to show the version 1.0, which gives a more basic and clear idea of how everything works.

Here is my very short and simple app file for version 1.0 -

/*
 * DN for Pebble
 * Ire Aderinokun
 */

// Require dependencies
var UI = require('ui');
var ajax = require('ajax');
var Vector2 = require('vector2');


// Loading Window
var loadingWindow = new UI.Window({
  fullscreen: true
});

var loadingBg = new UI.Rect({
  position: new Vector2(0, 0),
  size: new Vector2(144, 168), // full width and height of pebble window
  backgroundColor: 'blue', // in-built colours
});

var loadingText = new UI.Text({
  position: new Vector2(0, 50),
  size: new Vector2(144, 50),
  text:'DN Loading',
  font:'GOTHIC_24', // in-built font
  color:'white',
  textOverflow:'wrap',
  textAlign:'center',
  backgroundColor:'clear'
});

// Add background and text elements to the window
loadingWindow.add(loadingBg);
loadingWindow.add(loadingText);

// Show the window
loadingWindow.show();


// DN Request URL
var dnRequestURL = 'https://api.import.io/store/connector/_magic?url=https%3A%2F%2Fwww.
designernews.co%2F%3Fformat%3Drss&js=false&_user=59cf7cce-4fdd-4a7f-be6f-630574c6d814
&_apikey='+apiKey;

// Function to parse the JSON object returned
var parseFeed = function(data, quantity) {
  var items = [];

  for(var i = 0; i < quantity; i++) {
    var title = data.tables[0].results[i].value_1;
    items.push({
      title: title
    });
  }

  return items;
};

// AJAX request
ajax(
  {
    url: dnRequestURL,
    type:'json'
  },

  // On Success
  function(data) {

    // Create Menu of 10 Top Stories
    var menuItems = parseFeed(data, 10);

    var resultsMenu = new UI.Menu({
      backgroundColor: 'white',
      textColor: 'black',
      highlightBackgroundColor: 'blue',
      highlightTextColor: 'white',
      sections: [{
        title: 'Top Stories',
        items: menuItems
      }]
    });

    // When loaded, show resultsMenu and hide loading window
    resultsMenu.show();
    loadingWindow.hide();


    // On Select of a particular story
    resultsMenu.on('select', function(e) {

      var story = data.tables[0].results[e.itemIndex];
      var storyTitle = story.value_1;
      var storyDescription = story.description;

      // Create window for the detail view of story
      var detailView = new UI.Window({
        scrollable: true,
        fullscreen: true
      });

      var headerBg = new UI.Rect({
        position: new Vector2(0, 0),
        size: new Vector2(144, 105),
        backgroundColor: 'blue'
      });

      var bodyBg = new UI.Rect({
        position: new Vector2(0, 105),
        size: new Vector2(144, 320),
        backgroundColor: 'white'
      });

      var Title = new UI.Text({
        position: new Vector2(8, 0),
        size: new Vector2(131, 80),
        text: storyTitle,
        font:'GOTHIC_24_BOLD',
        color:'white',
        textOverflow:'wrap',
        textAlign:'left',
        backgroundColor:'clear'
      });

      var Description = new UI.Text({
        position: new Vector2(8, 110),
        size: new Vector2(131, 300),
        text: storyDescription,
        font:'GOTHIC_18',
        color:'black',
        textOverflow:'wrap',
        textAlign:'left',
        backgroundColor:'clear'
      });

      detailView.add(headerBg);
      detailView.add(bodyBg);
      detailView.add(Title);
      detailView.add(Description);
      detailView.show();

    });
  },

  // On error
  function(error) {

    var errorText = new UI.Text({
      position: new Vector2(0, 50),
      size: new Vector2(144, 100),
      text:'Download failed: ' + error,
      font:'GOTHIC_24',
      color:'white',
      textOverflow:'wrap',
      textAlign:'center',
      backgroundColor:'clear'
    });

    // remove loading text and add error text
    loadingWindow.remove(loadingText);
    loadingWindow.add(errorText);
  }
);

To get a JSON version of the website feed, I used import.io.

That's it! I have since made some design improvements to the app, mainly adding a variable height for the header section depending on the length of the story title. I'm also working on adding support for recent stories and discussions.

The only downside to Pebble.js is that it actually runs on the phone and so cannot be used when the phone is out of range. Although for an app like this, that isn't a problem, it is something worth noting.

Keep in touch KeepinTouch

Subscribe to my Newsletter 📥

Receive quality articles and other exclusive content from myself. You’ll never receive any spam and can always unsubscribe easily.

Elsewhere 🌐