Dynamic Pages

dynamic_bg

I already discussed dynamic Creation of Objects to speed up start time and to free memory as soon as possible.

Now let’s talk about dynamic Pages / Sheets where it depends from

  • data
  • settings
  • workflow and  status

how a Page will be layouted: which Containers, Fields or other Controls must be created, which ActionItems are available, where to change Visibility, Opacity or Icons and Colors ?

There’s an important rule you should always follow:

Spotlight On: Present relevant information only

spotlight

This can be easy explained taking a look at Categories and follow the impact of changing some properties.

Here are the Settings Category for

  • Working Time
  • Travel Time
  • Break / Rest

Swork_travel_break

Working Time:

  • Project: mandatory
  • Order: mandatory
  • Task: optional
  • Contact: mandatory

Travel Time:

  • Task: optional

Rest / Break

  • nothing

How does this look from Details Segment of Tracked Times Details:

DetailWork_travel_break

Only required or optional fields are visible to get User’s focus on the important things.

Please note the green Checkmark at Project and Order: this means both fields have a Validator attached and Validation Rules are checked and OK.

Container {
    id: projectEntryContainer
    visible: categoryMap.project
    TextField {
        id: projectText
        enabled: isEditable
        hintText: qsTr("Short project reference")
        validator: Validator {
            id: projectTextValidator
            mode: ValidationMode.Immediate
            errorMessage: qsTr("You must enter the Project Reference")
            onValidate: {
                if (! categoryMap.project || categoryMap.projectOptional || projectText.text.length > 0)
                    state = ValidationState.Valid;
                else
                    state = ValidationState.Invalid;
            }
        }
    }
}

The Container is only visible if Category requires a Project. TextField Validator checks if User has entered some Text or Project is optional.

Now let’s take a look at GPS Timestamps / GeoLocation.

Working Time:

  • requires GPS Stams at Start and Stop

TravelTime:

  • requires continuous GPS Tracking

Rest / Break:

  • requires NO GPS Tracking to guaranteee privacy

Now lets take a look at the Overview from Category Segment of Tracked Times Details:

OverviewWork_travel_break

Please note the different Icons for Geocoding / GPS Tracking: Working Time requires GPS Stamps at Start and Stop and displays a Marker with 2 flags. Travel Time requires continuous GPS Tracking and displays the earth. Rest/Break has no GPS stamps and gets another icon representing this state.

Contact is mandatory for Working Time, so there’s a Contact Icon, where TravelTime and Break have no Contact requested and th Icon is nearly invisible (Opacity 0.3). Contact Icon for Working Time is colored, so we know that there’s a Customer added.

You can see that you only have to set some properties or to change an Icon to provide an easy to understand UI where the important stuff is immediately recognized.

Dynamic TitleBars

Not only Pages can be dynamically – also TitleBars can reflect informations and dynamically change content.

If running TimeTracker Enterprise Edition your tracked data must be transmitted to server – this can be done manually or automatically. From Settings TimeTracker knows about the rules:

  • transmit Data always
  • transmit Data only if not Roaming
  • transmit Data only from WiFi

It’s the nature of a mobile app: you’re not always online, sometimes roaming and not always have access to WiFi. So transmitting data is a two-steps-operation:

  1. select data to be transmitted and put it in a Queue (can be done manually or automatically)
  2. from Queue send to server if all rules are valid – per ex. ‘not in roaming’

There’s an extra Tab (only visible if you’re running the Enterprise Edition) to see what’s inside the Queue and waiting. If nothing goes out and the Queue grows and grows users must inspect Settings from phone to find out the reason. To make this immediately visible I implemented a special TitleBar containing Icons reflecting the network state.

Here are some screenshots

WiFi available, Internet connection OK:

ServerTitlebarAll

NO WiFi, Internet connection OK:

ServerTitlebarNoWiFi

If no WiFi and Roaming the first Icon will change to:

signal_roaming

No Network, No Internet Connection:

ServerTitlebarNothing

