C

Qt Quick Ultralite Watch Demo

// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial

import QtQuick 2.15
import QtQuickUltralite.Extras 2.0
import Watch 1.0

Item {
    id: root
    height: Theme.appHeight
    width: Theme.appWidth

    property bool onScreen: false
    property bool offScreen: false

    readonly property real startOp: 0.0
    readonly property real startForecastMargin: 40
    readonly property real startDescriptionMargin: 10
    readonly property real startTopMargin: height / 2 - currentWeather.height / 2
    readonly property int introDuration: 150
    readonly property int introDurationLong: 250

    SequentialAnimation {
        id: intro

        ParallelAnimation {
            NumberAnimation { target: currentWeather; property: "margin"; to: 30; easing.type: Easing.InOutCubic; duration: introDurationLong }
            NumberAnimation { target: weatherCity; property: "opacity"; to: 1.0; easing.type: Easing.OutCubic; duration: introDurationLong }
        }
        NumberAnimation { target: bottomMask; property: "opacity"; to: 1.0; easing.type: Easing.OutCubic; duration: introDurationLong }
        ParallelAnimation {
            NumberAnimation { target: weatherForecast; property: "tueOpacity"; to: 1.0; easing.type: Easing.OutCubic; duration: introDuration }
            NumberAnimation { target: weatherForecast; property: "tueMargin"; to: 20; easing.type: Easing.OutCubic; duration: introDuration }
        }
        ParallelAnimation {
            NumberAnimation { target: weatherForecast; property: "wedOpacity"; to: 1.0; easing.type: Easing.OutCubic; duration: introDuration }
            NumberAnimation { target: weatherForecast; property: "wedMargin"; to: 20; easing.type: Easing.OutCubic; duration: introDuration }
        }
        ParallelAnimation {
            NumberAnimation { target: weatherForecast; property: "thuOpacity"; to: 1.0; easing.type: Easing.OutCubic; duration: introDuration }
            NumberAnimation { target: weatherForecast; property: "thuMargin"; to: 20; easing.type: Easing.OutCubic; duration: introDuration }
        }

        NumberAnimation { target: weatherForecast; property: "sepOpacity"; to: 1.0; easing.type: Easing.OutCubic; duration: introDuration }
        ParallelAnimation {
            NumberAnimation { target: weatherDescription; property: "opacity"; to: 1.0; easing.type: Easing.OutCubic; duration: introDurationLong }
            NumberAnimation { target: weatherDescription; property: "bottomMar"; to: 30; easing.type: Easing.OutCubic; duration: introDurationLong }
        }
    }

    /*
    * Current weather
    */
    Column {
        id: currentWeather
        anchors.right: parent.right
        anchors.rightMargin: parent.width / 2 - width
        anchors.top: parent.top
        anchors.topMargin: margin

        property int margin: startTopMargin

        Text {
            text: "18°"
            font.pixelSize: 61
            font.family: Theme.fontFamily
            font.weight: Font.Medium
            color: Theme.whiteColor
        }

        Text {
            id: weatherCity
            opacity: 0.0
            text: "BERLIN"
            font.pixelSize: 20
            font.family: Theme.fontFamily
            color: Theme.whiteColor
        }
    }

    /*
    * Weather big icon
    */
    Image {
        id: weatherIcon
        anchors.verticalCenter: currentWeather.verticalCenter
        anchors.right: currentWeather.left
        anchors.rightMargin: 10
        source: "images/weather/big-sun.png"
    }

    /*
    * Weather description
    */
    Row {
        id: weatherDescription
        anchors.bottom: bottomMask.top
        anchors.bottomMargin: bottomMar
        anchors.horizontalCenter: parent.horizontalCenter
        spacing: 15
        opacity: startOp

        property real bottomMar: startDescriptionMargin

        Image {
            source: "images/weather/ion-ios-rainy-outline.png"
        }

        StaticText {
            text: "Rain in 4 hours (17:00)"
            font.pixelSize: 25
            font.family: Theme.fontFamily
            color: Theme.whiteColor
        }
    }

    Image {
        id: bottomMask
        anchors.bottom: parent.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        source: "images/weather/w-bottom-mask.png"
        opacity: startOp
    }

    /*
    * Bottom weather forecast
    */
    Row {
        id: weatherForecast
        anchors.top: bottomMask.top
        anchors.horizontalCenter: parent.horizontalCenter

        property real tueOpacity: startOp
        property real wedOpacity: startOp
        property real thuOpacity: startOp
        property real sepOpacity: startOp

        property real tueMargin: startForecastMargin
        property real wedMargin: startForecastMargin
        property real thuMargin: startForecastMargin

        Repeater {
            model: ListModel {
                ListElement { day: "TUE"; weatherImg: "images/weather/ion-ios-partlysunny-outline.png"; temperature: "21°C" }
                ListElement { day: "WED"; weatherImg: "images/weather/ion-ios-rainy-outline.png"; temperature: "19°C" }
                ListElement { day: "THU"; weatherImg: "images/weather/ion-ios-sunny-outline.png"; temperature: "23°C" }
            }

            delegate: Item {
                width: 90
                opacity: getOpacity(index)

                Text {
                    id: dayLabel
                    anchors.left: temperatureLabel.left
                    anchors.top: parent.top
                    anchors.topMargin: getMargin(index)

                    text: model.day
                    font.pixelSize: 14
                    font.family: Theme.fontFamily
                    color: Theme.whiteColor
                }

                Text {
                    id: temperatureLabel
                    anchors.top: dayLabel.bottom
                    anchors.horizontalCenter: parent.horizontalCenter

                    text: model.temperature
                    font.pixelSize: 30
                    font.family: Theme.fontFamily
                    color: Theme.whiteColor
                }

                Image {
                    anchors.topMargin: 30 - height / 2
                    anchors.top: temperatureLabel.bottom
                    anchors.horizontalCenter: temperatureLabel.horizontalCenter
                    source: model.weatherImg
                }

                Image {
                    anchors.top: parent.top
                    anchors.right: parent.right
                    visible: index < 2
                    source: "images/weather/w-vertical.png"
                    opacity: weatherForecast.sepOpacity
                }
            }
        }
    }

    onOnScreenChanged: {
        if (onScreen) {
            intro.running = true
        }
    }

    onOffScreenChanged: {
        if (offScreen) {
            resetIntro()
        }
    }

    function resetIntro() {
        intro.running = false
        currentWeather.margin = startTopMargin
        weatherCity.opacity = startOp
        bottomMask.opacity = startOp
        weatherForecast.tueOpacity = startOp
        weatherForecast.wedOpacity = startOp
        weatherForecast.thuOpacity = startOp
        weatherForecast.sepOpacity = startOp
        weatherDescription.opacity = startOp
        weatherForecast.tueMargin = startForecastMargin
        weatherForecast.wedMargin = startForecastMargin
        weatherForecast.thuMargin = startForecastMargin
        weatherDescription.bottomMar = startDescriptionMargin
    }

    function getOpacity(index : int) : real {
        switch(index) {
            case 0:
                return weatherForecast.tueOpacity
            case 1:
                return weatherForecast.wedOpacity
            case 2:
                return weatherForecast.thuOpacity
        }
    }

    function getMargin(index : int) : real {
        switch(index) {
            case 0:
                return weatherForecast.tueMargin
            case 1:
                return weatherForecast.wedMargin
            case 2:
                return weatherForecast.thuMargin
        }
    }
}