Weather Forecast.

Weather forecast application provides weather updates of a city. Its easy to use the app. Simply enter the city name then select the interval and language and hit Search.
This app uses the weather information provided by openweathermap to fetch the weather information.
I have also published tutorial on how to code this app. The tutorial also covers various aspect for developing apps for Ubuntu touch. You can find the tutorial here.

Source code:
(1) weatherforecast.qml

import QtQuick 2.0
import QtQuick.LocalStorage 2.0
import Ubuntu.Components 0.1
import Ubuntu.Components.Popups 0.1
import Ubuntu.Components.Pickers 0.1
import Ubuntu.Components.ListItems 0.1
import QtQuick.XmlListModel 2.0
import "components"
import "logic.js" as Logic
import "style.js" as Style

/*!
    \brief MainView with a Label and Button elements.
*/

MainView {
    id: root

    // objectName for functional testing purposes (autopilot-qt5)
    objectName: "mainView"

    // Note! applicationName needs to match the "name" field of the click manifest
    applicationName: "com.ubuntu.developer.karthik.upadya1.weatherforecast"

    /*
     This property enables the application to change orientation
     when the device is rotated. The default is false.
    */
    //automaticOrientation: true

    LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft
    LayoutMirroring.childrenInherit: true

    backgroundColor: UbuntuColors.lightAubergine
    headerColor: UbuntuColors.orange

    property string currentTime
    property string currentDate
    property string cityName: ""
    property string interval: ""
    property string language: "&lang="
    property string queryUrl: "?mode=xml&units=metric&q="
    property string baseUrl: "http://api.openweathermap.org/data/2.5/forecast"
    property string url: ""
    property string mode: ""
    property string textInvalid: ""
    property string appid: "&APPID=976b526db6d1ff6759e5c0f594b68907"
    property string date: ""
    property string dayTemp: ""
    property string nightTemp: ""
    property string humidity: ""
    property string weatherRptStr: ""
    property string clouds: ""
    property string cloudsP: ""
    property string dateFrom: ""
    property string temperature: ""
    property string dateTo: ""
    property int languageIndex: 0
    property int intervalIndex: 0
    property string defintIndex: ""
    property string deflanIndex: ""
    property string deflocIndex: ""
    property int validator: -1
    property bool validation: false
    property var db: null

    width: units.gu(50)
    height: units.gu(75)

    function updateTime () {
        root.currentTime = Logic.getFormattedDateTime(Style.timeFormat);
        root.currentDate = Logic.getFormattedDateTime(Style.dateFormat);
    }

    function validateQuery () {
        if (cityName.text.length > 0 && languageIndex > 0 && intervalIndex > 0) {
            validator = 1;
            validation = true;
            intervalConvert ();
            languageConvert ();
            setQueryUrl ();
        }
        else {
            validator = 0;
            validation = false;
        }
    }

    function intervalConvert () {
        switch (intervalIndex) {
        case 0: return;
        case 1: interval = "";
                mode = "";
                break;
        default: interval = "cnt=" + (intervalIndex - 1);
                 mode = "/daily";
                 break;
        }
    }

    function languageConvert () {
        language = "&lang=";
        switch (languageIndex) {
        case 0: return;
        case 1: language = language + "en";
                break;
        case 2: language = language + "ru";
                break;
        case 3: language = language + "it";
                break;
        case 4: language = language + "sp";
                break;
        case 5: language = language + "ua";
                break;
        case 6: language = language + "de";
                break;
        case 7: language = language + "pt";
                break;
        case 8: language = language + "ro";
                break;
        case 9: language = language + "pl";
                break;
        case 10: language = language + "fi";
                 break;
        case 11: language = language + "nl";
                 break;
        case 12: language = language + "fr";
                 break;
        case 13: language = language + "bg";
                 break;
        case 14: language = language + "se";
                 break;
        case 15: language = language + "zh_tw";
                 break;
        case 16: language = language + "zh_cn";
                 break;
        case 17: language = language + "tr";
                 break;
        }
    }

    function setQueryUrl () {
        url = "";
        if (intervalIndex === 1) {
            url = baseUrl + mode + queryUrl + cityName.text + language;
        }
        else if (intervalIndex > 1) {
            url = baseUrl + mode + queryUrl + cityName.text + "&" + interval + language;
        }
        url = url + appid;
        print(url);
    }

    function getInvalidText () {
        textInvalid = "";
        if (cityName.text.length === 0) {
            textInvalid = textInvalid + "Please select a city.\n";
        }
        if (intervalIndex === 0) {
            textInvalid = textInvalid + "Please specify an interval\n";
        }
        if (languageIndex === 0) {
            textInvalid = textInvalid + "Please select a language.\n"
        }
        return i18n.tr(textInvalid);
    }

    function getWeatherReport () {
        weatherRptStr = "";
        var temp1 = '';
        var temp2 = '';
        if (intervalIndex > 1) {
            weatherRptStr = weatherRptStr + "Date: " + root.date + "\n";
            weatherRptStr = weatherRptStr + "Day Temperature: " + root.dayTemp + " °C\n";
            weatherRptStr = weatherRptStr + "Night Temperature: " + root.nightTemp + " °C\n";
        }
        else if (intervalIndex === 1) {
            temp1 = root.dateFrom.substring(0, 10) + ' ' + root.dateFrom.substring(11, root.dateFrom.length);
            temp2 = root.dateTo.substring(0, 10) + ' ' + root.dateTo.substring(11, root.dateTo.length);
            weatherRptStr = weatherRptStr + "From: " + temp1 + "\nTo: " + temp2 + "\n";
            weatherRptStr = weatherRptStr + "Temperature: " + root.temperature + " °C\n";
        }
        if (intervalIndex >= 1) {
            weatherRptStr = weatherRptStr + "Humidity: " + root.humidity + "%\n";
            weatherRptStr = weatherRptStr + "Clouds: " + root.clouds + "  " + root.cloudsP + "% cloudy";
        }
        return i18n.tr(weatherRptStr);
    }

    function openDB() {
        if(db !== null) return;

        // db = LocalStorage.openDatabaseSync(identifier, version, description, estimated_size, callback(db))
        db = LocalStorage.openDatabaseSync("example-app", "0.1", "Simple example app", 100000);

        try {
            db.transaction(function(tx){
                tx.executeSql('CREATE TABLE IF NOT EXISTS settings(key TEXT UNIQUE, value TEXT)');
                var table  = tx.executeSql("SELECT * FROM settings");
                // Seed the table with default values
                if (table.rows.length == 0) {
                    tx.executeSql('INSERT INTO settings VALUES(?, ?)', ["LOCATION", ""]);
                    tx.executeSql('INSERT INTO settings VALUES(?, ?)', ["INTERVAL", "0"]);
                    tx.executeSql('INSERT INTO settings VALUES(?, ?)', ["LANGUAGE", ""]);
                    tx.executeSql('INSERT INTO settings VALUES(?, ?)', ["APPNAME", "Weather Forecast"]);
                    console.log('Settings table added');
                };
            });
        } catch (err) {
            console.log("Error creating table in database: " + err);
        };
    }

    function saveSetting(key, value) {
        openDB();
        db.transaction( function(tx){
            tx.executeSql('INSERT OR REPLACE INTO settings VALUES(?, ?)', [key, value]);
        });
    }

    function getSetting(key) {
        openDB();
        var res = "";
        db.transaction(function(tx) {
            var rs = tx.executeSql('SELECT value FROM settings WHERE key=?;', [key]);
            res = rs.rows.item(0).value;
        });
        return res;
    }

    function checkDefaults () {
        var appName = getSetting("APPNAME");
        deflocIndex = getSetting("LOCATION");
        defintIndex = getSetting("INTERVAL");
        deflanIndex = getSetting("LANGUAGE");
        if (deflocIndex.length > 0 && defintIndex > 0 && deflanIndex > 0) {
            validator = 1;
            intervalIndex = defintIndex;
            languageIndex = deflanIndex;
            validation = true;
            intervalConvert();
            languageConvert();
            if (intervalIndex === 1) {
                url = baseUrl + mode + queryUrl + deflocIndex + language;
            }
            else if (intervalIndex > 1) {
                url = baseUrl + mode + queryUrl + deflocIndex + "&" + interval + language;
            }
            url = url + appid;
            print(url);
        }
        return appName;
    }

    function trimSomeText (text1, text2) {
        var finaltext = '';
        finaltext = text1.substr(0, 10) + ' ' + text1.substr(11, 16) + ' to ' + text2.substr(11, 16)
        return finaltext;
    }

    Page {
        id: mainPage
        title: i18n.tr(root.checkDefaults())

        Timer {
            id: updateTimer
            running: Qt.application.active && visible == true
            repeat: true
            triggeredOnStart: true
            onTriggered: {
                root.updateTime()
                interval: 1000
            }
        }

        Column {
            id: pageLayout
            spacing: units.gu(2)
            clip: true

            anchors {
                 fill: parent
                 margins: root.margins
                 leftMargin: units.gu(1)
                 topMargin: units.gu(1)
                 rightMargin: units.gu(1)
            }

            Row {
                id: line1
                spacing: units.gu(2)

                Label {
                    id: clockText
                    fontSize: "large"
                    color: "lightgreen" //UbuntuColors.orange
                    text: qsTr(currentDate + "\t" + currentTime)
                }
            }

            Row {
                id: line2
                spacing: units.gu(2)

                OptionSelector {
                    id: intervalTime
                    width: root.width * 0.4
                    selectedIndex: root.intervalIndex
                    highlightWhenPressed: true
                    model: [i18n.tr("Interval"),
                            i18n.tr("Every 3 hour"),
                            i18n.tr("Today"),
                            i18n.tr("Tomorrow"),
                            i18n.tr("Two days"),
                            i18n.tr("Three days"),
                            i18n.tr("Four days"),
                            i18n.tr("Five days"),
                            i18n.tr("Six days"),
                            i18n.tr("One week"),
                            i18n.tr("Eight days"),
                            i18n.tr("Nine days"),
                            i18n.tr("Ten days"),
                            i18n.tr("Eleven days"),
                            i18n.tr("Twelve days"),
                            i18n.tr("Thirteen days"),
                            i18n.tr("Two weeks"),]
                    containerHeight: itemHeight * 3
                    onSelectedIndexChanged: {
                        intervalIndex = selectedIndex
                    }
                }

                OptionSelector {
                    id: languageSelect
                    width: root.width * 0.5
                    selectedIndex: root.languageIndex
                    model: [i18n.tr("Language"),
                            i18n.tr("English"),
                            i18n.tr("Russian"),
                            i18n.tr("Italian"),
                            i18n.tr("Spanish"),
                            i18n.tr("Ukranian"),
                            i18n.tr("German"),
                            i18n.tr("Portuguese"),
                            i18n.tr("Romanian"),
                            i18n.tr("Polish"),
                            i18n.tr("Finnish"),
                            i18n.tr("Dutch"),
                            i18n.tr("French"),
                            i18n.tr("Bulgarian"),
                            i18n.tr("Swedish"),
                            i18n.tr("Chinese Traditional"),
                            i18n.tr("Chinese Simplified"),
                            i18n.tr("Turkish")]
                    containerHeight: itemHeight * 3
                    onSelectedIndexChanged: {
                        languageIndex = selectedIndex
                    }
                }

                Component {
                    id: dialog
                    Dialog {
                        id: dialogue

                        title: i18n.tr("Invalid input!")
                        text: root.getInvalidText()

                        Button {
                            text: i18n.tr("OK")
                            onClicked: PopupUtils.close(dialogue)
                        }
                    }
                }
            }

            Row {
                id: line3
                spacing: units.gu(2)

                TextField {
                    id: cityName
                    color: UbuntuColors.orange
                    placeholderText: i18n.tr("Enter city name")
                    text: {
                        if (deflocIndex.length > 0) {
                            cityName.text = deflocIndex;
                        }
                    }
                }

                Button {
                    id: serachButton
                    text: i18n.tr("Search")
                    onClicked: {
                        root.validateQuery()
                        onValidationChanged: {
                            (!root.validation) ? PopupUtils.open (dialog, null) : null
                        }
                    }
                }
            }

            Row {
                id: line4
                spacing: units.gu(2)

                Label {
                    id: resultText
                    fontSize: "large"
                    color: UbuntuColors.orange
                    text: qsTr("Result")
                }

                ActivityIndicator {
                    id: activity
                    running: (root.validator === 1) && (weatherData.status === XmlListModel.Loading)
                    Text {
                        id: activityText
                        anchors.centerIn: activity
                        color: UbuntuColors.orange
                        text: (activity.running) ? qsTr("\t\tLoading. Please wait!") : ""
                    }
                }

                Text {
                    color: UbuntuColors.orange
                    text: (weatherData.status === XmlListModel.Error) ? qsTr("Error loading data.") : ""
                }
            }

            Row {
                id: line5
                spacing: units.gu(1)

                OptionSelector {
                    id: selectedOption
                    expanded: true
                    width: root.width
                    selectedIndex: -1
                    model: weatherData
                    delegate: weatherDataDelegate
                    containerHeight: itemHeight * 5
                    onSelectedIndexChanged: {
                        if (selectedOption.selectedIndex >= 0) {
                            if (root.intervalIndex > 1) {
                                root.date = weatherData.get(selectedIndex).Date;
                                root.dayTemp = weatherData.get(selectedIndex).DayTemp;
                                root.nightTemp = weatherData.get(selectedIndex).NightTemp;
                            }
                            else if (root.intervalIndex === 1) {
                                root.dateFrom = weatherData.get(selectedIndex).DateF;
                                root.dateTo = weatherData.get(selectedIndex).DateT;
                                root.temperature = weatherData.get(selectedIndex).Temperature;
                            }
                            root.humidity = weatherData.get(selectedIndex).Humidity;
                            root.clouds = weatherData.get(selectedIndex).Clouds;
                            root.cloudsP = weatherData.get(selectedIndex).CloudsP;
                            PopupUtils.open(dialog2, null)
                        }
                        selectedOption.selectedIndex = -1
                    }
                }

                Component {
                    id: dialog2
                    Dialog {
                        id: dialogue2

                        title: i18n.tr("Weather of " + cityName.text)
                        text: root.getWeatherReport()

                        Button {
                            text: i18n.tr("OK")
                            onClicked: PopupUtils.close(dialogue2)
                        }
                    }
                }
            }

            XmlListModel {
                id: weatherData
                source: root.url
                query: "/weatherdata/forecast/time"

                XmlRole { name: "Date"; query: "@day/string()"  }
                XmlRole { name: "DateF"; query: "@from/string()" }
                XmlRole { name: "DateT"; query: "@to/string()" }
                XmlRole { name: "DayTemp"; query: "temperature/@day/string()" }
                XmlRole { name: "NightTemp"; query: "temperature/@night/string()" }
                XmlRole { name: "Temperature"; query: "temperature/@value/string()" }
                XmlRole { name: "Humidity"; query: "humidity/@value/string()" }
                XmlRole { name: "Clouds"; query: "clouds/@value/string()" }
                XmlRole { name: "CloudsP"; query: "clouds/@all/string()" }

                onStatusChanged: {
                    Text: {
                        text: (get(0) === undefined || status == XmlListModel.Null) ? qsTr("Error loading data.") : ""
                    }
                }
            }

            Component {
                id: weatherDataDelegate
                OptionSelectorDelegate {
                    Label {
                        width: root.width
                        fontSize: "large"
                        color: UbuntuColors.orange
                        text: {
                            if (root.intervalIndex > 1) {
                                qsTr("\n   " + model.Date);
                            }
                            else if (root.intervalIndex === 1) {
                                qsTr("\n  " + root.trimSomeText(model.DateF, model.DateT));
                            }
                        }
                    }
                }
            }
        }

        tools: ToolbarItems {
            ToolbarButton {
                id: actionsButton
                text: "Options"
                iconSource: "option.png"
                onTriggered: PopupUtils.open(actionSelectionPopover, actionsButton)
                visible: true
            }
            locked: false
            opened: true
        }

        Item {
            Component {
                id: actionSelectionPopover

                ActionSelectionPopover {
                    actions: ActionList {
                        Action {
                            text: i18n.tr("Settings")
                            onTriggered: PopupUtils.open(composerSheet, null)
                        }
                        Action {
                            text: i18n.tr("About me")
                            onTriggered: PopupUtils.open(defaultSheet, null)
                        }
                        Action {
                            text: i18n.tr("Quit")
                            onTriggered: Qt.quit()
                        }
                    }
                }
            }
        }

        Component {
            id: defaultSheet
            DefaultSheet {
                id: sheet
                title: i18n.tr("About me")
                Label {
                    anchors.fill: parent
                    color: UbuntuColors.orange
                    fontSize: "small"
                    wrapMode: Text.WordWrap
                    text: "Developed by: <b>KARTHIK</b><br/>" +
                          "Tested by: <b>KARTHIK</b><br/>" +
                          "Email: <b>karthik.upadya1@gmail.com</b><br/>" +
                          "Country: <b>INDIA</b><br/>" +
                          "This is <b>open source</b> Weather forecasting application designed for Ubuntu and Ubuntu Touch.<br/>" +
                          "Please mail me to get source code.<br/>" +
                          "Please give credit to me if you use this application as part of your project.<br/>" +
                          "<b>Check out my another app \"Daily Karma\" a beautiful note taking app.</b><br/>"+
                          "If you have android device you can download my apps from SlideMe.<br/>"+
                          "1. Bumpy Adventures I<br/>2. Auto Call Blocker<br/>3. Snake<br/>4. Millenium alien<br/>"+
                          "My developer name in the site is \"developerKASS013\" Thanks :)"
                }
            }
        }

        Component {
            id: composerSheet
            ComposerSheet {
                id: sheet
                title: i18n.tr("Settings")
                Column {
                    spacing: units.gu(2)
                    width: parent.width
                    clip: true
                    anchors {
                        margins: root.margins
                         leftMargin: units.gu(1)
                         topMargin: units.gu(1)
                         rightMargin: units.gu(1)
                    }
                    Row {
                        width: parent.width
                        TextField {
                            id: appName
                            color: UbuntuColors.orange
                            text: root.getSetting("APPNAME")
                            width: parent.width
                        }
                    }
                    Row {
                        width: parent.width
                        TextField {
                            id: defLoc
                            color: UbuntuColors.orange
                            placeholderText: i18n.tr("Specify your default location")
                            text: {
                                var loc = root.getSetting("LOCATION");
                                if (loc.length > 0) {
                                    defLoc.text = i18n.tr(loc);
                                }
                            }
                            width: parent.width
                        }
                    }
                    Row {
                        width: parent.width
                        spacing: units.gu(2)
                        OptionSelector {
                            id: defintVal
                            width: parent.width * 0.4
                            selectedIndex: root.getSetting("INTERVAL")
                            highlightWhenPressed: true
                            model: [i18n.tr("Interval"),
                                    i18n.tr("Every 3 hour"),
                                    i18n.tr("Today"),
                                    i18n.tr("Tomorrow"),
                                    i18n.tr("Two days"),
                                    i18n.tr("Three days"),
                                    i18n.tr("Four days"),
                                    i18n.tr("Five days"),
                                    i18n.tr("Six days"),
                                    i18n.tr("One week"),
                                    i18n.tr("Eight days"),
                                    i18n.tr("Nine days"),
                                    i18n.tr("Ten days"),
                                    i18n.tr("Eleven days"),
                                    i18n.tr("Twelve days"),
                                    i18n.tr("Thirteen days"),
                                    i18n.tr("Two weeks"),]
                            containerHeight: itemHeight * 3
                        }
                        OptionSelector {
                            id: defLan
                            width: parent.width * 0.5
                            selectedIndex: root.getSetting("LANGUAGE")
                            model: [i18n.tr("Language"),
                                    i18n.tr("English"),
                                    i18n.tr("Russian"),
                                    i18n.tr("Italian"),
                                    i18n.tr("Spanish"),
                                    i18n.tr("Ukranian"),
                                    i18n.tr("German"),
                                    i18n.tr("Portuguese"),
                                    i18n.tr("Romanian"),
                                    i18n.tr("Polish"),
                                    i18n.tr("Finnish"),
                                    i18n.tr("Dutch"),
                                    i18n.tr("French"),
                                    i18n.tr("Bulgarian"),
                                    i18n.tr("Swedish"),
                                    i18n.tr("Chinese Traditional"),
                                    i18n.tr("Chinese Simplified"),
                                    i18n.tr("Turkish")]
                            containerHeight: itemHeight * 3
                        }
                    }
                    Row {
                        Label {
                            wrapMode: Text.WordWrap
                            text: "More option, apps and games are under<br/>" +
                                  " development, stay tuned.<br/>" +
                                  "Version: 0.1.6"
                        }
                    }
                }

                onCancelClicked: PopupUtils.close(sheet)
                onConfirmClicked: {
                    root.saveSetting("APPNAME", appName.text);
                    root.saveSetting("LOCATION", defLoc.text);
                    root.saveSetting("INTERVAL", defintVal.selectedIndex);
                    root.saveSetting("LANGUAGE", defLan.selectedIndex);
                    PopupUtils.close(sheet)
                }
            }
        }
    }
}

(2) style.js

var timeFormat = "hh : mm : ss"
var dateFormat = "dd / MM / yyyy"
var textColor = "red"

(3) logic.js

function getFormattedDateTime (format) {
    var date = new Date
    return Qt.formatDateTime(date, format)
}

Screenshots: