Weekend Coder: Using ListView to create an RSS feed

By Brian Scheirer on 8 Sep 2013 05:35 pm
2
loading...
21
loading...
41
loading...

Way back at my first conference, BlackBerry Jam Americas 2012, I heard an interesting statistic: 80% of all apps contain lists. And if you think about it's not that surprising of a statistic considering most of the social network apps (Twitter, Facebook, etc) and everyone's favorite app, CB10, are a list of items. Because of that BlackBerry made sure to have a very good feature for lists, and they do called ListView. So this tutorial will mainly focus on ListView but will have a few other features to make the sample application a bit more full featured.

A bit more back story about this tutorial (feel free to skip this part if you just want to learn coding stuff), I wrote this example app very quickly (given a 2 day deadline) for a friend who lives in Trinidad and Tobago and wanted to show it off at a local developer meet up. So the feed is for a local newspaper there. But since RSS feeds usually follow the same .xml format you should be able to replace the source with any feed of your choosing. Finally, this tutorial may not be the best one to read if you are completely new to Cascades because I skip some explanations for the sake of length. On to the tutorial...

Before we set up our ListView, since we know we are going to use certain imports and libraries let's call those in first. So at the top of the page along with bb.cascades 1.0 we need to import in the data library.

import bb.cascades 1.0
import bb.data 1.0

Then in our .pro file we need the following libraries.

LIBS += -lbbdata -lbbsystem -lscreen

ListView

Now let's set up the ListView.  The basic components are ListItemComponent {} which holds the display of the list items, GroupDataModel {} which sorts the data, and DataSource which is exactly what it sounds like, the source of your data. So that general setup would look something like the following

import bb.cascades 1.0
import bb.data 1.0
Page {
    id: newsPane
    Container {
        ListView {
            id: myListView
            dataModel: myDataModel
            listItemComponents: [
                ListItemComponent {
                    type: "header"
                },
                ListItemComponent {
                    type: "item"
                }
            ]
            onTriggered: {
            }
        }
    }
    attachedObjects: [
        GroupDataModel {
            id: myDataModel
        },
        DataSource {
            id: myDataSource
            source: ""
            query: ""
            type: DataSourceType.Xml
            onDataLoaded: {
            }
        }
    ]
    onCreationCompleted: {
        myDataSource.load();
    }
}

Now that we have the framework of our ListView we can start filling in our information. First the The DataSource, we need the source: "" and query: "" and then onDataLoaded: {} we want to clear the list then populate it from our source.

DataSource {
            id: myDataSource
            source: "http://newsday.co.tt/rss.xml"
            query: "/rss/channel/item"
            type: DataSourceType.Xml
            onDataLoaded: {
                myDataModel.clear();
                myDataModel.insertList(data)
            }
        }

Next the GroupDataModel has sortingKeys which we'll want to sort by date, and the tag in the .xml file is "pubdate"

GroupDataModel {
            id: myDataModel
            sortingKeys: [
                "pubDate"
            ]
            sortedAscending: false
            grouping: ItemGrouping.ByFullValue
        }

Finally the display of the actual list. For both the header and item let's use custom compoents (rather than StandardListIem) to exactly control the look of components. In this example I didn't want any "header" to show so the easiest way to have that is to have the header as a Container with a blank Label

ListItemComponent {
                        type: "header"
                        Container {
                            Label {
                                text: ""
                            }
                        }
                    }

Then for the "item" compoenent with a stack of Labels with the article title, date, and description. To help separate the feed items, I've inserted a Divider at the bottom of my custom component.

ListItemComponent {
                        type: "item"
                        // Custom List compoents
                        Container {
                            Label {
                                text: ListItemData.title
                                textStyle.fontWeight: FontWeight.Bold
                                multiline: true
                            }
                            Label {
                                text: ListItemData.pubDate
                            }
                            Label {
                                text: ListItemData.description
                                textStyle.fontSize: FontSize.Small
                                multiline: true
                            }
                            Divider {
                            }
                        }
                    }

Additional Features

A stylized title bar can be added to the top of the page. In this example I use name of the newspaper as the title.

Page {
        titleBar: TitleBar {
            title: "Newsday"
        }
...
}

The ListView should now be fully set up, however there will be only the info pulled from the .xml shown. Typically a user expects to be able to click on an item and it brings them to the full article and that can be done using the onTriggered: {} signal and a WebView. The WebView will be added to the attached objects inside of Page. To give the WebView page a full set a features, I have also added a ScollView, and a ProgressIndicator for a loading bar. Additionally for the push/pop navigation to work everything needs to be in a NavigationPane. At this point it is easiest to these all added at once.

