diff --git a/.gitmodules b/.gitmodules index ea9ed74..3913e73 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "static/Shuffle"] path = static/Shuffle url = https://source.netsyms.com/Mirrors/Vestride_Shuffle.git +[submodule "static/weather-icons"] + path = static/weather-icons + url = https://source.netsyms.com/Mirrors/erikflowers_weather-icons.git diff --git a/action.php b/action.php index 28f6029..f4ade7e 100644 --- a/action.php +++ b/action.php @@ -7,7 +7,6 @@ /** * Make things happen when buttons are pressed and forms submitted. */ - require_once __DIR__ . "/required.php"; if ($VARS['action'] !== "signout") { @@ -35,8 +34,37 @@ switch ($VARS['action']) { session_destroy(); header('Location: index.php?logout=1'); die("Logged out."); - case "thumbnail": - header("Content-Type: image/jpeg"); - // TODO + case "settempunits": + $unit = "C"; + if (!empty($VARS['unit'])) { + switch (strtoupper($VARS['unit'])) { + case "F": + $unit = "F"; + break; + case "C": + $unit = "C"; + break; + case "K": + $unit = "K"; + break; + } + } + setcookie("TemperatureUnitsPref", $unit, time() + 60 * 60 * 24 * 90); + returnToSender(""); + break; + case "setspeedunits": + $unit = "K"; + if (!empty($VARS['unit'])) { + switch (strtoupper($VARS['unit'])) { + case "KPH": + $unit = "KPH"; + break; + case "MPH": + $unit = "MPH"; + break; + } + } + setcookie("SpeedUnitsPref", $unit, time() + 60 * 60 * 24 * 90); + returnToSender(""); break; } \ No newline at end of file diff --git a/langs/en/weather.json b/langs/en/weather.json new file mode 100644 index 0000000..4d9c085 --- /dev/null +++ b/langs/en/weather.json @@ -0,0 +1,6 @@ +{ + "High: {temp}{units}": "High: {temp}{units}", + "Low: {temp}{units}": "Low: {temp}{units}", + "Temperature: {temp}{units}": "Temperature: {temp}{units}", + "{temp}{units}": "{temp}{units}" +} diff --git a/lib/Conditions.lib.php b/lib/Conditions.lib.php new file mode 100644 index 0000000..da4fc82 --- /dev/null +++ b/lib/Conditions.lib.php @@ -0,0 +1,249 @@ +time, SUNFUNCS_RET_TIMESTAMP, $this->lat, $this->lng); + $sunset = date_sunset($this->time, SUNFUNCS_RET_TIMESTAMP, $this->lat, $this->lng); + + $this->daytime = ($this->time >= $sunrise && $this->time < $sunset); + + return $this->daytime; + } + + /** + * Check if it's day or night, based on location and time. + * @return bool true if daytime. + */ + public function isDay(): bool { + return $this->setDayorNight(); + } + + /** + * Check if it's windy (6 or higher on the Beaufort scale). + * + * A 6 is described as large branches in motion, whistling heard in power + * lines, and umbrellas used with difficulty. + * + * https://en.wikipedia.org/wiki/Beaufort_scale + * + * @return bool true if it's windy. + */ + public function isWindy(): bool { + return ($this->windSpeed >= 39); + } + + /** + * Check if it's cloudy out (greater than 50% cloud cover). + * @return bool + */ + public function isCloudy(): bool { + return ($this->cloudCover > 0.5); + } + + /** + * Check if it's overcast(greater than 80% cloud cover). + * @return bool + */ + public function isOvercast(): bool { + return ($this->cloudCover > 0.8); + } + + /** + * Check if it's really hot out (> 32C/90F) + * @return bool true if it's hotter than my mixtape outside + */ + public function isHot(): bool { + return ($this->temperature > 32); + } + + /** + * Check if it's really cold out (< -6C/20F) + * @return bool true if it's cold af + */ + public function isCold(): bool { + return ($this->temperature < -6); + } + + /** + * Get a suitable icon to show for the weather conditions. + * + * https://erikflowers.github.io/weather-icons/ + * + * @return string + */ + public function getIcon(): string { + $downfall = ""; + + if ($this->precipProbability > 0.5) { + switch ($this->precipType) { + case PrecipType::RAIN: + $downfall = "rain"; + break; + case PrecipType::SNOW: + $downfall = "snow"; + break; + case PrecipType::SLEET: + $downfall = "sleet"; + break; + case PrecipType::HAIL: + $downfall = "hail"; + break; + } + } + + // Handle precipitation icons for day/night, windy/not, and overcast + if ($downfall != "") { + $wind = $this->isWindy() ? "-wind" : ""; + if ($this->isOvercast()) { + return "wi-$downfall$wind"; + } else { + $daynight = $this->isDay() ? "day" : "night-alt"; + return "wi-$daynight-$downfall$wind"; + } + } + + if ($this->isOvercast()) { + return "wi-cloudy"; + } + + if ($this->isCloudy()) { + return $this->isDay() ? "wi-day-cloudy" : "wi-night-alt-cloudy"; + } + + if ($this->isCold()) { + return "wi-snowflake-cold"; + } + + if ($this->isDay()) { + if ($this->isHot()) { + return "wi-hot"; + } + return "wi-day-sunny"; + } + + // Pick one for variety + return ["wi-night-clear", "wi-night-clear", "wi-stars"][random_int(0, 2)]; + } + +} + +class PrecipType { + + const NONE = 1; + const RAIN = 2; + const SNOW = 4; + const SLEET = 8; + const HAIL = 16; + +} diff --git a/lib/Weather.lib.php b/lib/Weather.lib.php index c000ecf..20a2c6e 100644 --- a/lib/Weather.lib.php +++ b/lib/Weather.lib.php @@ -6,6 +6,81 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -class Weather { - -} \ No newline at end of file +abstract class Weather { + + protected $conditions = []; + protected $currently; + protected $low; + protected $high; + protected $lat = 0.0; + protected $lng = 0.0; + + public function __construct($latitude, $longitude) { + $this->lat = $latitude; + $this->lng = $longitude; + } + + abstract protected function loadForecast(); + + // Getters + + public function getLatitude(): float { + return $this->lat; + } + + public function getLongitude(): float { + return $this->lng; + } + + public function getForecast(): array { + return $this->conditions; + } + + public function getCurrently(): Conditions { + return $this->currently; + } + + public function getLow() { + return $this->low; + } + + public function getHigh() { + return $this->high; + } + + // Setters + + public function setForecast(array $conditions) { + $this->conditions = $conditions; + } + + public function setCurrently(Conditions $weather) { + $this->currently = $weather; + } + + public function setLow(Conditions $weather) { + $this->low = $weather; + } + + public function setHigh(Conditions $weather) { + $this->high = $weather; + } + + /** + * Convert a temperature in Celsuis to the given unit ("F" or "K"). + * @param float $temperature + * @param string $to + * @return float + */ + public static function convertDegCToUnits(float $temperature, string $to): float { + switch (strtoupper($to)) { + case "K": + return $temperature + 273.15; + case "F": + return ($temperature * (9.0 / 5.0)) + 32.0; + default: + return $temperature; + } + } + +} diff --git a/lib/Weather_DarkSky.lib.php b/lib/Weather_DarkSky.lib.php index 707fa92..db84c62 100644 --- a/lib/Weather_DarkSky.lib.php +++ b/lib/Weather_DarkSky.lib.php @@ -8,4 +8,39 @@ class Weather_DarkSky extends Weather { -} \ No newline at end of file + public function loadForecast() { + global $SETTINGS; + $apikey = $SETTINGS['apikeys']['darksky.net']; + $url = "https://api.darksky.net/forecast/$apikey/" . $this->lat . ',' . $this->lng; + $json = ApiFetcher::get($url, ["exclude" => "minutely,hourly", "units" => "ca", "lang" => $SETTINGS['language']]); + $resp = json_decode($json); + + $currently = new Conditions(); + + $currently->lat = $this->lat; + $currently->lng = $this->lng; + $currently->time = $resp->currently->time; + + $currently->summary = $resp->currently->summary; + $currently->setDayorNight(); + + $currently->temperature = $resp->currently->temperature; + $currently->tempFeels = $resp->currently->apparentTemperature; + + $currently->precipProbability = $resp->currently->precipProbability; + + $currently->ozone = $resp->currently->ozone; + $currently->dewpoint = $resp->currently->dewPoint; + $currently->cloudCover = $resp->currently->cloudCover; + $currently->humidity = $resp->currently->humidity; + $currently->visibility = $resp->currently->visibility; + $currently->uvindex = $resp->currently->uvIndex; + + $currently->windSpeed = $resp->currently->windSpeed; + $currently->windGust = $resp->currently->windGust; + $currently->windBearing = $resp->currently->windBearing; + + $this->setCurrently($currently); + } + +} diff --git a/pages.php b/pages.php index 23cf0d4..e397887 100644 --- a/pages.php +++ b/pages.php @@ -10,6 +10,9 @@ define("PAGES", [ "title" => "Overview", "navbar" => true, "icon" => "fas fa-home", + "styles" => [ + "static/weather-icons/css/weather-icons.min.css" + ], "scripts" => [ "static/Shuffle/dist/shuffle.min.js", "static/js/home.js" diff --git a/pages/home.php b/pages/home.php index 4dee109..df5fa0f 100644 --- a/pages/home.php +++ b/pages/home.php @@ -5,6 +5,21 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +//$weatherclass = "Weather_" . $SETTINGS['sources']['weather']; +//$weather = new $weatherclass(46.595806, -112.027031); // TODO: get user location +$weather = new Weather_DarkSky(46.595806, -112.027031); +$weather->loadForecast(); + +$tempunits = "C"; +$degreesymbol = "°"; +if (!empty($_COOKIE['TemperatureUnitsPref']) && preg_match("/[FCK]/", $_COOKIE['TemperatureUnitsPref'])) { + $tempunits = $_COOKIE['TemperatureUnitsPref']; + // No degree symbol for Kelvins + if ($tempunits == "K") { + $degreesymbol = ""; + } +} + News::load($SETTINGS["sources"]["news"]); $newsitems = News::getItems(); @@ -16,36 +31,73 @@ foreach ($newsitems as $item) { } ?> +
+
+
+ getCurrently(); + ?> +
+ +
+
+

