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
BackRead original postSend to a friend
Add comment
Add comment Show all posts
|