Qt-based BB10 API Examples Documentation

Contents

BBM Contacts Example

Files:

Description

The BBM Contacts example demonstrates how to retrieve your list of contacts(that have the same application installed) from the BBM Social Platform.

Overview

In this example we'll learn how to use the ContactService class of the bb::platform::bbm module to retrieve your contacs, that have the same application installed, from the BBM Social Platform.

To use the BBM Social Platform, the application must register first. How this is done is explained in bbmregistration and this sample is based on that code. We will describe here everything that needs to be done after the registration was successful.

The business logic of this application is encapsulated in the ContactsDisplay class, and the Contact class, which is exposed to QML as a metatype.

UI

The main UI of this application is shown after a successful registration.

The Contacts display page

    Field {
        id: contactCount
        objectName: "contactCount"
        title: qsTr("BBM Contacts")
        value: "0"
    }

It consists of one page with a single field to display a single value of the number of contacts found to have your application installed.

    // The list of contacts
    ListView {
        objectName: "contactListView"

        listItemComponents: [
            ListItemComponent {
                ContactItem {
                }
            }
        ]
        // Create Contact page upon the user selecting a contact from the list
        onTriggered: {
            //This gives the selected contact.
            var page = contactPage.createObject();
            page.contact = dataModel.data(indexPath);
            navigationPane.push(page);
        }
    }

Following this field is the ListView containing those contacts. Whenever the user triggers one of the ContactItem's, an instance of the ContactPage page is created through a ComponentDefinition and pushed on the navigation pane.

    attachedObjects: ComponentDefinition {
        id: contactPage
        source: "ContactPage.qml"
    }

The list items are represented by custom ListItemComponent called ContactItem. Which consists of two labels to display the Contact's brief summary (display name, personal message), and his/her avatar in a LeftToRight order.

    // Container that represents a Contact in the ListView
    Container {

        topPadding: 40
        leftPadding: 40
        rightPadding: 40

        Container {
            Container {
                layout: StackLayout {
                    orientation: LayoutOrientation.LeftToRight
                }

                Container {
                    layoutProperties: StackLayoutProperties {
                        spaceQuota: 1
                    }
                    // Contacts display name
                    Label {
                        verticalAlignment: VerticalAlignment.Center

                        text: ListItemData.displayName
                        textStyle {
                            color: Color.White
                        }
                    }
                    // Contacts personal message
                    Label {
                        verticalAlignment: VerticalAlignment.Center
                        leftMargin: 50.0

                        multiline: true

                        text: ListItemData.personalMessage
                        textStyle {
                            color: Color.White
                            fontSize: FontSize.Small
                        }

                    }
                }
                // The Contacts display image
                ImageView {
                    verticalAlignment: VerticalAlignment.Center

                    image: ListItemData.avatar
                    scalingMethod: ScalingMethod.None
                    preferredHeight: 100
                    preferredWidth: 100
                }
            }
            Container {
                background: Color.White

                Divider {
                }
            }
        }
    }

The Contact Page

    ImageView {
        preferredHeight: 300
        preferredWidth: 300

        image: contact ? contact.avatar : null
    }

At the top an ImageView is located to show the Contact avatar. The image is provided through the 'avatar' property of the Contact object and uses a placeholder image by default. Only when the call to the ContactService::requestDisplayPicture() method is successful, the real avatar image replaces the placeholder image in the property.

    ImageView {
        verticalAlignment: VerticalAlignment.Center

        imageSource: "images/busy.png"
        visible: contact ? contact.busy : false
    }

    Label {
        layoutProperties: StackLayoutProperties {
            spaceQuota: 1
        }

        text: contact ? contact.displayName : "n/a"
        textStyle {
            color: Color.White
            fontWeight: FontWeight.Bold
        }
    }

Below the avatar, an ImageView and a Label are located that show the current busy status and the name of the Contact. Depending on the value of the Contact's 'busy' property, the busy indicator is visible or hidden.

    Field {
        title: qsTr("status message")
        value: contact ? contact.statusMessage : "n/a"
    }

For all the other data of the Contact, a Field is created, which is a custom component (implemented in Field.qml) with two Labels side by side. The left Label displays the title of the field and the right Label the corresponding value. All the Contact data are provided by Contact through properties, which we simply bind against the Field's 'value' property.

The Contact class