import bb.cascades 1.0
import bb.data 1.0
NavigationPane {
    id: newsPane
    Page {
        titleBar: TitleBar {
            title: "Newsday"
        }
        Container {
            ListView {
                id: myListView
                dataModel: myDataModel
                listItemComponents: [
                    ListItemComponent {
                        type: "header"
                        Container {
                            ...
                        }
                    },
                    ListItemComponent {
                        type: "item"
                        // Custom List components
                        Container {
                            ...
                        }
                    }
                ]
                onTriggered: {
                    var feedItem = dataModel.data(indexPath);
                    var page = detailsPage.createObject();
                    page.htmlContent = feedItem.link;
                    newsPane.push(page);
                }
            }
        }
    }
    attachedObjects: [
        GroupDataModel {
            id: myDataModel
            ...
        },
        DataSource {
            id: myDataSource
            ...
        },
        ComponentDefinition {
            id: detailsPage
            Page {
                property alias htmlContent: detailsView.url
                Container {
                    layout: DockLayout {
                    }
                    Container {
                        ScrollView {
                            scrollViewProperties.scrollMode: ScrollMode.Both
                            scrollViewProperties {
                                pinchToZoomEnabled: true
                                    maxContentScale: 5
                                    minContentScale: 1
                            }
                            WebView {
                                id: detailsView
                                settings.zoomToFitEnabled: true
                                settings.activeTextEnabled: true
                                onLoadProgressChanged: {
                                    // Update the ProgressBar while loading.
                                    progressIndicator.value = loadProgress / 100.0
                                }
                                onLoadingChanged: {
                                    if (loadRequest.status == WebLoadStatus.Started) {
                                        // Show the ProgressBar when loading started.
                                        progressIndicator.opacity = 1.0
                                    } else if (loadRequest.status == WebLoadStatus.Succeeded) {
                                        // Hide the ProgressBar when loading is complete.
                                        progressIndicator.opacity = 0.0
                                    } else if (loadRequest.status == WebLoadStatus.Failed) {
                                        // If loading failed
                                        
                                        html = "Check Internet connection?"
                                        progressIndicator.opacity = 0.0
                                    }
                                }
                            }
                        }
                    }
                    Container {
                        bottomPadding: 25
                        horizontalAlignment: HorizontalAlignment.Center
                        verticalAlignment: VerticalAlignment.Bottom
                        ProgressIndicator {
                            id: progressIndicator
                            opacity: 0
                        }
                    }
                }
            }
        }
    ]
    onCreationCompleted: {
        myDataSource.load();
    }
}

There are a few more things that can be added/enhanced, such as a more stylized "item" list component, but as I said at the beginning I wrote this sample relatively quickly. This should cover most features that are necessary for an RSS feed as well as uses quite a few other UI elements and design features too... Or just think of it as an RSRSS (Really Simple RSS, haha).

22 comments

Warlack

First!

Posted via CB10

thedustytaco

Knock knock. Who's there? First. First who? FIRST YOUR FACE!!!

shootsscores

Love these coding things. Please, use no abbreviations in the articles' headlines.

Flip4Bytes

The term RSS feed is used almost 100% of the time.. I wouldn't consider it really an abbreviation as its used more than the actual term..

- Developer of 'Web Design Cheat Sheet' for BB10 (Posted via CB10)

KermEd

In this particular case,

If you aren't familiar with the term RSS (which is no longer considered an abbreviation in developer terms) then you probably can't leverage this sample.

Good code bit. A final screen shot of the app in use might help junior devs know if they did it right :)

Posted via CB from my LE

Notcho

Wow so news finally.

Sent from The Legendary Zed10

Notcho

Some*

Sent from The Legendary Zed10

DisturbedRocks31

Do one about how to read from XML and save to XML.. or JSON...

emmuniz1

I guess because of the start of the 2013 NFL Season today is a slow day at the office... #Justsayin

#BlueNation #NYFootballGiants #NYFGiants4Ever #NYFGChamps #EliteEli #SalsaCruz #JustinBrickStrongTuck #JPPBeast #DoneDiehl #AllIn #DriveFor5 #BigBlue #GgggMen

I'm MongezaurioBerry

zhaoyizhi

ghcjjfhj

Posted via CB10

fast666

Down day today? Nothing to report !
Tomorrow may be a big news day about BBMforall, channels, or strategic planning. Just hoping.

ChannelX C000D3759 We review channels

Otech#CB

I'm a newbie to coding. Just started learning C#. What type of code is this?

Posted via CB10

ddddafadf

It's QML, a declarative language BlackBerry 10 uses for the UI. Cascades is kind of synonymous with QML.

Join the Surge Co. BBM Channel! C001213C9

martinjdub

Interesting info, thx!

Posted via CB10

DementedDevil

Otech

Tutorial is written in QML and has a little embedded C++.

I also program in C# (which is close-ish to C++) on Windows and Linux so hope you're having fun with that too!

Powered by Z10 on 10.2.0.1443 via DTAC 3G

alinet_Dev

Great tutorial for RSS could you make one to show how we can praise JSON data from a Web API using Http requests if you can.

Thanks

Ali,

Posted via CB10

scribl3

Great

Posted via CB10

Drazeni

Awesome Brian! Firstly, another super tutorial from you, especially for us up and coming devs. You're one of the guys who have become a great aid to me and I always look forward to more tutorials - well done!

I have an awesome app running now, although not perfect as I have a few niggles to resolve, especially to make the information look as presentable as possible..

1. One of them is the 'description' of the RSS item.. depending on which rss feeds I load, some of them show perfectly, others show html tags too. I'm assuming this is because not all RSS feeds are equal on formatting. Is there a way around this?
2. Also, some descriptions are near perfect except something like the apostrophe " ' " showing up as " ’ " for eg. I'm baffled as where to look, could this be dependent on language or something?

Thank you,
Mario.

Drazeni

Twitter has switched off the RSS feeds and suggested an API, from what I've read. So the sample app that Mattias mentioned above gives an error.. just to mention.

lawdawg123

Anyone know if there is a simple way, in the above example, to handle CDATA contained within the RSS feed?