diff --git a/__init__.py b/__init__.py
index fc0f286c..e3cdcc92 100644
--- a/__init__.py
+++ b/__init__.py
@@ -29,6 +29,7 @@
from collections import defaultdict
from datetime import datetime, timedelta
from multi_key_dict import multi_key_dict
+from time import sleep
from typing import List, Optional
from adapt.intent import IntentBuilder
@@ -59,7 +60,16 @@
# Later weather: only the word "later" in the vocab file works all others
# invoke datetime skill
+MARK_II = "mycroft_mark_2"
MINUTES = 60 # Minutes to seconds multiplier
+CLEAR = 0
+PARTLY_CLOUDY = 1
+CLOUDY = 2
+LIGHT_RAIN = 3
+RAIN = 4
+THUNDERSTORM = 5
+SNOW = 6
+WINDY = 7
class WeatherSkill(MycroftSkill):
@@ -68,19 +78,19 @@ def __init__(self):
self.weather_api = OWMApi()
self.weather_api_new = OpenWeatherMapApi()
self.weather_config = WeatherConfig(self.config_core, self.settings)
-
+ self.platform = self.config_core['enclosure']['platform']
# Build a dictionary to translate OWM weather-conditions
# codes into the Mycroft weather icon codes
# (see https://openweathermap.org/weather-conditions)
- self.CODES = multi_key_dict()
- self.CODES['01d', '01n'] = 0 # clear
- self.CODES['02d', '02n', '03d', '03n'] = 1 # partly cloudy
- self.CODES['04d', '04n'] = 2 # cloudy
- self.CODES['09d', '09n'] = 3 # light rain
- self.CODES['10d', '10n'] = 4 # raining
- self.CODES['11d', '11n'] = 5 # stormy
- self.CODES['13d', '13n'] = 6 # snowing
- self.CODES['50d', '50n'] = 7 # windy/misty
+ self.image_codes = multi_key_dict()
+ self.image_codes['01d', '01n'] = CLEAR
+ self.image_codes['02d', '02n', '03d', '03n'] = PARTLY_CLOUDY
+ self.image_codes['04d', '04n'] = CLOUDY
+ self.image_codes['09d', '09n'] = LIGHT_RAIN
+ self.image_codes['10d', '10n'] = RAIN
+ self.image_codes['11d', '11n'] = THUNDERSTORM
+ self.image_codes['13d', '13n'] = SNOW
+ self.image_codes['50d', '50n'] = WINDY
# Use Mycroft proxy if no private key provided
self.settings["api_key"] = None
@@ -378,30 +388,75 @@ def _report_current_weather(self, message):
intent_data = self._get_intent_data(message)
weather = self._get_weather(intent_data)
if weather is not None:
+ self._display_current_conditions(weather)
dialog = WeatherDialog(
weather.current, self.weather_config, intent_data
)
dialog.build_current_weather_dialog()
- self._display_current_weather(weather)
self._speak_weather(dialog)
+ if self.gui.connected and self.platform != MARK_II:
+ self._display_more_current_conditions(weather)
dialog.build_high_low_temperature_dialog()
self._speak_weather(dialog)
-
- def _display_current_weather(self, report):
- image_code = self.CODES[report.current.condition.icon]
+ if self.gui.connected:
+ if self.platform == MARK_II:
+ self._display_more_current_conditions(weather)
+ sleep(5)
+ self._display_hourly_forecast(weather)
+ else:
+ four_day_forecast = weather.daily[1:5]
+ self._display_forecast(four_day_forecast)
+
+ def _display_current_conditions(self, weather):
+ image_code = self.image_codes[weather.current.condition.icon]
if self.gui.connected:
- self.gui["current"] = report.current.temperature
- self.gui["min"] = report.current.low_temperature
- self.gui["max"] = report.current.high_temperature
- self.gui["condition"] = report.current.condition.description
- self.gui["icon"] = report.current.condition.icon
- self.gui["weathercode"] = image_code
- self.gui.show_pages(["weather.qml", "highlow.qml"])
+ page_name = "current_1_generic.qml"
+ self.gui.clear()
+ self.gui["currentTemperature"] = weather.current.temperature
+ self.gui["weatherCode"] = image_code
+ if self.platform == MARK_II:
+ self.gui["highTemperature"] = weather.current.high_temperature
+ self.gui["lowTemperature"] = weather.current.low_temperature
+ page_name = page_name.replace("generic", "mark_ii")
+ self.gui.show_page(page_name)
else:
self.enclosure.deactivate_mouth_events()
self.enclosure.weather_display(
- image_code, report.current.temperature
+ image_code, weather.current.temperature
+ )
+
+ def _display_more_current_conditions(self, weather):
+ page_name = "current_2_generic.qml"
+ self.gui.clear()
+ if self.platform == MARK_II:
+ self.gui["windSpeed"] = weather.current.wind_speed
+ self.gui["humidity"] = weather.current.humidity
+ page_name = page_name.replace("generic", "mark_ii")
+ else:
+ self.gui["highTemperature"] = weather.current.high_temperature
+ self.gui["lowTemperature"] = weather.current.low_temperature
+ self.gui.show_page(page_name)
+
+ def _display_hourly_forecast(self, weather):
+ hourly_forecast = defaultdict(list)
+ for hour_count, hourly in enumerate(weather.hourly):
+ if not hour_count:
+ continue
+ if hour_count > 4:
+ break
+ # TODO: make the timeframe aware of language/location settings
+ hourly_forecast['times'].append(hourly.date_time.strftime('%H:00'))
+ hourly_forecast['temperatures'].append(hourly.temperature)
+ hourly_forecast['weather_codes'].append(
+ self.image_codes.get(hourly.condition.icon)
)
+ hourly_forecast['precipitation'].append(hourly.chance_of_precipitation)
+ self.gui.clear()
+ self.gui['times'] = hourly_forecast['times']
+ self.gui['temperatures'] = hourly_forecast['temperatures']
+ self.gui['weatherCodes'] = hourly_forecast['weather_codes']
+ self.gui['chancesOfPrecipitation'] = hourly_forecast['precipitation']
+ self.gui.show_page('hourly_mark_ii.qml')
def _report_one_hour_weather(self, message):
intent_data = self._get_intent_data(message)
@@ -418,7 +473,7 @@ def _report_multi_day_forecast(self, message, days):
intent_data = WeatherIntent(message, self.lang)
weather = self._get_weather(intent_data)
if weather is not None:
- forecast = weather.daily[:days]
+ forecast = weather.daily[1:days + 1]
dialogs = self._build_forecast_dialogs(forecast, intent_data)
self._display_forecast(forecast)
for dialog in dialogs:
@@ -457,19 +512,60 @@ def _build_forecast_dialogs(self, forecast, intent_data):
def _display_forecast(self, forecast: List):
"""Builds forecast for the upcoming days for the Mark-2 display."""
+ if self.platform == MARK_II:
+ self._display_forecast_mark_ii(forecast)
+ else:
+ self._display_forecast_generic(forecast)
+
+ def _display_forecast_mark_ii(self, forecast):
+ page_one_name = "daily_mark_ii.qml"
+ display_data = defaultdict(list)
+ for day in forecast:
+ display_data['weatherCodes'].append(
+ self.image_codes[day.condition.icon]
+ )
+ display_data['days'].append(day.date_time.strftime("%a"))
+ display_data['highTemperatures'].append(day.temperature.high)
+ display_data['lowTemperatures'].append(day.temperature.low)
+ self.gui.clear()
+ self.gui["numberOfDays"] = min([4, len(forecast)])
+ self.gui['weatherCodes'] = display_data['weatherCodes'][:4]
+ self.gui['days'] = display_data["days"][:4]
+ self.gui["lowTemperatures"] = display_data["lowTemperatures"][:4]
+ self.gui["highTemperatures"] = display_data["highTemperatures"][:4]
+ self.gui.show_page(page_one_name)
+ if len(forecast) > 4:
+ sleep(20)
+ self.gui.clear()
+ self.gui["numberOfDays"] = min([4, len(forecast) - 4])
+ self.gui['weatherCodes'] = display_data['weatherCodes'][4:]
+ self.gui['days'] = display_data["days"][4:]
+ self.gui["lowTemperatures"] = display_data["lowTemperatures"][4:]
+ self.gui["highTemperatures"] = display_data["highTemperatures"][4:]
+ self.gui.clear()
+ self.gui.show_page(page_one_name)
+
+ def _display_forecast_generic(self, forecast):
+ page_one_name = "daily_1_generic.qml"
+ page_two_name = page_one_name.replace("1", "2")
display_data = []
- for forecast_day in forecast:
+ for day_number, day in enumerate(forecast):
+ if day_number == 4:
+ break
display_data.append(
dict(
- weathercode=self.CODES[forecast_day.condition.icon],
- max=forecast_day.temperature.high,
- min=forecast_day.temperature.low,
- date=forecast_day.date_time.strftime('%a')
+ weatherCode=self.image_codes[day.condition.icon],
+ highTemperature=day.temperature.high,
+ lowTemperature=day.temperature.low,
+ date=day.date_time.strftime('%a')
)
)
self.gui['forecast'] = dict(
first=display_data[:2], second=display_data[2:]
)
+ self.gui.show_page(page_one_name)
+ sleep(5)
+ self.gui.show_page(page_two_name)
def _report_temperature(self, message, temperature_type=None):
intent_data = self._get_intent_data(message)
@@ -527,7 +623,6 @@ def _get_intent_data(self, message):
except ValueError:
self.speak_dialog("cant.get.forecast")
else:
- print(self.voc_match(intent_data.utterance, "RelativeDay"))
if self.voc_match(intent_data.utterance, "RelativeTime"):
intent_data.timeframe = "hourly"
elif self.voc_match(intent_data.utterance, "Later"):
diff --git a/ui/ForecastDelegate.qml b/ui/DailyGenericDelegate.qml
similarity index 92%
rename from ui/ForecastDelegate.qml
rename to ui/DailyGenericDelegate.qml
index a4db1cec..9bc29864 100644
--- a/ui/ForecastDelegate.qml
+++ b/ui/DailyGenericDelegate.qml
@@ -6,7 +6,7 @@ import org.kde.kirigami 2.4 as Kirigami
import Mycroft 1.0 as Mycroft
import org.kde.lottie 1.0
-WeatherDelegate {
+WeatherGenericDelegate {
id: root
property alias model: forecastRepeater.model
@@ -25,7 +25,7 @@ WeatherDelegate {
Layout.preferredHeight: proportionalGridUnit * 20
Layout.preferredWidth: Layout.preferredHeight
- source: Qt.resolvedUrl(getWeatherImagery(modelData.weathercode))
+ source: Qt.resolvedUrl(getWeatherImagery(modelData.weatherCode))
loops: Animation.Infinite
fillMode: Image.PreserveAspectFit
running: true
@@ -43,7 +43,7 @@ WeatherDelegate {
Layout.fillWidth: true
Layout.preferredHeight: proportionalGridUnit * 20
rightPadding: -font.pixelSize * 0.1
- text: modelData.max + "°"
+ text: modelData.highTemperature + "°"
}
Mycroft.AutoFitLabel {
@@ -51,7 +51,7 @@ WeatherDelegate {
Layout.fillWidth: true
Layout.preferredHeight: proportionalGridUnit * 20
rightPadding: -font.pixelSize * 0.1
- text: modelData.min + "°"
+ text: modelData.lowTemperature + "°"
}
}
}
diff --git a/ui/WeatherDelegate.qml b/ui/WeatherGenericDelegate.qml
similarity index 100%
rename from ui/WeatherDelegate.qml
rename to ui/WeatherGenericDelegate.qml
diff --git a/ui/WeatherMarkIIDelegate.qml b/ui/WeatherMarkIIDelegate.qml
new file mode 100644
index 00000000..236309cb
--- /dev/null
+++ b/ui/WeatherMarkIIDelegate.qml
@@ -0,0 +1,44 @@
+import QtQuick.Layouts 1.4
+import QtQuick 2.4
+import QtQuick.Controls 2.0
+import org.kde.kirigami 2.4 as Kirigami
+
+import Mycroft 1.0 as Mycroft
+
+Mycroft.Delegate {
+ id: root
+ bottomPadding: 32
+ leftPadding: 32
+ rightPadding: 32
+ topPadding: 32
+
+ function getWeatherImagery(weathercode) {
+ switch(weathercode) {
+ case 0:
+ return "images/sunny.svg";
+ break
+ case 1:
+ return "images/partly_cloudy.svg";
+ break
+ case 2:
+ return "images/cloudy.svg";
+ break
+ case 3:
+ return "images/rain.svg";
+ break
+ case 4:
+ return "images/rain.svg";
+ break
+ case 5:
+ return "images/storm.svg";
+ break
+ case 6:
+ return "images/snow.svg";
+ break
+ case 7:
+ return "images/cloudy.svg";
+ break
+ }
+ }
+
+}
diff --git a/ui/weather.qml b/ui/current_1_generic.qml
similarity index 86%
rename from ui/weather.qml
rename to ui/current_1_generic.qml
index 0bd579ab..bbe0bc69 100644
--- a/ui/weather.qml
+++ b/ui/current_1_generic.qml
@@ -6,7 +6,7 @@ import org.kde.kirigami 2.4 as Kirigami
import Mycroft 1.0 as Mycroft
import org.kde.lottie 1.0
-WeatherDelegate {
+WeatherGenericDelegate {
id: root
spacing: proportionalGridUnit * 5
@@ -17,7 +17,7 @@ WeatherDelegate {
Layout.preferredWidth: Math.min(root.contentWidth, proportionalGridUnit * 50)
Layout.preferredHeight: Layout.preferredWidth
- source: Qt.resolvedUrl(getWeatherImagery(sessionData.weathercode))
+ source: Qt.resolvedUrl(getWeatherImagery(sessionData.weatherCode))
loops: Animation.Infinite
fillMode: Image.PreserveAspectFit
@@ -25,7 +25,7 @@ WeatherDelegate {
// Debug:
onSourceChanged: {
- console.log(getWeatherImagery(sessionData.weathercode));
+ console.log(getWeatherImagery(sessionData.weatherCode));
}
onStatusChanged: {
console.log(weatherAnimation.status, errorString);
@@ -38,6 +38,6 @@ WeatherDelegate {
Layout.fillWidth: true
Layout.preferredHeight: proportionalGridUnit * 40
rightPadding: -font.pixelSize * 0.1
- text: sessionData.current + "°"
+ text: sessionData.currentTemperature + "°"
}
}
diff --git a/ui/current_1_mark_ii.qml b/ui/current_1_mark_ii.qml
new file mode 100644
index 00000000..497b50e1
--- /dev/null
+++ b/ui/current_1_mark_ii.qml
@@ -0,0 +1,150 @@
+/*
+One of many screns that show when the user asks for the current weather.
+
+Shows an animation with current conditions, the current temperature, and
+the high/low temperature for today.
+
+This code is specific to the Mark II device. It uses a grid of 32x32 pixel
+squares for alignment of items.
+*/
+import QtQuick.Layouts 1.4
+import QtQuick 2.4
+import QtQuick.Controls 2.0
+import org.kde.kirigami 2.4 as Kirigami
+
+import Mycroft 1.0 as Mycroft
+import org.kde.lottie 1.0
+
+WeatherMarkIIDelegate {
+ id: root
+
+ Item {
+ // Bounding box for the content of the screen.
+ id: card
+ height: parent.height
+ width: parent.width
+
+ Item {
+ // City/state if in same country as device. City/country if in a different country
+ id: weatherLocation
+ height: 64
+ width: parent.width
+
+ Label {
+ id: weatherLocationText
+ anchors.baseline: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ font.family: "Noto Sans Display"
+ font.pixelSize: 48
+ text: "Kansas City, Missouri"
+ }
+ }
+
+ GridLayout {
+ id: weather
+ anchors.left: parent.left
+ anchors.leftMargin: 32
+ anchors.top: weatherLocation.bottom
+ anchors.topMargin: 32
+ columns: 2
+ columnSpacing: 32
+
+ Item {
+ // First row in grid
+ id: currentConditions
+ height: 288
+ width: 320
+
+ Image {
+ // Image depicting the current weather conditions (e.g. sunny, cloudy, etc.)
+ id: conditionsImage
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.horizontalCenterOffset: -32
+ fillMode: Image.PreserveAspectFit
+ height: 112
+ source: Qt.resolvedUrl(getWeatherImagery(sessionData.weatherCode))
+ }
+
+ Label {
+ // Current temperature in the configured temperature unit.
+ id: currentTemperature
+ anchors.baseline: parent.bottom
+ anchors.baselineOffset: -16
+ anchors.horizontalCenter: parent.horizontalCenter
+ font.family: "Noto Sans Display"
+ font.pixelSize: 176
+ font.weight: Font.Bold
+ text: sessionData.currentTemperature + "°"
+ }
+ }
+
+ Column {
+ // Second column
+ id: highLowTemperature
+ height: 288
+ width: 320
+ spacing: 32
+
+ Item {
+ // High temperature for today
+ id: highTemperature
+ height: 128
+ width: parent.width
+
+ Image {
+ id: highTemperatureIcon
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: 32
+ anchors.left: highTemperature.left
+ anchors.leftMargin: 32
+ fillMode: Image.PreserveAspectFit
+ height: 64
+ source: Qt.resolvedUrl("images/high_temperature.svg")
+ }
+
+ Label {
+ id: highTemperatureValue
+ anchors.baseline: parent.bottom
+ anchors.baselineOffset: -32
+ anchors.left: highTemperatureIcon.right
+ anchors.leftMargin: 32
+ font.family: "Noto Sans Display"
+ font.pixelSize: 118
+ font.weight: Font.Bold
+ text: sessionData.highTemperature + "°"
+ }
+ }
+
+ Item {
+ // Low temperature for today
+ id: lowTemperature
+ height: 128
+ width: parent.width
+
+ Image {
+ id: lowTemperatureIcon
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: 32
+ anchors.left: lowTemperature.left
+ anchors.leftMargin: 32
+ fillMode: Image.PreserveAspectFit
+ height: 64
+ source: Qt.resolvedUrl("images/low_temperature.svg")
+ }
+
+ Label {
+ id: lowTemperatureValue
+ anchors.baseline: parent.bottom
+ anchors.baselineOffset: -32
+ anchors.left: lowTemperatureIcon.right
+ anchors.leftMargin: 32
+ font.family: "Noto Sans Display"
+ font.pixelSize: 118
+ font.weight: Font.Light
+ text: sessionData.lowTemperature + "°"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/ui/highlow.qml b/ui/current_2_generic.qml
similarity index 83%
rename from ui/highlow.qml
rename to ui/current_2_generic.qml
index 60d638dc..9deff6b7 100644
--- a/ui/highlow.qml
+++ b/ui/current_2_generic.qml
@@ -10,22 +10,22 @@ WeatherDelegate {
id: root
Mycroft.AutoFitLabel {
- id: maxTemp
+ id: highTemperature
font.weight: Font.Bold
Layout.fillWidth: true
Layout.preferredHeight: proportionalGridUnit * 40
//The off-centering to balance the ° should be proportional as well, so we use the computed pixel size
rightPadding: -font.pixelSize * 0.1
- text: sessionData.max + "°"
+ text: sessionData.highTemperature + "°"
}
Mycroft.AutoFitLabel {
- id: minTemp
+ id: lowTemperature
Layout.fillWidth: true
Layout.preferredHeight: proportionalGridUnit * 40
rightPadding: -font.pixelSize * 0.1
font.weight: Font.Thin
font.styleName: "Thin"
- text: sessionData.min + "°"
+ text: sessionData.lowTemperature + "°"
}
}
diff --git a/ui/current_2_mark_ii.qml b/ui/current_2_mark_ii.qml
new file mode 100644
index 00000000..264ad53e
--- /dev/null
+++ b/ui/current_2_mark_ii.qml
@@ -0,0 +1,107 @@
+import QtQuick.Layouts 1.4
+import QtQuick 2.4
+import QtQuick.Controls 2.0
+import org.kde.kirigami 2.4 as Kirigami
+
+import Mycroft 1.0 as Mycroft
+import org.kde.lottie 1.0
+
+WeatherMarkIIDelegate {
+ id: root
+
+ Item {
+ // Bounding box for the content of the screen.
+ id: card
+ height: parent.height
+ width: parent.width
+
+ GridLayout {
+ id: weather
+ anchors.left: parent.left
+ anchors.leftMargin: 32
+ anchors.top: parent.top
+ anchors.topMargin: 32
+ columns: 2
+ columnSpacing: 32
+ rowSpacing: 0
+
+ Column {
+ id: wind
+ height: 352
+ width: 320
+
+ Item {
+ id: windIconBox
+ height: 128
+ width: parent.width
+
+ Image {
+ id: windIcon
+ anchors.top: parent.top
+ anchors.horizontalCenter: parent.horizontalCenter
+ fillMode: Image.PreserveAspectFit
+ height: parent.height
+ source: Qt.resolvedUrl("images/wind.svg")
+ }
+ }
+
+ Item {
+ id: windSpeedBox
+ anchors.top: windIconBox.bottom
+ anchors.topMargin: 32
+ height: 160
+ width: parent.width
+
+ Label {
+ id: windSpeed
+ anchors.baseline: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ font.family: "Noto Sans Display"
+ font.weight: Font.Bold
+ font.pixelSize: 176
+ text: sessionData.windSpeed
+ }
+ }
+ }
+
+ Column {
+ id: humidity
+ height: 352
+ width: 320
+
+ Item {
+ id: humidityIconBox
+ height: 128
+ width: parent.width
+
+ Image {
+ id: humidityIcon
+ anchors.top: parent.top
+ anchors.horizontalCenter: parent.horizontalCenter
+ fillMode: Image.PreserveAspectFit
+ height: parent.height
+ source: Qt.resolvedUrl("images/humidity.svg")
+ }
+ }
+
+ Item {
+ id: humidityValueBox
+ anchors.top: humidityIconBox.bottom
+ anchors.topMargin: 32
+ height: 160
+ width: parent.width
+
+ Label {
+ id: humidityValue
+ anchors.baseline: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ font.family: "Noto Sans Display"
+ font.pixelSize: 180
+ font.weight: Font.Bold
+ text: sessionData.humidity
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/ui/forecast1.qml b/ui/daily_1_generic.qml
similarity index 90%
rename from ui/forecast1.qml
rename to ui/daily_1_generic.qml
index b8b321d4..956df1ab 100644
--- a/ui/forecast1.qml
+++ b/ui/daily_1_generic.qml
@@ -6,7 +6,7 @@ import org.kde.kirigami 2.4 as Kirigami
import Mycroft 1.0 as Mycroft
import org.kde.lottie 1.0
-ForecastDelegate {
+DailyGenericDelegate {
id: root
model: sessionData.forecast.first
}
diff --git a/ui/forecast2.qml b/ui/daily_2_generic.qml
similarity index 90%
rename from ui/forecast2.qml
rename to ui/daily_2_generic.qml
index aad6da03..922b9de8 100644
--- a/ui/forecast2.qml
+++ b/ui/daily_2_generic.qml
@@ -6,7 +6,7 @@ import org.kde.kirigami 2.4 as Kirigami
import Mycroft 1.0 as Mycroft
import org.kde.lottie 1.0
-ForecastDelegate {
+DailyGenericDelegate {
id: root
model: sessionData.forecast.second
}
diff --git a/ui/daily_mark_ii.qml b/ui/daily_mark_ii.qml
new file mode 100644
index 00000000..84849f0d
--- /dev/null
+++ b/ui/daily_mark_ii.qml
@@ -0,0 +1,114 @@
+//import QtQuick.Layouts 1.4
+//import QtQuick 2.4
+//import QtQuick.Controls 2.0
+//import org.kde.kirigami 2.4 as Kirigami
+//
+//import Mycroft 1.0 as Mycroft
+//import org.kde.lottie 1.0
+//
+//ForecastMarkIIDelegate {
+// id: root
+// model: sessionData.forecast.first
+//}
+import QtQuick.Layouts 1.4
+import QtQuick 2.4
+import QtQuick.Controls 2.0
+import org.kde.kirigami 2.4 as Kirigami
+
+import Mycroft 1.0 as Mycroft
+import org.kde.lottie 1.0
+
+WeatherMarkIIDelegate {
+ Item {
+ id: hourlyCard
+ height: parent.height
+ width: parent.width
+
+ GridLayout {
+ id: currentWeather
+ anchors.left: parent.left
+ anchors.leftMargin: 32
+ anchors.top: parent.top
+ anchors.topMargin: 32
+ columns: sessionData.numberOfDays
+ columnSpacing: 32
+ rowSpacing: 0
+ Layout.fillWidth: true
+
+ Repeater {
+ id: conditionRepeater
+ model: sessionData.weatherCodes
+ anchors.top: parent.top
+
+ Item {
+ height: 64
+ width: 144
+
+ Image {
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.top: parent.top
+ height: 64
+ fillMode: Image.PreserveAspectFit
+ source: Qt.resolvedUrl(getWeatherImagery(modelData))
+ }
+ }
+ }
+
+ Repeater {
+ id: timeRepeater
+ model: sessionData.days
+
+ Item {
+ height: 64
+ width: 144
+
+ Label {
+ anchors.baseline: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ font.family: "Noto Sans Display"
+ font.pixelSize: 59
+ text: modelData
+ }
+ }
+ }
+
+ Repeater {
+ id: highTemperatureRepeater
+ model: sessionData.highTemperatures
+
+ Item {
+ height: 96
+ width: 144
+
+ Label {
+ anchors.baseline: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ font.family: "Noto Sans Display"
+ font.pixelSize: 72
+ font.weight: Font.Bold
+ text: modelData + "°"
+ }
+ }
+ }
+
+ Repeater {
+ id: lowTemperatureRepeater
+ model: sessionData.lowTemperatures
+
+ Item {
+ height: 96
+ width: 144
+
+ Label {
+ anchors.baseline: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ font.family: "Noto Sans Display"
+ font.pixelSize: 59
+ font.weight: Font.Thin
+ text: modelData + "°"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/ui/hourly_mark_ii.qml b/ui/hourly_mark_ii.qml
new file mode 100644
index 00000000..f0209855
--- /dev/null
+++ b/ui/hourly_mark_ii.qml
@@ -0,0 +1,114 @@
+//import QtQuick.Layouts 1.4
+//import QtQuick 2.4
+//import QtQuick.Controls 2.0
+//import org.kde.kirigami 2.4 as Kirigami
+//
+//import Mycroft 1.0 as Mycroft
+//import org.kde.lottie 1.0
+//
+//ForecastMarkIIDelegate {
+// id: root
+// model: sessionData.forecast.first
+//}
+import QtQuick.Layouts 1.4
+import QtQuick 2.4
+import QtQuick.Controls 2.0
+import org.kde.kirigami 2.4 as Kirigami
+
+import Mycroft 1.0 as Mycroft
+import org.kde.lottie 1.0
+
+WeatherMarkIIDelegate {
+ Item {
+ id: hourlyCard
+ height: parent.height
+ width: parent.width
+
+ GridLayout {
+ id: currentWeather
+ anchors.left: parent.left
+ anchors.leftMargin: 32
+ anchors.top: parent.top
+ anchors.topMargin: 32
+ columns: 4
+ columnSpacing: 32
+ rowSpacing: 0
+ Layout.fillWidth: true
+
+ Repeater {
+ id: conditionRepeater
+ model: sessionData.weatherCodes
+ anchors.top: parent.top
+
+ Item {
+ height: 64
+ width: 144
+
+ Image {
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.top: parent.top
+ height: 64
+ fillMode: Image.PreserveAspectFit
+ source: Qt.resolvedUrl(getWeatherImagery(modelData))
+ }
+ }
+ }
+
+ Repeater {
+ id: timeRepeater
+ model: sessionData.times
+
+ Item {
+ height: 64
+ width: 144
+
+ Label {
+ anchors.baseline: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ font.family: "Noto Sans Display"
+ font.pixelSize: 59
+ text: modelData
+ }
+ }
+ }
+
+ Repeater {
+ id: temperatureRepeater
+ model: sessionData.temperatures
+
+ Item {
+ height: 96
+ width: 144
+
+ Label {
+ anchors.baseline: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ font.family: "Noto Sans Display"
+ font.pixelSize: 72
+ font.weight: Font.Bold
+ text: modelData + "°"
+ }
+ }
+ }
+
+ Repeater {
+ id: precipitationRepeater
+ model: sessionData.chancesOfPrecipitation
+
+ Item {
+ height: 96
+ width: 144
+
+ Label {
+ anchors.baseline: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ font.family: "Noto Sans Display"
+ font.pixelSize: 59
+ font.weight: Font.Thin
+ text: modelData + "%"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/ui/images/cloudy.svg b/ui/images/cloudy.svg
new file mode 100644
index 00000000..6ce35734
--- /dev/null
+++ b/ui/images/cloudy.svg
@@ -0,0 +1,3 @@
+
diff --git a/ui/images/high_temperature.svg b/ui/images/high_temperature.svg
new file mode 100644
index 00000000..f6ae4048
--- /dev/null
+++ b/ui/images/high_temperature.svg
@@ -0,0 +1,3 @@
+
diff --git a/ui/images/humidity.svg b/ui/images/humidity.svg
new file mode 100644
index 00000000..f6fba0dc
--- /dev/null
+++ b/ui/images/humidity.svg
@@ -0,0 +1,6 @@
+
diff --git a/ui/images/low_temperature.svg b/ui/images/low_temperature.svg
new file mode 100644
index 00000000..d98838f2
--- /dev/null
+++ b/ui/images/low_temperature.svg
@@ -0,0 +1,3 @@
+
diff --git a/ui/images/partly_cloudy.svg b/ui/images/partly_cloudy.svg
new file mode 100644
index 00000000..361aa1f6
--- /dev/null
+++ b/ui/images/partly_cloudy.svg
@@ -0,0 +1,4 @@
+
diff --git a/ui/images/rain.svg b/ui/images/rain.svg
new file mode 100644
index 00000000..d941e79c
--- /dev/null
+++ b/ui/images/rain.svg
@@ -0,0 +1,6 @@
+
diff --git a/ui/images/snow.svg b/ui/images/snow.svg
new file mode 100644
index 00000000..584779b8
--- /dev/null
+++ b/ui/images/snow.svg
@@ -0,0 +1,3 @@
+
diff --git a/ui/images/storm.svg b/ui/images/storm.svg
new file mode 100644
index 00000000..4ca5bc3d
--- /dev/null
+++ b/ui/images/storm.svg
@@ -0,0 +1,3 @@
+
diff --git a/ui/images/sunny.svg b/ui/images/sunny.svg
new file mode 100644
index 00000000..b8c3c205
--- /dev/null
+++ b/ui/images/sunny.svg
@@ -0,0 +1,3 @@
+
diff --git a/ui/images/wind.svg b/ui/images/wind.svg
new file mode 100644
index 00000000..44a66f2c
--- /dev/null
+++ b/ui/images/wind.svg
@@ -0,0 +1,3 @@
+