Adding some icons to your TitleBar and connecting them to Signals if NetworkState changes tells your user the complete story why data wasn’t transmitted.

To provide such kind of dynamic TitleBars Cascades gives you the FreeFormTitleBar:

ComponentDefinition {
     id: serverTitlebarComponent
    TitleBar {
        id: serverTitlebar
        property alias titleText: titlebarLabel.text
        kind: TitleBarKind.FreeForm
        scrollBehavior: TitleBarScrollBehavior.Sticky
        kindProperties: FreeFormTitleBarKindProperties {
            Container {
                rightPadding: 10
                leftPadding: 20
                layout: StackLayout {
                    orientation: LayoutOrientation.LeftToRight
                }
                Label {
                    id: titlebarLabel
                    text: "Titlebar"
                    textStyle.base: SystemDefaults.TextStyles.TitleText
                    textStyle.color: Color.White
                    verticalAlignment: VerticalAlignment.Center
                    layoutProperties: StackLayoutProperties {
                        spaceQuota: 1
                    }
                }
                Container {
                    layout: StackLayout {
                        orientation: LayoutOrientation.LeftToRight
                    }
                    verticalAlignment: VerticalAlignment.Center
                    // images will be automatically updated from C++
                    // as soon as any events are fired
                    ImageView {
                        id: wifiSignalImage
                        objectName: "wifiSignalImage"
                        imageSource: "images/titlebar/no_signal.png"
                        verticalAlignment: VerticalAlignment.Center
                    }
                    ImageView {
                        id: onlineOfflineImage
                        objectName: "onlineOfflineImage"
                        imageSource: "images/titlebar/offline.png"
                        verticalAlignment: VerticalAlignment.Center
                    }
                }
            }
        }
    }
} // end serverTitlebarComponent

I defined the ServerTitleBar as a ComponentDefinition attached to my root object (TabbedPane). Read here about dynamic creation.

This ServerTitleBar is used from some of my Pages and as soon as these Pages are created dynamically I create and add the TitleBar. Then the Page becomes the owner and this TitleBar will be destroyed together with the Page.

Layout of this TitleBar is a simple StackLayout using a Label for the Title and two Icons. These Icons will change if NetworkState is changing. This stuff is done by C++ methods like this one:

void Rest::updateServerTitleBarNetstatus(int netstatusInfo)
{
    // there can be some pages using a ServerTitlebar
    QList<ImageView*> images = Application::instance()->scene()->findChildren<ImageView*>(
            "wifiSignalImage");
    if (images.size() > 0) {
        QString imageSource = QDir::currentPath() + "/app/native/assets/images/titlebar/";
        switch (netstatusInfo) {
            case NetstatusInfo::WifiOrBETTER:
                imageSource += "wifi.png";
                break;
            case NetstatusInfo::Cellular:
                if (roaming()) {
                    imageSource += "signal_roaming.png";
                } else {
                    imageSource += "signal.png";
                }
                break;
            case NetstatusInfo::Offline:
                imageSource += "no_signal.png";
                break;
            default:
                return;
        }
        for (int i = 0; i < images.size(); ++i) {
            ImageView* image = images.at(i);
            image->setImageSource(imageSource);
        }
    }
}

Creating the ServerTitleBar per ex. from ServerQueueListPage is done in onCreationCompleted{}:

onCreationCompleted: {
        // set parent to the Page where the TitleBar belongs to, so it will be destroyed with the Page
        serverQueueListPage.titleBar = rootPane.serverTitleBar(serverQueueListPage)
        serverQueueListPage.titleBar.titleText = qsTr("List of queued Data")
    }

this is the function from rootPane:

function serverTitleBar(parent) {
    return serverTitlebarComponent.createObject(parent)
}

As you can see the TitleBar was created from ComponentDefinition with ServerQueueListpage as parent.

I’m using such kind of TitleBars in some of my apps, sometimes also adding Login/Logoff Icons to visualize if User is logged in or not.

More UX Highlights: