diff --git a/applets/weather/data/i18n.dat b/applets/weather/data/i18n.dat index 8ed87ad21..8ec79702d 100644 --- a/applets/weather/data/i18n.dat +++ b/applets/weather/data/i18n.dat @@ -1,21 +1,18 @@ wind direction|N wind direction|NNE wind direction|NE wind direction|ENE wind direction|E wind direction|SSE wind direction|SE wind direction|ESE wind direction|S wind direction|NNW wind direction|NW wind direction|WNW wind direction|W wind direction|SSW wind direction|SW wind direction|WSW wind direction|VR wind speed|Calm -pressure tendency|rising -pressure tendency|falling -pressure tendency|steady diff --git a/applets/weather/package/contents/ui/main.qml b/applets/weather/package/contents/ui/main.qml index 554c80d6a..328b26925 100644 --- a/applets/weather/package/contents/ui/main.qml +++ b/applets/weather/package/contents/ui/main.qml @@ -1,446 +1,450 @@ /* * Copyright 2018 Friedrich W. H. Kossebau * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import QtQuick 2.9 import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.private.weather 1.0 Item { id: root readonly property string weatherSource: plasmoid.nativeInterface.source readonly property int updateInterval: plasmoid.nativeInterface.updateInterval readonly property int displayTemperatureUnit: plasmoid.nativeInterface.displayTemperatureUnit readonly property int displaySpeedUnit: plasmoid.nativeInterface.displaySpeedUnit readonly property int displayPressureUnit: plasmoid.nativeInterface.displayPressureUnit readonly property int displayVisibilityUnit: plasmoid.nativeInterface.displayVisibilityUnit property bool connectingToSource: false readonly property bool needsConfiguration: !generalModel.location && !connectingToSource readonly property int invalidUnit: -1 //TODO: make KUnitConversion::InvalidUnit usable here // model providing final display strings for observation properties readonly property var observationModel: { var model = {}; var data = weatherDataSource.currentData || {}; function getNumber(key) { var number = data[key]; if (typeof number === "string") { var parsedNumber = parseFloat(number); return isNaN(parsedNumber) ? null : parsedNumber; } return (typeof number !== "undefined") && (number !== "") ? number : null; } function getNumberOrString(key) { var number = data[key]; return (typeof number !== "undefined") && (number !== "") ? number : null; } var reportTemperatureUnit = data["Temperature Unit"] || invalidUnit; var reportPressureUnit = data["Pressure Unit"] || invalidUnit; var reportVisibilityUnit = data["Visibility Unit"] || invalidUnit; var reportWindSpeedUnit = data["Wind Speed Unit"] || invalidUnit; model["conditions"] = data["Current Conditions"] || ""; var conditionIconName = data["Condition Icon"] || null; model["conditionIconName"] = conditionIconName ? Util.existingWeatherIconName(conditionIconName) : "weather-none-available"; var temperature = getNumber("Temperature"); model["temperature"] = temperature !== null ? Util.temperatureToDisplayString(displayTemperatureUnit, temperature, reportTemperatureUnit) : ""; var windchill = getNumber("Windchill"); // Use temperature unit to convert windchill temperature // we only show degrees symbol not actual temperature unit model["windchill"] = windchill !== null ? Util.temperatureToDisplayString(displayTemperatureUnit, windchill, reportTemperatureUnit, false, true) : ""; var humidex = getNumber("Humidex"); // TODO: this seems wrong, does the humidex have temperature as units? // Use temperature unit to convert humidex temperature // we only show degrees symbol not actual temperature unit model["humidex"] = humidex !== null ? Util.temperatureToDisplayString(displayTemperatureUnit, humidex, reportTemperatureUnit, false, true) : ""; var dewpoint = getNumber("Dewpoint"); model["dewpoint"] = dewpoint !== null ? Util.temperatureToDisplayString(displayTemperatureUnit, dewpoint, reportTemperatureUnit) : ""; var pressure = getNumber("Pressure"); model["pressure"] = pressure !== null ? Util.valueToDisplayString(displayPressureUnit, pressure, reportPressureUnit, 2) : ""; var pressureTendency = (data && data["Pressure Tendency"]) || null; - model["pressureTendency"] = pressureTendency ? i18nc("pressure tendency", pressureTendency) : ""; + model["pressureTendency"] = + pressureTendency === "rising" ? i18nc("pressure tendency", "Rising") : + pressureTendency === "falling" ? i18nc("pressure tendency", "Falling") : + pressureTendency === "steady" ? i18nc("pressure tendency", "Steady") : + /* else */ ""; var visibility = getNumberOrString("Visibility"); model["visibility"] = visibility !== null ? ((reportVisibilityUnit !== invalidUnit) ? Util.valueToDisplayString(displayVisibilityUnit, visibility, reportVisibilityUnit, 1) : visibility) : ""; var humidity = getNumber("Humidity"); model["humidity"] = humidity !== null ? Util.percentToDisplayString(humidity) : ""; // TODO: missing check for windDirection validness var windDirection = data["Wind Direction"] || ""; var windSpeed = getNumberOrString("Wind Speed"); var windSpeedText; if (windSpeed !== null && windSpeed !== "") { var windSpeedNumeric = (typeof windSpeed !== 'number') ? parseFloat(windSpeed) : windSpeed; if (!isNaN(windSpeedNumeric)) { if (windSpeedNumeric !== 0) { windSpeedText = Util.valueToDisplayString(displaySpeedUnit, windSpeedNumeric, reportWindSpeedUnit, 1); } else { windSpeedText = i18nc("Wind condition", "Calm"); } } else { // TODO: i18n? windSpeedText = windSpeed; } } model["windSpeed"] = windSpeedText || ""; model["windDirectionId"] = windDirection; model["windDirection"] = windDirection ? i18nc("wind direction", windDirection) : ""; var windGust = getNumber("Wind Gust"); model["windGust"] = windGust !== null ? Util.valueToDisplayString(displaySpeedUnit, windGust, reportWindSpeedUnit, 1) : ""; return model; } readonly property var generalModel: { var model = {}; var data = weatherDataSource.currentData || {}; var todayForecastTokens = (data["Short Forecast Day 0"] || "").split("|"); model["location"] = data["Place"] || ""; model["courtesy"] = data["Credit"] || ""; model["creditUrl"] = data["Credit Url"] || ""; var forecastDayCount = parseInt(data["Total Weather Days"] || ""); var forecastTitle; if (!isNaN(forecastDayCount) && forecastDayCount > 0) { forecastTitle = i18ncp("Forecast period timeframe", "1 Day", "%1 Days", forecastDayCount); } model["forecastTitle"] = forecastTitle || ""; var conditionIconName = observationModel.conditionIconName; if (!conditionIconName || conditionIconName === "weather-none-available") { // try icon from current weather forecast if (todayForecastTokens.length === 6 && todayForecastTokens[1] !== "N/U") { conditionIconName = Util.existingWeatherIconName(todayForecastTokens[1]); } else { conditionIconName = "weather-none-available"; } } model["currentConditionIconName"] = conditionIconName; return model; } readonly property var detailsModel: { var model = []; if (observationModel.windchill) { model.push({ "label": i18nc("@label", "Windchill:"), "text": observationModel.windchill }); }; if (observationModel.humidex) { model.push({ "label": i18nc("@label", "Humidex:"), "text": observationModel.humidex }); } if (observationModel.dewpoint) { model.push({ "label": i18nc("@label ground temperature", "Dewpoint:"), "text": observationModel.dewpoint }); } if (observationModel.pressure) { model.push({ "label": i18nc("@label", "Pressure:"), "text": observationModel.pressure }); } if (observationModel.pressureTendency) { model.push({ "label": i18nc("@label pressure tendency, rising/falling/steady", "Pressure Tendency:"), "text": observationModel.pressureTendency }); } if (observationModel.visibility) { model.push({ "label": i18nc("@label", "Visibility:"), "text": observationModel.visibility }); } if (observationModel.humidity) { model.push({ "label": i18nc("@label", "Humidity:"), "text": observationModel.humidity }); } if (observationModel.windGust) { model.push({ "label": i18nc("@label", "Wind Gust:"), "text": observationModel.windGust }); } return model; } readonly property var forecastModel: { var model = []; var data = weatherDataSource.currentData; var forecastDayCount = parseInt((data && data["Total Weather Days"]) || ""); if (isNaN(forecastDayCount) || forecastDayCount <= 0) { return model; } var reportTemperatureUnit = (data && data["Temperature Unit"]) || invalidUnit; var dayItems = []; var conditionItems = []; var hiItems = []; var lowItems = []; for (var i = 0; i < forecastDayCount; ++i) { var forecastDayKey = "Short Forecast Day " + i; var forecastDayTokens = ((data && data[forecastDayKey]) || "").split("|"); if (forecastDayTokens.length !== 6) { // We don't have the right number of tokens, abort trying break; } dayItems.push(forecastDayTokens[0]); // If we see N/U (Not Used) we skip the item var weatherIconName = forecastDayTokens[1]; if (weatherIconName && weatherIconName !== "N/U") { var iconAndToolTip = Util.existingWeatherIconName(weatherIconName); iconAndToolTip += "|"; var condition = forecastDayTokens[2]; var probability = forecastDayTokens[5]; if (probability !== "N/U" && probability !== "N/A" && !!probability) { iconAndToolTip += i18nc("certain weather condition (probability percentage)", "%1 (%2 %)", condition, probability); } else { iconAndToolTip += condition; } conditionItems.push(iconAndToolTip); } var tempHigh = forecastDayTokens[3]; if (tempHigh !== "N/U") { if (tempHigh === "N/A" || !tempHigh) { hiItems.push(i18nc("Short for no data available", "-")); } else { hiItems.push(Util.temperatureToDisplayString(displayTemperatureUnit, tempHigh, reportTemperatureUnit, true)); } } var tempLow = forecastDayTokens[4]; if (tempLow !== "N/U") { if (tempLow === "N/A" || !tempLow) { lowItems.push(i18nc("Short for no data available", "-")); } else { lowItems.push(Util.temperatureToDisplayString(displayTemperatureUnit, tempLow, reportTemperatureUnit, true)); } } } if (dayItems.length) { model.push(dayItems); } if (conditionItems.length) { model.push(conditionItems); } if (hiItems.length) { model.push(hiItems); } if (lowItems.length) { model.push(lowItems); } return model; } readonly property var noticesModel: { var model = []; var data = weatherDataSource.currentData; var warnings = []; var warningsCount = parseInt((data && data["Total Warnings Issued"]) || ""); if (isNaN(warningsCount)) { warningsCount = 0; } for (var i = 0; i < warningsCount; ++i) { warnings.push({ "description": data["Warning Description "+i], "info": data["Warning Info "+i] }); } model.push(warnings); var watches = []; var watchesCount = parseInt((data && data["Total Watches Issued"]) || ""); if (isNaN(watchesCount)) { watchesCount = 0; } for (var i = 0; i < watchesCount; ++i) { watches.push({ "description": data["Watch Description "+i], "info": data["Watch Info "+i] }); } model.push(watches); return model; } PlasmaCore.DataSource { id: weatherDataSource readonly property var currentData: data[weatherSource] engine: "weather" connectedSources: weatherSource interval: updateInterval * 60 * 1000 onConnectedSourcesChanged: { if (weatherSource) { connectingToSource = true; plasmoid.busy = true; connectionTimeoutTimer.start(); } } onCurrentDataChanged: { if (currentData) { connectionTimeoutTimer.stop(); connectingToSource = false; plasmoid.busy = false; } } } Timer { id: connectionTimeoutTimer interval: 60 * 1000 // 1 min repeat: false onTriggered: { connectingToSource = false; plasmoid.busy = false; // TODO: inform user var sourceTokens = weatherSource.split("|"); var foo = i18n("Weather information retrieval for %1 timed out.", sourceTokens.value(2)); } } // workaround for now to ensure "Please configure" tooltip // TODO: remove when configurationRequired works Plasmoid.icon: needsConfiguration ? "configure" : generalModel.currentConditionIconName Plasmoid.toolTipMainText: needsConfiguration ? i18nc("@info:tooltip", "Please configure") : generalModel.location Plasmoid.toolTipSubText: { if (!generalModel.location) { return ""; } var tooltips = []; var temperature = plasmoid.nativeInterface.temperatureShownInTooltip ? observationModel.temperature : null; if (observationModel.conditions && temperature) { tooltips.push(i18nc("weather condition + temperature", "%1 %2", observationModel.conditions, temperature)); } else if (observationModel.conditions || temperature) { tooltips.push(observationModel.conditions || temperature); } if (plasmoid.nativeInterface.windShownInTooltip && observationModel.windSpeed) { if (observationModel.windDirection) { if (observationModel.windGust) { tooltips.push(i18nc("winddirection windspeed (windgust)", "%1 %2 (%3)", observationModel.windDirection, observationModel.windSpeed, observationModel.windGust)); } else { tooltips.push(i18nc("winddirection windspeed", "%1 %2", observationModel.windDirection, observationModel.windSpeed)); } } else { tooltips.push(observationModel.windSpeed); } } if (plasmoid.nativeInterface.pressureShownInTooltip && observationModel.pressure) { if (observationModel.pressureTendency) { tooltips.push(i18nc("pressure (tendency)", "%1 (%2)", observationModel.pressure, observationModel.pressureTendency)); } else { tooltips.push(observationModel.pressure); } } if (plasmoid.nativeInterface.humidityShownInTooltip && observationModel.humidity) { tooltips.push(i18n("Humidity: %1", observationModel.humidity)); } return tooltips.join("\n"); } Plasmoid.associatedApplicationUrls: generalModel.creditUrl || null Plasmoid.compactRepresentation: CompactRepresentation { generalModel: root.generalModel observationModel: root.observationModel } Plasmoid.fullRepresentation: FullRepresentation { generalModel: root.generalModel observationModel: root.observationModel } Component.onCompleted: { // workaround for missing note about being in systray or similar (kde bug #388995) // guess from cointainer structure data and make available to config page plasmoid.nativeInterface.needsToBeSquare = (plasmoid.parent !== null && ((plasmoid.parent.pluginName === 'org.kde.plasma.private.systemtray' || plasmoid.parent.objectName === 'taskItemContainer'))); } }