The Contact class encapsulates the information about the users contact and makes the data available through properties.

    class Contact: public QObject
    {
            Q_OBJECT
            // Property to display contacts handle
            Q_PROPERTY(QString handle READ handle NOTIFY contactChanged)

            // Property to indicate users ppId
            Q_PROPERTY(QString ppid READ ppid NOTIFY contactChanged)

            // Property that indicates this app version running on the contacts device
            Q_PROPERTY(QString appVersion READ appVersion NOTIFY contactChanged)

            // BBM Social Platform version that is running on a contact's device
            Q_PROPERTY(QString platformVersion READ platformVersion NOTIFY contactChanged)

            // The contacts display name
            Q_PROPERTY(QString displayName READ displayName NOTIFY contactChanged)

            // The contacts personal message
            Q_PROPERTY(QString personalMessage READ personalMessage NOTIFY contactChanged)

            // The contacts status
            Q_PROPERTY(QString statusMessage READ statusMessage NOTIFY contactChanged)

            // Property to indicate contacts availability
            Q_PROPERTY(bool busy READ busy NOTIFY contactChanged)

            // The contacts avatar image
            Q_PROPERTY(QVariant avatar READ avatar NOTIFY avatarChanged)

    public:
            Contact() { }

            /**
             * Default constructor.
             */
            Contact(const bb::platform::bbm::Contact &contact);
            ~Contact();

            QString handle();
            QString ppid();
            QString appVersion();
            QString platformVersion();
            QString displayName();
            QString personalMessage();
            QString statusMessage();
            // Returns true if the contact's status is busy; otherwise, returns false.
            bool busy() const;
            QVariant avatar();

    Q_SIGNALS:
            // Emitted when contact info changes
            void contactChanged();
            // Emitted when contact avatar changes
            void avatarChanged();

    public Q_SLOTS:
            // Corresponds to the bb::platform::bbm::ContactService::displayPictureUpdate() signal
            void avatarUpdated (const QString &handle, const bb::platform::bbm::ImageType::Type imageType, const QByteArray &displayPicture);

    private:
            void setAvatar(const QByteArray &imageData);
            const bb::platform::bbm::Contact m_bbmspContact;
            bb::cascades::Image m_avatar;
    };

Inside the constructor the member variables are initialized.

    Contact::Contact(const bb::platform::bbm::Contact &contact) :
                    m_bbmspContact(contact) {
            // Load the place holder for the display image (avatar)
            // Image by Decosigner: http://openclipart.org/detail/104977/help-orb-button-by-decosigner
            m_avatar = bb::cascades::Image(QUrl("asset:///images/avatarPlaceholder.png"));
    }

Whenever the ContactsDisplay class creates or updates a Contact instance in the ListView model the requestDisplayPicture() method is invoked, this in turn updates the Contact avatar image. This is the result of having the displayPictureUpdate signal of the ContactService object connected to our own avatarUpdated slot, so that whenever the contact changes we retrieve it's image right away. Inside this method we verify that the avatarUpdate is for this Contact using handle comparison, afterwards we take the raw image data that is provided, create an Image object from it, since ImageView can only use that one as input, and emit the change notification signal to let the ImageView update its representation.

    void Contact::avatarUpdated(const QString& handle,
                    const bb::platform::bbm::ImageType::Type imageType,
                    const QByteArray& displayPicture) {

            Q_UNUSED(imageType);
            //Verify the update handle corresponds to this contact handle
            if (QString::compare(m_bbmspContact.handle(), handle) == 0) {
                    // Verify that there is an image to be set.
                    if(displayPicture.size() != 0) {
                            setAvatar(displayPicture);
                    }
            }
    }

    void Contact::setAvatar(const QByteArray &imageData) {
            m_avatar = bb::cascades::Image(imageData);
            Q_EMIT avatarChanged();
    }

In all the other property accessor methods, we simply return the values as we get them from the bb::platform::bbm::Contact object.

    QString Contact::displayName() {
            return m_bbmspContact.displayName();
    }

    QString Contact::personalMessage() {
            return m_bbmspContact.personalMessage();
    }

The ContactsDisplay class

The ContactsDisplay class encapsulates the code that populates and updates the user contact list in the ListView.

    class ContactsDisplay: public QObject
    {
            Q_OBJECT

    public:
            /**
             * Default Constructor.
             */
            ContactsDisplay(bb::platform::bbm::Context &context, QObject *parent = 0);

    public Q_SLOTS:
            /**
             * Creates the ContactList qml document and sets
             * the application scene to it.
             */
            void show();

            /**
             * Updates the ListView model with your bbm contacts.
             */
            void updateModel();

            /**
             * Updates the contact in the datamodel with the
             * contact changes.
             */
            void contactUpdated(const QString &handle);

    private:
            bb::platform::bbm::Context *m_context;
            bb::cascades::QListDataModel<Contact*>* m_contactsDataModel;
            bb::platform::bbm::ContactService * m_contactService;

    };

The class takes a reference to the Context object in the constructor, that instance is used later to create the ContactService. Additionally it provides three slots to create the ContactList.qml UI, update ListView model, and update a single contact.

    ContactsDisplay::ContactsDisplay(bb::platform::bbm::Context &context, QObject *parent)
            : QObject(parent)
            , m_context(&context)
            , m_contactsDataModel(new QListDataModel<Contact*>())
            , m_contactService(0)
    {
            m_contactsDataModel->setParent(this);
    }

