ListView to create a RSS Feed

Elements/Components Used:

NavigationPane, ListView, WebView, ProgressIndicator

While at Jam Americas in September 2012, I heard an interesting statistic: 80% of all apps contain lists. Because of that BlackBerry made sure to have a very good feature for lists, and they do called ListView. Also I see a lot of requests for RSS feeds, which lend themselves perfectly to being shown in a list. 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 quickily (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 = "
<title>Loading Failed</title>
Check Internet connection?"
                                        progressIndicator.opacity = 0.0
                                    }
                                }
                            }
                        }
                    }
                    Container {
                        bottomPadding: 25
                        horizontalAlignment: HorizontalAlignment.Center
                        verticalAlignment: VerticalAlignment.Bottom
                        ProgressIndicator {
                            id: progressIndicator
                            opacity: 0
                        }
                    }
                }
            }
        }
    ]
    onCreationCompleted: {
        myDataSource.load();
    }
}
 

One final addition is to allow Orientation support, for viewing either portrait or landscape mode. This is easily done by changing the bar-descriptor.xml Orientation to "Auto-orient" on the Application tab. Then add the follow code to the onCreationCompleted {} signal.

onCreationCompleted: {
        myDataSource.load();
        OrientationSupport.supportedDisplayOrientation = SupportedDisplayOrientation.All;
    }
 

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).

-Brian