Building an Ubuntu SDK App: rev 2

In my previous article I discussed how I got started with a new Ubuntu SDK app, and how easy it was to get a listing of Reddit articles displayed in a simple list. In my second revision, I added image thumbnails to that list, the ability to change to a different subreddit, and finally the capability to actually display the article’s content.

Thumbnails

For some subreddits, Reddit will provide an image thumbnail to go along with the article.  Not only is this a nice feature of Reddit, but it’s also supplied as part of their API.  Since ListItem.Subtitled derives from ListItem.Base, it also has an optional icon property that can conveniently take a URL.  This made adding the thumbnail to my ListView incredibly easy.

Since not all articles have a thumbnail image, for now I just used a placeholder (the avatar image you get from the template).  I also didn’t do anything to make sure the images would fit in the ListItem.  In later revisions I would get a little smarter about how I handled thumbnails.


ListView {
    id: articleList
    ...
    delegate: ListItem.Subtitled {
        ...
        icon: (model.data.thumbnail) ? model.data.thumbnail : Qt.resolvedUrl("avatar.png")
        ...
    }
}

Changing Subreddits

Now that the subreddit article list in a pretty good state, I turned my attention to being able to change from one subreddit to another.  Revision 1 had a text input and button for this, but due to my not understanding QML layout this was hidden behind the header in those earlier screenshots.

So this time I decided to use another Ubuntu SDK component, Popups.Dialog, to show the form as an overlay on top of the article list.  This was very simple to do, and it looks so much nicer and more professional too.  The default theme that you get with the Ubuntu SDK makes it easy to make good looking apps, even if you’re not a designer.

The Dialog itself is straight forward, you simply wrap it up in a Component (you’ll see why later), give it a title and a bit of descriptive text for the user, and add your widgets to it.  All I needed was a TextField and a Button.  Since the Reddit “Frontpage” doesn’t have a subreddit, I decided to use no subreddit value to mean “Frontpage”, and used the TextField’s placeholderText property to display that when the TextField was empty (and yes I called it “Homepage” at first, I did correct it in later revisions).

    Component {
         id: dialogComponent
         Popups.Dialog {
             id: dialog
             title: "Change Subreddit"
             text: "Select a new Subreddit"

             TextField {
                 id: subreddit
                 placeholderText: 'Homepage'
                 text: currentSubreddit
             }
             Button {
                 id: 'goButton'
                 text: 'Go'
                 color: 'green'
                 onClicked: {
                     currentSubreddit = subreddit.text
                     PopupUtils.close(dialog)
                 }
             }
         }
    }

To call up the dialog, I added a new button to the bottom toolbar.  Since I hadn’t added any before (the “Back” button was provided by PageStack) I had to give my subreddits page a property called tools that contains a ToolbarActions instance.  Inside of that, I was able to add an Action for opening my dialog.  Here is why you needed to wrap your Dialog in a Component, because it’s the component that you need to pass to PopupUtils.open.

    tools: ToolbarActions {
        Action {
            id: subredditAction
            objectName: "action"

            iconSource: Qt.resolvedUrl("avatar.png")
            text: i18n.tr("Subreddit")

            onTriggered: {
                PopupUtils.open(dialogComponent, subredditAction.itemHint)
            }
        }
    }

 

Viewing Articles

Now that I could change subreddits, and my subreddit article list was starting to look pretty good, I really, Really wanted to be able to view the contents of those articles.  Since I had no idea what the contents would be (webpage, image, video, reddit comments page), I wanted to be able to display anything that could be posted to Reddit, which essentially means I needed a browser.

Fortunately, the popular and powerful WebKit browser engine has a Qt component, which makes adding it to a QML dead simple.  So in my articleView page, I just needed to add the WebView component. I did have to set the visible property to false, otherwise it would display the content of the WebView, even when the articleView page wasn’t (I suspect it has something to do with WebKit taking over rendering from Qt/QML).

Page {
    id: articleView
    title: 'Article'

    WebView {
        id: articleContent
        anchors.fill: parent
        url: ""
        scale: 1
        visible: false
    }
}

And then in the ListItem.onClicked callback handler I defined earlier, in addition to pushing the articleView page on to the top of the PageStack, I also had to set the url property of the WebView. I also set the title of the articleView page to be the article’s title. Finally, I have this callback set the visibility to true to that it would actually be displayed.

ListView {
    id: articleList
    ...
    delegate: ListItem.Subtitled {
        ...
        onClicked: {
            articleView.title = model.data.title
            articleContent.url = model.data.url
            articleContent.visible = true
            pageStack.push(articleView)
        }
    }
}

Property Change handlers

One important bit of code that changed in this revision was the addition of a global currentSubreddit property (you can see it being used in the change subreddit dialog). In QML, any property you define will automatically get an on<Property>Changed callback. This means that I got an onCurrentSubredditChanged callback (camel case, which means the first letter of your property name is capitalized), so I used that to make the appropriate changes to the other components in my app.

    property string currentSubreddit: ''
    function onCurrentSubredditChanged() {
        console.debug('Changing Subreddit: '+currentSubreddit)
        if (currentSubreddit != '') {
            subredditFeed.source = "http://www.reddit.com/hot.json"
            subreddits.title = 'Homepage'
        } else {
            subredditFeed.source = "http://www.reddit.com/r/"+currentSubreddit+"/hot.json"
            subreddits.title = '/r/'+currentSubreddit
        }

        pageStack.clear()
        pageStack.push(subreddits)
    }

Another consequence of getting these automatic property change callbacks, is that you usually just need to change a component’s property in order to get it to do something. In this case, changing the source property on my JSONListModel was enough to make it load the new Reddit API data, which was then enough for my ListView to drop it’s currently items and add the new ones just loaded into the model. It really does border on magical sometimes.

Next time: Refactoring

Up until this point, all of the code I’ve been writing was in a single uReadIt.qml file, and it was starting to get rather large. But with QML it doesn’t need to be that way (and really, it shouldn’t be that way), so for revision 3 I decided to split it out into separate files.

Read the next article

This entry was posted in OpenSource, Programming, Projects and tagged , , , , , , . Bookmark the permalink.

6 Responses to Building an Ubuntu SDK App: rev 2

  1. payload says:

    Bug – condition should be other way around

    if (currentSubreddit != ”) {
    subredditFeed.source = “http://www.reddit.com/hot.json”
    subreddits.title = ‘Homepage’
    } else {
    subredditFeed.source = “http://www.reddit.com/r/”+currentSubreddit+”/hot.json”
    subreddits.title = ‘/r/’+currentSubreddit
    }

  2. Dan says:

    Hey Michael,

    looking forward to seeing your refactoring. There are not a lot of tutorials on how to arrange your code in a project sense. Lots of tuts show you how to use features and put them in a simple, single, file.

    I would like to see some tuts on how to organsise/order a ‘project’ with real world examples.

    I hope this makes sense.

    • Michael Hall says:

      Thanks Dan,

      I won’t guarantee that my refactoring will represent the “best” or “proper” way to organize code in a project, it’s mostly just a matter of what seems right to be at the moment. At any rate, it’ll be something that works, and shows how to link code from various files into a single program.

  3. Pingback: Building an Ubuntu SDK App: rev 1 | Michael Hall

  4. Pingback: Building an Ubuntu SDK App: rev 5-6 | Michael Hall

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>