summary; ?>

+

build("{temp}{units}", ["temp" => round(Weather::convertDegCToUnits($currently->temperature, $tempunits), 1), "units" => " $degreesymbol$tempunits"]); ?>

+
+
+
+ +
+

get("Headlines"); ?>

- -
+
+ = 6) { + if ($count >= 10) { break; } $count++; ?> - - \ No newline at end of file + + +
+ +
\ No newline at end of file diff --git a/settings.template.php b/settings.template.php index 332002c..d98242c 100644 --- a/settings.template.php +++ b/settings.template.php @@ -51,9 +51,7 @@ $SETTINGS = [ "NewsAPI", "Reddit" ], - "weather" => [ - "DarkSky" - ] + "weather" => "DarkSky" ], // List of required user permissions to access this app. "permissions" => [ diff --git a/static/js/home.js b/static/js/home.js new file mode 100644 index 0000000..a0e78e6 --- /dev/null +++ b/static/js/home.js @@ -0,0 +1,15 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + + +window.shuffleInstance = new window.Shuffle(document.getElementById('news-grid'), { + itemSelector: '.grid__brick', + sizer: '.sizer-element' +}); + +setInterval(function () { + window.shuffleInstance.layout(); +}, 500); \ No newline at end of file diff --git a/static/weather-icons b/static/weather-icons new file mode 160000 index 0000000..58cb6a2 --- /dev/null +++ b/static/weather-icons @@ -0,0 +1 @@ +Subproject commit 58cb6a2ee70b3352f5b82d1d124da05b26659c69