Supporting BlackBerry Passport – 10.3 Themes, SignatureAction, Touch on Keyboard

September 13, 2014 — Leave a comment

Welcome to part five of my article series on ‘Supporting BlackBerry Passport and 10.3 SDK / API’

First three parts of this article series help you to support the BlackBerry Passport from SDK / API 10.2 – the other ones are using SDK 10.3

Please read these articles before going on:

  1. Supporting BlackBerry Passport – step one 10.2
  2. Supporting BlackBerry Passport – Keyboard Shortcuts
  3. Supporting BlackBerry Passport – Fonts, Layouts, Logic
  4. Supporting BlackBerry Passport – Git, Colors and ActionBar

Switching themes

In part #4 we’ve seen that some pages won’t look so good in 10.3 because of bright ActionBar.

Here’s the Home Page of my TimeTracker App using the new compact ActionBar:

compact_actionBar2

I have to redesign this page for the bright theme without using black background. (Will do this later – needs some work on images)

As a first step I made the Theme configurable from settings – so users on Passport can switch to the dark theme:

settings_wow_dark

In my settings data I’m storing ‘Default’, ‘Dark’ or ‘Bright’ and check this at startup. app.visualStyle() returns my settings value.

I’m also calling this function immediately after saving the settings – Cascades dynamically changes the style.

function setVisualStyle(){
    if(app.visualStyle() == "Default"){
        return
    }
    if(app.visualStyle() == "Dark"){
        if (Application.themeSupport.theme.colorTheme.style == VisualStyle.Bright) {
            Application.themeSupport.setVisualStyle(VisualStyle.Dark);
        }
    } else {
        if (Application.themeSupport.theme.colorTheme.style == VisualStyle.Dark) {
            Application.themeSupport.setVisualStyle(VisualStyle.Bright);
        }
    }
}

There’s one rule: on devices using OLED  displays it’s not recommended to use the bright style, so I’m hiding this settings option:

QML

Container {
    id: visualStyleContainer
    visible: !app.isOrganicDisplayTechnology()
}

C++

bool ApplicationUI::isOrganicDisplayTechnology()
{
    bb::device::DisplayInfo display;
    return display.displayTechnology() == DisplayTechnology::Oled;
}

On a Z30 the user has no chance to switch to the bright theme, but on BlackBerry Passport users can toggle between dark and bright.

I also changed the Home Page to display only one button (Start or Stop) in the middle between TabMenu and ActionMenu – so it looks like the Signature ActionItem – only using a larger one. Here’s how it looks now using the dark theme:

home_onebutton_dark

Don’t use disabled Signature Actions

I already wrote about Signature ActionItems in part #4 of this series.

There may be situations where your Signature Action will be disabled – per ex. no data to send. Disabling ‘normal’ ActionItems is easy – simply set enabled to false. But using a Signature Action this doesn’t look well – even if the user has hidden all ActionItem Labels what’s possible in 10.3 from Device Settings.

Here’s an example how enabled / disabled SignatureActions are looking from bright or dark theme:

signature_disabled

Because the background color of a Signature Action remains the same for disabled Actions the difference between both states isn’t always easy to recognize. So for me it’s clear I never will disable a Signature ActionItem.

On the other side: having an enabled Signature Action telling the user after tapping on it that there’s no data to send isn’t the best solution😉

Unfortunately the ‘Signature’ property of an ActionItem can only be set once while creating the ActionItem so you cannot switch between OnBar and Signature.

Here’s how I’m dealing with this. Example is from TimeTracker’s Server Queue: sometimes there’s data inside the queue – sometimes not. If there’s data and network coverage TimeTracker will send queued data out automatically. Perhaps something went wrong and the user wants to trigger it manually – so there’s the ActionItem ‘Try again’.

If there’s nothing in the Queue I’m using a ‘normal’ disabled ActionItem:

queue_empty

If there’s some data,  the ActionItem was changed into an enabled Signature ActionItem:

queue_with_content

Now both states are easy to distinguish🙂

attachedObjects: [
     ActionItem {
        id: tryAgainAction
        title: qsTr("Try again")
        imageSource: "asset:///images/try_again.png"
        ActionBar.placement: ActionBarPlacement.Signature
        onTriggered: {
            // do your stuff
        }
    }
]
actions: [
    ActionItem {
        title: qsTr("Network")
        imageSource: "asset:///images/info_cloud.png"
        ActionBar.placement: ActionBarPlacement.OnBar
        onTriggered: {
            // do your stuff
        }
    },
    ActionItem {
        id: tryAgainActionDisabled
        title: qsTr("Try again")
        enabled: false
        imageSource: "asset:///images/try_again.png"
        ActionBar.placement: ActionBarPlacement.OnBar
        onTriggered: {
            // dummy
        }
    },
    ActionItem {
        id: adminAction
        title: qsTr("Admin")
        imageSource: "asset:///images/server.png"
        ActionBar.placement: ActionBarPlacement.OnBar
        onTriggered: {
            // do your stuff
        }
    }
]

