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
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
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:
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:
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:
- select data to be transmitted and put it in a Queue (can be done manually or automatically)
- 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:
NO WiFi, Internet connection OK:
If no WiFi and Roaming the first Icon will change to:
No Network, No Internet Connection:
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:
You must be logged in to post a comment.