Friday, December 18, 2009

Web Runtime Widget Tutorial – Part 4: Refining the UI

Grab the code!

In this fourth part of the tutorial we smooth off some of the rougher edges in our Widget’s UI.

We will look at using progress notifications to help with the uncertainty over when our request to Digg has completed. We’ll also improve the presentation of the detail view and allow the user to open a link to the full story. Doing this will also cause us to at last make use of our project’s empty CSS file.

As promised, I’ve also got a different icon for our widget. Notice I said “different”, not “better”. At least the new icon is more relevant than the “Hello” speech bubble icon we’ve been using up to now.

Showing Progress

We’ve been using the UIManager object’s showNotification() function since the beginning of this tutorial. Back in part 1 of the tutorial we noted that showNotification() took three parameters:

  • duration (in milliseconds) to show the note
    • If the duration is negative, the note will remain visible until such time as your code explicitly hides the notification
  • type of note (which influences the icon shown in the note dialog)
    • “info” – the type we’ve used up till now, intended for showing general information to the user
    • “warning” – intended for use with errors or similar situations
    • “wait” – this is the type we’ll look at using now because it is intended for use with progress notifications
    • If you pass null as the note type, no icon will be displayed in the notification.
  • message to be shown to the user

If you are using a “wait” notification, a fourth parameter can be passed, which defines the progress of an operation. This fourth parameter should be a floating point number between 0.0 and 1.0, with 0.0 meaning the operation is at 0% and 1.0 meaning the operation is at 100%. Of course, the progress of some operations is difficult to calculate, such as our request to Digg. For these situations, you can pass a negative progress value. The “wait” notification uses slightly different styles depending on whether progress is known or unknown.

Using a “wait” notification is particularly easy if the actual progress over time is not known. You simply need to call UIManager’s showNotification() function as your operation begins and then call the function hideNotification() on your UIManager object when the operation completes.

Displaying the progress notification

From part 3 of the tutorial, we know that our event handler diggButtonClicked() is the function that initiates the web request to Digg which makes it a good place to present the progress notification, just before we start the web request:

Show wait notification

The code above is identical to the implementation of this function in part 3 of the tutorial, except for the addition of line 207. Here we call showNotification() on our UIManager object, passing a duration of –1 indicating that the notification should not time out, a type of “wait”, a suitable message and a progress of –1, indicating that we can’t tell what the operation’s progress is.

The function then goes on to issue a request for stories to Digg as before. The screenshot below shows the main view with our new “wait” notification visible during a request to Digg:

Screenshot showing wait note

Hiding the progress notification

If we’ve modified the code that creates a request to Digg in order to show a progress notification, it seems sensible that we add code to remove the progress notification in our function that gets called when the request completes.

Hiding the wait notification

The code above is an abridged version of handleDiggResponse() from part 3 of the tutorial. The only difference between the implementation in part 3 and this part of the tutorial is the addition of line 278 – the call to UIManager’s hideNotification() function. We call hideNotification() here  as our last action in handleDiggResponse() because we can be sure that everything has been processed and the UI has been updated as appropriate.

Detail View 2.0

The detail view we’ve been using up to now hasn’t been very interesting. It was fine to prototype our ideas with and demonstrate how we could move data around our views. But if we want to put our widget on our phones and use it, we want something a bit better.

Something like this maybe?

New Detail View

To turn our dull detail view from part 3 of the tutorial into the slightly more interesting view shown above takes just a small amount of code and a bit of CSS. 

Detail View 2.0: Code changes

First up, we need another variable to represent the “Read more” link shown in the screenshot above. This will be a link that opens the browser on the phone and takes the user to a website where they can read more about the particular story displayed in the detail view.

Link label variable

We’ve added the variable linkLabel to represent the link to the full story.

Next we modify the init() function to create a new Label control and assign the reference to the new control to the linkLabel variable.

Label initialisation without captions

We’ve also removed the captions from each of the four labels that will now make up the detail view by passing null as the first parameter to the Label control’s constructor. We don’t need the label captions anymore because we will use differences in style to provide visual cues as to the significance of each label.

We’re going to rely on CSS to improve the appearance of our detail view, but we need to make some more code changes to give our CSS a helping hand; specifically, we need to inject class names into each of the labels we want to style via CSS.

We can set the text of any WRTKit Label control to any arbitrary HTML we like. WRT will render the HTML when it renders the Label control, so provided the HTML is valid, the user should only see the text you intended them to see.

This technique allows us to easily wrap a piece of text intended to be shown to the user in a <div> tag and within the <div> tag we can specify a class attribute. The value of the class attribute can then be used in our CSS to selectively style particular elements in our UI.

Let’s update the implementation of our populateDetailView() function to add class names to our Label controls as appropriate:

Injecting CSS class names to labels

The titleLabel is simply wrapped in a <div> element which defines a class attribute with the value “DiggTitle”.

Similarly, the diggsLabel is wrapped in a <div> element which defines a class attribute with the value “Diggs”. In addition, we also insert a <br/> tag to force a new line; on this new line we add the text “diggs”. This effectively gives us one label which renders it’s content over two lines – the first line renders the number of diggs a story has had with the second line rendering the word “diggs”.

We’ve not changed the storyLabel because the default text styling is fine for the main text of the view.

Our new linkLabel control does require to be styled, in order to make it look like a hyperlink. So we enclose the text of the link in a <div> element with a class attribute which has the value “DiggLink”.

However, we need a little more substance as well as a bit of style in the case of the linkLabel. We need to do something useful when the user clicks the link.

We achieve this by adding a HTML <a> tag to our linkLabel’s text and specifing an href attribute with the value “JavaScript:openStoryLink(…)”.  We are not allowed to open a link directly from our widget’s HTML page, so we can’t just use the URL of the current story’s link property. Instead, by defining the href with the value “JavaScript:openStoryLink(…), WRT will try to invoke a function called openStoryLink() in our JavaScript code. The final thing to notice about the way we define the text of the linkLabel is that we construct the href value in such a way that we pass the numerical id of the story displayed in the detail view when the “Read more” link is clicked. For example, if we were showing the story with id = 3, the <a> tag would look something like this in the HTML of the page:

<a href=”JavaScript:openStoryLink(3)>Read more</a>

The final code change we need to make is to provide an implementation of the function openStoryLink(), otherwise nothing much will happen if the user clicks on the story link in our improved detail view.

As I noted above, we’re not allowed to open a link directly from within our widget’s HTML – the page rendered in your widget must never be replaced with a new page. We get round this by using functionality provided by WRT which allows us to open a link in the phone’s browser instead. The code to achieve this is:

Function to open a URL

If our widget is running in a WRT environment, we call openURL() on our inbuilt widget object, passing it the URL of the story with the id passed as the parameter to our function. openURL() will then launch the relevant link in your phone’s browser. When the user eventually closes the browser, they will be returned to our widget.

If our widget is running in another environment, for example, in a browser environment on your PC, we use JavaScript’s window object, which represents your browser’s window, to open a new window to display the link associated with the story.

That’s all the code changes we require. Now we can turn our attention to our as yet empty CSS file.

Detail View 2.0: Cascading Style Sheet

By implementing the code changes above, we defined three classes that can be referred to by CSS to selectively style content in our new detail view. The classes we defined were:

  • DiggTitle which refers to the title of a story
  • Diggs which refers to the number of Diggs a story has had
  • and DiggLink which refers to the hyperlink to the full story

Styling the title of our story is quite simple. We just need to use bold text, which we’ll centre. We also want the text a bit bigger than the story text, but we don’t want it to dominate our phone’s small screen. We’ll use the following CSS to define a suitable style:

CSS style for story title

This block of CSS starts with the class name to which it applies, preceded by a period. Within the block we specify that the font-weight should be bold, the text should be centred and that the font-size should be 1.25em. We use em as the unit of font size instead of specifying a fixed size because em’s are relative to the default size of the current font. This means that the title should look reasonably in proportion to the text of the story across a range of screen sizes.

Next, we style the number of diggs the current story has had, using the following CSS:

CSS style for number of diggs

We use a font size between normal size and the size used for the story title, which should make the number of diggs the story has had stand out a little. We then define a pale yellow background and centre the text within this element.

Next we define some padding to ensure there is a small gap top and bottom of our diggs element, which just helps to space the content out a little in our detail view. The four values given in the padding property specification define the padding between the element border and the element content in the order top, right, bottom and left. Hence, we’ve defined a 7 pixel gap top and bottom for our diggs element.

If we left it there, what we’d see would be a pale yellow box stretching across the width of our screen, with text centred over two lines. That’s not what we’re looking for. We want the number of diggs to be shown in a small box, similar to the way this information is shown on Digg. We can achieve this by defining a margin for our diggs element, as shown in the CSS block above.

What the margin definition above asks for is that our diggs element is rendered to the screen with 77% of the screen width used as a margin to the right of our element. Admittedly this technique will result in the width of the diggs element changing between devices with different screen widths. As with the padding property, the four values specified for the margin property define the margin around the top, right, bottom and left of the related element respectively.

Having styled the number of diggs a story has had, let’s now look at styling the link that will let users read more about the story. We do this in two parts. First we define some CSS to style the link in its unselected state, then we define a slightly different style for the link in its selected state.

Here’s the CSS for the unselected state:

CSS style for unselected link

This is quite simple, but there is one significant difference to the previous two styles. Rather than applying the style to the whole of the element referred to by the class name “DiggLink”, we only want to style the HTML <a> tag within the element referred to by the “DiggLink” class. We specify this by placing the element we want to apply the style to between the class name and the opening brace of the style definition.

We apply a typical style for hyperlinks, underlining the link, using blue text and rendering it in bold font to make it stand out.

When the user selects the link, we use a different style so the user can see a clear difference between the selected and unselected states:

 CSS style for selected link

As with the CSS for the unselected state, the CSS above defines a style that is applied to <a> tags within elements identified by the class “DiggLink”. However, we only want this style to be applied if the <a> element has focus. The CSS pseudo-class “:focus” is used to specify this constraint on the application of the above style.

The style itself simply inverts the text of the link, using white text on a blue background.

Goodbye “Hello”

We’re almost done. All we need to finish off is replace the “Hello” speech bubble icon we’ve been using since part 1 of the tutorial with something more relevant. Here’s what I’ve come up with:

New improved icon

I know it’s not very exciting, but I’m no graphic artist, so it’ll have to do. Feel free to replace it with something better if you’ve got the graphic ability. The new icon is included in the downloadable package associated with this part of the tutorial.

Coming next…

This concludes the fourth part of our tutorial on creating a Digg client with Nokia WRT & Aptana Studio. Next time we’ll look at getting our widget off our PC and on to our phone. Aptana gives us a helping hand in this task, but you’ll need some means of getting files from your PC to your phone, such as a cable or Bluetooth, or a card reader.

Part 5>

1 comment:

  1. Hi,
    Your presentation was very useful.I have one major problem.When I tap on digg button,Nothing happens.Could you please explain me how does digg.com external site is accessible from aptana studio?

    ReplyDelete