From 80a75d9809aad65159c1cd9b36b5a6544db0e1ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A1lint=20Erd=C5=91si?= Date: Fri, 22 Nov 2019 13:37:19 +0100 Subject: [PATCH] Add dashboard widget (#76) Add weather dashboard widget --- appinfo/info.xml | 3 + css/widget.css | 47 ++++++++++ img/app-dark.svg | 63 +++++++++++++ js/widget.js | 78 ++++++++++++++++ lib/Widgets/DefaultWidget.php | 167 ++++++++++++++++++++++++++++++++++ templates/widget.php | 21 +++++ 6 files changed, 379 insertions(+) create mode 100644 css/widget.css create mode 100644 img/app-dark.svg create mode 100644 js/widget.js create mode 100644 lib/Widgets/DefaultWidget.php create mode 100644 templates/widget.php diff --git a/appinfo/info.xml b/appinfo/info.xml index 54b52d3..d727c9c 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -20,4 +20,7 @@ OCA\Weather\Settings\AdminSettings + + OCA\Weather\Widgets\DefaultWidget + diff --git a/css/widget.css b/css/widget.css new file mode 100644 index 0000000..9a6fbd8 --- /dev/null +++ b/css/widget.css @@ -0,0 +1,47 @@ +.icon-weather { + background-image: url('../img/app-dark.svg'); +} +.icon-weather-light { + background-image: url('../img/app.svg'); +} + +.weatherWidgetContents { + margin: 0 44px; +} + +.weatherWidgetContents h3.locationValue { + text-align: left; +} + +.weatherWidgetContents .weatherWidgetList { + display: flex; + padding: 0; + flex-wrap: wrap; +} + +.weatherWidgetContents .weatherWidgetList .measurement, +.weatherWidgetContents .weatherWidgetList .value { + flex: 1 1 50%; + text-align: left; + min-width: 80px; +} + +.weatherWidgetContents .weatherWidgetList .measurement { + font-weight: bold; +} + +.weatherWidgetContents .weaterWidgetList .measurement::after { + content:":"; +} + +.weatherWidgetContents .info { + position: absolute; + bottom: 11px; + left: 0; + margin: 22px; +} + +.weatherWidgetContents .info.error { + color: red; + color: var(--color-error); +} diff --git a/img/app-dark.svg b/img/app-dark.svg new file mode 100644 index 0000000..d9cff13 --- /dev/null +++ b/img/app-dark.svg @@ -0,0 +1,63 @@ + +image/svg+xml + diff --git a/js/widget.js b/js/widget.js new file mode 100644 index 0000000..448f545 --- /dev/null +++ b/js/widget.js @@ -0,0 +1,78 @@ +/** + * + * @copyright Copyright (c) 2019, Balint Erdosi (erdosib@gmail.com) + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +/** global: OCA */ +/** global: net */ + +(function () { + + /** + * @constructs Weather + */ + var Weather = function() { + } + + Weather.prototype.divWeather = null; + Weather.prototype.init = function() { + this.getWeather(); + + } + + Weather.prototype.getWeather = function() { + var request = { + widget: "weather", + request: "getWeather" + }; + + net.requestWidget(request, this.updateWeather); + } + + Weather.prototype.updateWeather = function(result) { + var divWeather = document.querySelector("#widget-weather"); + var divInfo = divWeather.querySelector(".info"); + var temperatureRepresentationLookup = { + "kelvin": "°K", + "imperial":"°F", + "metric": "°C" + } + if (result.value.error) { + divInfo.classList.add("error"); + divInfo.innerHTML = "Failed to update: " + result.value.error; + return; + } + try { + divInfo.classList.remove("error"); + divInfo.innerHTML = ""; + divWeather.querySelector(".locationValue").innerHTML = result.value.location; + divWeather.querySelector(".temperatureValue").innerHTML = result.value.temperature; + divWeather.querySelector(".temperatureRepresentation").innerHTML = temperatureRepresentationLookup[result.value.metric]|| "ERROR"; + divWeather.querySelector(".weatherValue").innerHTML = result.value.weather; + divWeather.querySelector(".humidityValue").innerHTML = result.value.humidity; + divWeather.querySelector(".windValue").innerHTML = result.value.wind; + } catch (e) { + divInfo.classList.add("error"); + divInfo.innerHTML = "Failed to update some data."; + } + } + + OCA.DashBoard.Weather = Weather; + OCA.DashBoard.weather = new Weather(); +})() diff --git a/lib/Widgets/DefaultWidget.php b/lib/Widgets/DefaultWidget.php new file mode 100644 index 0000000..d82eab2 --- /dev/null +++ b/lib/Widgets/DefaultWidget.php @@ -0,0 +1,167 @@ +. + * + */ + +namespace OCA\Weather\Widgets; + +use \OCP\AppFramework\App; +use \OCP\AppFramework\Http; + +use \OCP\IContainer; + +use OCP\Dashboard\Model\WidgetSetup; +use OCP\Dashboard\Model\WidgetTemplate; +use OCP\Dashboard\IDashboardWidget; +use OCP\Dashboard\Model\IWidgetRequest; +use OCP\Dashboard\Model\IWidgetConfig; + +use \OCA\Weather\AppInfo\Application; +use \OCA\Weather\Controller\WeatherController; + +use \OCP\IL10N; +use \OCP\ILogger; + +class DefaultWidget implements IDashboardWidget { + + const WIDGET_ID = 'weather'; + + + /** @var IL19N */ + private $l10n; + private $logger; + + + /** + * DefaultWidget constructor + * @param IL10N $l10n + */ + public function __construct(ILogger $logger, IL10N $l10n) { + $this->l10n = $l10n; + $this->logger = $logger; + } + + /** + * @return string + */ + public function getId(): string { + return self::WIDGET_ID; + } + + /** + * @return string + */ + public function getName(): string { + return $this->l10n->t('Weather'); + } + + /** + * @return string + */ + public function getDescription(): string { + return $this->l10n->t('Watch the weather directly on your Nextcloud.'); + } + + /** + * @return WidgetTemplate + */ + public function getWidgetTemplate(): WidgetTemplate { + $template = new WidgetTemplate(); + $template->addCss('widget') + ->addJs('widget') + ->setIcon('icon-weather') + ->setContent('widget') + ->setInitFunction('OCA.DashBoard.weather.getWeather'); + return $template; + } + + /** + * @return WidgetTemplate + */ + public function getWidgetSetup(): WidgetSetup { + $setup = new WidgetSetup(); + $setup->addSize(WidgetSetup::SIZE_TYPE_MIN, 2, 1); + $setup->addSize(WidgetSetup::SIZE_TYPE_MAX, 4, 5); + $setup->addSize(WidgetSetup::SIZE_TYPE_DEFAULT, 2, 3); + $setup->addDelayedJob('OCA.DashBoard.weather.getWeather', 600); + return $setup; + } + + /** + * @param IWidgetConfig $settings + */ + public function loadWidget(IWidgetConfig $settings) { + + } + + /** + * @param IWidgetRequest $request + */ + public function requestWidget(IWidgetRequest $request) { + if ($request->getRequest() === 'getWeather') { + $app = new Application(); + $container = $app->getContainer(); + $weatherController = $container->query('OCA\Weather\Controller\WeatherController'); + $cityController = $container->query('OCA\Weather\Controller\CityController'); + $settingsController = $container->query('OCA\Weather\Controller\SettingsController'); + + $allCities = json_decode($cityController->getAll()->render(), true); + + if (count($allCities) == 0) { + $request->addResult('error', $this->l10n->t('Please make sure you select cities in the Weather app.')); + return; + } + + $homeCityId = $allCities['home']; + $homeCityArray = array_filter( + $allCities['cities'], + function($city) use ($homeCityId) { + return $city['id'] === $homeCityId; + } + ); + + if (count($homeCityArray) != 1) { + $request->addResult('error', $this->l10n->t('Please make sure you select a home city in the Weather app.')); + return; + } + + $homeCity = array_pop($homeCityArray)['name']; + + $resultJSONResponse = $weatherController->get($homeCity); + if ($resultJSONResponse->getStatus() != Http::STATUS_OK) { + $request->addResult('error', $this->l10n->t('Failed to get city weather informations. Please contact your administrator')); + return; + } + + $result = json_decode($resultJSONResponse->render(), true); + $metric = json_decode($settingsController->metricGet()->render(), true)['metric']; + + $request->addResult('location', $homeCity); + $request->addResult('temperature', $result['main']['temp']); + $request->addResult('metric', $metric); + $request->addResult('weather', $result['weather'][0]['description']); + $request->addResult('humidity', $result['main']['humidity']); + $request->addResult('wind', $result['wind']['speed']); + } + } + + +} +?> diff --git a/templates/widget.php b/templates/widget.php new file mode 100644 index 0000000..f74a5a3 --- /dev/null +++ b/templates/widget.php @@ -0,0 +1,21 @@ + + +
+

+
t('Updating widget…')); ?>
+
+
t('Temperature')); ?>
+
 
+ +
t('Cloudiness')); ?>
+
+ +
t('Humidity')); ?>
+
 %
+ +
t('Wind')); ?>
+
 m/s
+
+