Monthly Archives: July 2016

Improving appDefaults

I have tried to maintain a consistent user interface look by collecting all the UI related constants to a java library (appDefaults.js) that is imported to each application. The library defines the default page margins, the view header dimensions, the color scheme and other UI properties. Basically this approach has worked ok, but there are still some issues that have made me wonder if there was a better way to handle the UI properties. First of all the appDefault.js needs to be imported to each application page where the properties are needed. This might have a small effect to the page load time. Another issue is that there does not seem to be a way to adjust the property values inside the library file based on the device orientation (e.g. the view header dimensions are different for portrait and landscape modes). This means that I need to adjust the properties inside my QML components.

Here is an example of the Header.qml component. A lot of the spacing values need to be adjusted based on the orientation. I think this just adds unnecessary clutter to the code and makes it less readable.

import QtQuick 1.1
import com.nokia.meego 1.0
import "appDefaults.js" as AppDefaults

Item {
    property alias headerText: titleLabel.text
    property alias infoTopText: infoTop.text
    property alias infoBottomText: infoBottom.text
    property bool singleLineHeader: true

    property string viewHeader: "image://theme/color"+theme.colorScheme+"-meegotouch-view-header-fixed"
    property int headerTopSpacing : (inPortrait)?AppDefaults.HEADER_DEFAULT_TOP_SPACING_PORTRAIT:
                         AppDefaults.HEADER_DEFAULT_TOP_SPACING_LANDSCAPE
    property int headerBottomSpacing : (inPortrait)?AppDefaults.HEADER_DEFAULT_BOTTOM_SPACING_PORTRAIT:
                         AppDefaults.HEADER_DEFAULT_BOTTOM_SPACING_LANDSCAPE
    property int infoBottomSpacing : (inPortrait)?
                                         0.75*AppDefaults.HEADER_DEFAULT_BOTTOM_SPACING_PORTRAIT:
                                         0.5*AppDefaults.HEADER_DEFAULT_BOTTOM_SPACING_LANDSCAPE
    property string headerFontFamily : AppDefaults.FONT_FAMILY
    property int headerFontSize : AppDefaults.FONT_SIZE_LARGE
    property int infoTopFontSize: AppDefaults.FONT_SIZE_SMALL
    property int infoBottomFontSize: AppDefaults.FONT_SIZE_TINY

    // header dimensions
    height: (inPortrait)?AppDefaults.HEADER_DEFAULT_HEIGHT_PORTRAIT:
                          AppDefaults.HEADER_DEFAULT_HEIGHT_LANDSCAPE
    ...
}

After thinking about this it occured to me that I might as well create a QML component to store the UI default values. This would solve both the aforementioned java library issues: I could instantiate the component just to my main.qml file and all the properties would become available to all the child pages automatically, no need to import anything for those pages. I could also put the portrait/landscape tests inside that component and the actual UI pages would just see one property.

Below is the new AppDefaults.qml file. Note how the spacing parameters are set based on the orientation. And also the color scheme can be set here.

import QtQuick 1.1

Item {

    property int cCOLOR_SCHEME : 4
    property int cDEFAULT_MARGIN : 16

    property int cHEADER_DEFAULT_HEIGHT_PORTRAIT : 72
    property int cHEADER_DEFAULT_TOP_SPACING_PORTRAIT : 15
    property int cHEADER_DEFAULT_BOTTOM_SPACING_PORTRAIT : 15

    property int cHEADER_DEFAULT_HEIGHT_LANDSCAPE : 64
    property int cHEADER_DEFAULT_TOP_SPACING_LANDSCAPE : 9
    property int cHEADER_DEFAULT_BOTTOM_SPACING_LANDSCAPE : 13

    property string cFONT_FAMILY : "Nokia pure Text Light"
    property int cFONT_SIZE_LARGE : 32
    property int cFONT_SIZE_SMALL : 24
    property int cFONT_SIZE_TINY : 18
    property string cFONT_FAMILY_BUTTON : "Nokia pure Text"
    property int cFONT_SIZE_BUTTON : 20

    property int cTEXT_AREA_HEIGHT : 60
    property string cVIEW_HEADER : "image://theme/color"+cCOLOR_SCHEME+"-meegotouch-view-header-fixed"

    property int cHEADER_HEIGHT : (inPortrait)?cHEADER_DEFAULT_HEIGHT_PORTRAIT:
                          cHEADER_DEFAULT_HEIGHT_LANDSCAPE
    property int cHEADER_TOP_SPACING : (inPortrait)?cHEADER_DEFAULT_TOP_SPACING_PORTRAIT:
                         cHEADER_DEFAULT_TOP_SPACING_LANDSCAPE
    property int cHEADER_BOTTOM_SPACING : (inPortrait)?cHEADER_DEFAULT_BOTTOM_SPACING_PORTRAIT:
                         cHEADER_DEFAULT_BOTTOM_SPACING_LANDSCAPE
    property int cHEADER_REDUCED_BOTTOM_SPACING : (inPortrait)?
                         0.75*cHEADER_DEFAULT_BOTTOM_SPACING_PORTRAIT:
                         0.5*cHEADER_DEFAULT_BOTTOM_SPACING_LANDSCAPE

    Component.onCompleted:
        theme.colorScheme = cCOLOR_SCHEME

}

The AppDefaults component can now be instantiated into the main.qml file and that is basically all that needs to be done.

import QtQuick 1.1
import com.nokia.meego 1.0

PageStackWindow {
    id: appWindow

    initialPage: mainPage

    AppDefaults {
        id: appDefaults
    }

    MainPage {
        id: mainPage
    }
    ...
}

The Header.qml file will just import the needed QML libraries. It can refer directly to the appDefaults properties without any additional imports. And no orientation tests are needed so the code becomes cleaner.

import QtQuick 1.1
import com.nokia.meego 1.0

Item {
    property alias headerText: titleLabel.text
    property alias infoTopText: infoTop.text
    property alias infoBottomText: infoBottom.text
    property bool singleLineHeader: true

    property string headerFontFamily : appDefaults.cFONT_FAMILY
    property int headerFontSize : appDefaults.cFONT_SIZE_LARGE
    property int infoTopFontSize: appDefaults.cFONT_SIZE_SMALL
    property int infoBottomFontSize: appDefaults.cFONT_SIZE_TINY

    // header dimensions
    height: appDefaults.cHEADER_HEIGHT
    width: parent.width
    ...
}