Inside the constructor we just initialize the member variable.

After a successful registration to the BBM service, the show() slot of the ContactsDisplay class is invoked. The signal/slot connection for this is established in main.cpp

    RegistrationHandler *registrationHandler = new RegistrationHandler(uuid, &app);

    ContactsDisplay *contactsDisplay = new ContactsDisplay(registrationHandler->context(), &app);

    // Whenever the registration has finished successfully, we continue to the main UI
    bool ok = QObject::connect(registrationHandler, SIGNAL(registered()), contactsDisplay, SLOT(show()));
    Q_ASSERT(ok);
    Q_UNUSED(ok);

Inside the show() slot a new ContactService object is created using the supplied Context. This does the low-level communication with the BBM service. We connect all update signals of the ContactService object to our own update slots, so that our DataModel notify modifications as soon as any underlying Contact object is added or changed. We than retrieve the number of bbm contacts that have this application installed, update the qml field with this value and populate the QListDataModel with the Contact's.

At the end of this method, the UI is loaded from ContactList.qml

    void ContactsDisplay::show()
    {
            // Create the UI
            QmlDocument *qml = QmlDocument::create("asset:///ContactList.qml").parent(this);
            AbstractPane *root = qml->createRootObject<AbstractPane>();
            Application::instance()->setScene(root);

            m_contactService = new bb::platform::bbm::ContactService(m_context, this);

            // Connect the update signals to the model update slot
            bool ok = QObject::connect(m_contactService, SIGNAL(contactListUpdated()), this, SLOT (updateModel()));
            Q_ASSERT(ok);

            ok = QObject::connect(m_contactService, SIGNAL(applicationEnabled(const QString&)), this, SLOT (updateModel()));
            Q_ASSERT(ok);

            ok = QObject::connect(m_contactService, SIGNAL(applicationDisabled(const QString&)), this, SLOT (updateModel()));
            Q_ASSERT(ok);

            ok = QObject::connect(m_contactService, SIGNAL(contactUpdated(const QString&)), this, SLOT(contactUpdated(const QString&)));
            Q_ASSERT(ok);

            if (m_contactService->isValid()) {
                    updateModel();
            }

            // Retrieve the Field.qml custom component and set it's value
            QObject* contactCountField = root->findChild<QObject*>("contactCount");
            QString contCount = QString("%1").arg(m_contactService->contactCount());

            contactCountField->setProperty("value", contCount);

            // Retrieve the ListView and set its datamodel
            ListView* contactListView = root->findChild<ListView*>("contactListView");
            contactListView->setDataModel(m_contactsDataModel);

            qDebug() << contCount;
    }

The updateModel() method retrieves a list of Contact's, that have your application installed, using the ContactService. Afterwards, it creates a Contact instance for each one of them and connects the displayPictureUpdated signal to our avatarUpdated slot in order to receive the contact display image when requestDisplayPicture() is made via ContactService.

    void ContactsDisplay::show()
    {
            // Create the UI
            QmlDocument *qml = QmlDocument::create("asset:///ContactList.qml").parent(this);
            AbstractPane *root = qml->createRootObject<AbstractPane>();
            Application::instance()->setScene(root);

            m_contactService = new bb::platform::bbm::ContactService(m_context, this);

            // Connect the update signals to the model update slot
            bool ok = QObject::connect(m_contactService, SIGNAL(contactListUpdated()), this, SLOT (updateModel()));
            Q_ASSERT(ok);

            ok = QObject::connect(m_contactService, SIGNAL(applicationEnabled(const QString&)), this, SLOT (updateModel()));
            Q_ASSERT(ok);

            ok = QObject::connect(m_contactService, SIGNAL(applicationDisabled(const QString&)), this, SLOT (updateModel()));
            Q_ASSERT(ok);

            ok = QObject::connect(m_contactService, SIGNAL(contactUpdated(const QString&)), this, SLOT(contactUpdated(const QString&)));
            Q_ASSERT(ok);

            if (m_contactService->isValid()) {
                    updateModel();
            }

            // Retrieve the Field.qml custom component and set it's value
            QObject* contactCountField = root->findChild<QObject*>("contactCount");
            QString contCount = QString("%1").arg(m_contactService->contactCount());

            contactCountField->setProperty("value", contCount);

            // Retrieve the ListView and set its datamodel
            ListView* contactListView = root->findChild<ListView*>("contactListView");
            contactListView->setDataModel(m_contactsDataModel);

            qDebug() << contCount;
    }

The contactUpdated() method searches through the ListView data model to find the Contact with the specified handle, once it is found it is replaced with the new Contact instance and the appropriate connections are made in order to get the contact display image update.