There are now two Actionitems: one inside actions [ ] the other one as attached Object.

If the state changes I’m swapping the ActionItems. There’s no problem to remove / add the same Action more then one time because the removed Action still has the current Page as parent and can be reused.

if(tryAgainEnabled){
    removeAction(tryAgainActionDisabled)
    addAction(tryAgainAction)
} else {
    removeAction(tryAgainAction)
    removeAction(adminAction)
    addAction(tryAgainActionDisabled)
    addAction(adminAction)
}

I cannot insert an ActionItem at a specific position on ActionBar, so I’m also removing the adminAction and add again after adding the disabled tryAgainAction.

Please note: Adding the Signature ActionItem I don’t have to do this because a Signature Action always will be positioned in the middle.

Touch Enabled Keyboard and Scrolling (ListView, ScrollView)

How cool it is to scroll through pages from your touch enabled keyboard is easy to test:

Open the Browser and scroll through a long Page. If you need more space: rotate the Passport and scroll from the (now vertical positioned) keyboard.

Go back to your app and try to scroll through your Pages – if using ListView or ScrollView this should work.

uuups – some Lists or ScrollViews don’t scroll

At first I was thinking there’s a bug (Tested using a pre-release SDK and Simulator).

Then tried to find out which Pages scroll and which not – and finally found out the reason and it makes sense. So please don’t blame Cascades if a Page isn’t scrolling out of the box.

Remember: we’re on a Keyboard and Keyboard events are always working on the field having the Focus. If you want to enter a word into a TextField you have to Tap on the field or your app must use requestFocus() !

Same with Touch Events from your Passport Keyboard. In most Pages it will simply work, because the ScrollView or ListView is the first UI Control getting the focus automatically.

But this isn’t always true. I’m running into situations where a Page is structured this way:

  • Page
    • ScrollView disabled
      • Container for content if no-data-available
    • ListView
      • ListItems

Opening this Page with data in your List doesn’t scroll from keyboard because the ListView doesn’t have the Focus. The ScrollView has the Focus, but nothing to scroll because it’s disabled.

Now it’s up to you to manage the Focus if you’re running the app on a device like Passport where you can touch on the Keyboard: use Signals/Slots or functions.

function requestFocusToScrollTheList(){    
    if (dataModelTracked.size() && app.isKeyboardDevice()) {
        trackedList.requestFocus()
    }
}

Hint: don’t set the focus from onCreationCompleted{} – the Page must be visible before requesting the focus will work.

EDITED 2014-09-30:

There seems to be a bug (see this Issue) if scrolling from Touch-Keyboard, then from Touch-Screen, then back to Keyboard and scrolling stops working.

Workaround: at ListView set this policy:

ListView{    
    focusRetentionPolicyFlags: FocusRetentionPolicy.LoseToFocusable
}

Now also users of your app can benefit from the cool scrolling function using touch gestures on BlackBerry Passport🙂

It’s worth to support this – you know there will be the BlackBerry Classic later this year using a Trackpad besides the screen – I don’t know but could imagine it will work similar.

More Gestures on Keyboard

Scrolling is a built-in feature, but you can add your own touch functionality.

Here per ex. HowTo detect if the user swiped horizontally:

eventHandlers: [
    TouchKeyboardHandler {
        id: touchKeyboard
        property int startX
        property int stopX
        onTouch: {
            if (event.touchType == TouchType.Down) {
                startX = event.screenX
                return
            }
            if (event.touchType == TouchType.Up) {
                stopX = event.screenX
                var distance = Math.abs(stopX - startX)
                if (distance > 360) {
                    console.debug("Swiped horizontally " + distance)
                } else {
                    console.debug("distance too short")
                }
                return
            }
        }
    }
]

I’m testing if the user moved his fingers horizontally more then 360 px (around 25% of width of keyboard) – if device is in Landscape you must reduce the value.

Using Touch Events isn’t easy – please take a look at Cascades documentation, because this isn’t covered by this article series.

 

Next part will focus on Design Units. Have fun with BlackBerry Passport.

No Comments

Be the first to start the conversation!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s