diff --git a/.gitignore b/.gitignore
index 81e49ae0..40e809a3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,7 +11,7 @@ cmake_install.cmake
Makefile
build
tools
-
+node_modules/
# Resulting binary files
*.a
*.so
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 9c99b664..f6038816 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -1,54 +1,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 00000000..75a67e67
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,118 @@
+{
+ "name": "InfiniTime",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "dependencies": {
+ "lv_font_conv": "^1.5.2"
+ }
+ },
+ "node_modules/lv_font_conv": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/lv_font_conv/-/lv_font_conv-1.5.2.tgz",
+ "integrity": "sha512-0UapRSTkVP/pnB8Z4r2HDHx5p2dJx/xUG1+14u/WXo59mwuC7BahR+Bnx/66jKoDrG1wFQwn9ZzoyMxRHOD9bg==",
+ "bundleDependencies": [
+ "argparse",
+ "bit-buffer",
+ "debug",
+ "make-error",
+ "mkdirp",
+ "opentype.js",
+ "pngjs"
+ ],
+ "dependencies": {
+ "argparse": "^2.0.0",
+ "bit-buffer": "^0.2.5",
+ "debug": "^4.1.1",
+ "make-error": "^1.3.5",
+ "mkdirp": "^1.0.4",
+ "opentype.js": "^1.1.0",
+ "pngjs": "^6.0.0"
+ },
+ "bin": {
+ "lv_font_conv": "lv_font_conv.js"
+ }
+ },
+ "node_modules/lv_font_conv/node_modules/argparse": {
+ "version": "2.0.1",
+ "inBundle": true,
+ "license": "Python-2.0"
+ },
+ "node_modules/lv_font_conv/node_modules/bit-buffer": {
+ "version": "0.2.5",
+ "inBundle": true,
+ "license": "MIT"
+ },
+ "node_modules/lv_font_conv/node_modules/debug": {
+ "version": "4.3.1",
+ "inBundle": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/lv_font_conv/node_modules/make-error": {
+ "version": "1.3.6",
+ "inBundle": true,
+ "license": "ISC"
+ },
+ "node_modules/lv_font_conv/node_modules/mkdirp": {
+ "version": "1.0.4",
+ "inBundle": true,
+ "license": "MIT",
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/lv_font_conv/node_modules/ms": {
+ "version": "2.1.2",
+ "inBundle": true,
+ "license": "MIT"
+ },
+ "node_modules/lv_font_conv/node_modules/opentype.js": {
+ "version": "1.3.3",
+ "inBundle": true,
+ "license": "MIT",
+ "dependencies": {
+ "string.prototype.codepointat": "^0.2.1",
+ "tiny-inflate": "^1.0.3"
+ },
+ "bin": {
+ "ot": "bin/ot"
+ },
+ "engines": {
+ "node": ">= 8.0.0"
+ }
+ },
+ "node_modules/lv_font_conv/node_modules/pngjs": {
+ "version": "6.0.0",
+ "inBundle": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.13.0"
+ }
+ },
+ "node_modules/lv_font_conv/node_modules/string.prototype.codepointat": {
+ "version": "0.2.1",
+ "inBundle": true,
+ "license": "MIT"
+ },
+ "node_modules/lv_font_conv/node_modules/tiny-inflate": {
+ "version": "1.0.3",
+ "inBundle": true,
+ "license": "MIT"
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 00000000..d339766c
--- /dev/null
+++ b/package.json
@@ -0,0 +1,5 @@
+{
+ "dependencies": {
+ "lv_font_conv": "^1.5.2"
+ }
+}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0a97a015..550d3d48 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -364,6 +364,7 @@ list(APPEND SOURCE_FILES
BootloaderVersion.cpp
logging/NrfLogger.cpp
displayapp/DisplayApp.cpp
+ displayapp/WeatherHelper.cpp
displayapp/screens/Screen.cpp
displayapp/screens/Tile.cpp
displayapp/screens/InfiniPaint.cpp
@@ -588,6 +589,7 @@ set(INCLUDE_FILES
logging/Logger.h
logging/NrfLogger.h
displayapp/DisplayApp.h
+ displayapp/WeatherHelper.h
displayapp/Messages.h
displayapp/TouchEvents.h
displayapp/screens/Screen.h
diff --git a/src/components/ble/SimpleWeatherService.h b/src/components/ble/SimpleWeatherService.h
index 03d2f6ff..1aa52771 100644
--- a/src/components/ble/SimpleWeatherService.h
+++ b/src/components/ble/SimpleWeatherService.h
@@ -60,7 +60,7 @@ namespace Pinetime {
Smog = 8, // Mist
Unknown = 255
};
-
+
using Location = std::array; // 32 char + \0 (end of string)
struct CurrentWeather {
@@ -111,6 +111,10 @@ namespace Pinetime {
static int16_t CelsiusToFahrenheit(int16_t celsius) {
return celsius * 9 / 5 + 3200;
}
+
+ static const char* TemperatureColor(int16_t temperature);
+
+ static int16_t RoundTemperature(int16_t temp);
private:
// 00050000-78fc-48fe-8e23-433b3a1942d0
@@ -125,7 +129,7 @@ namespace Pinetime {
}
ble_uuid128_t weatherUuid {BaseUuid()};
-
+
ble_uuid128_t weatherDataCharUuid {CharUuid(0x00, 0x01)};
const struct ble_gatt_chr_def characteristicDefinition[2] = {{.uuid = &weatherDataCharUuid.u,
diff --git a/src/displayapp/UserApps.h b/src/displayapp/UserApps.h
index 67bbfa7d..531a447d 100644
--- a/src/displayapp/UserApps.h
+++ b/src/displayapp/UserApps.h
@@ -14,6 +14,7 @@
#include "displayapp/screens/WatchFaceInfineat.h"
#include "displayapp/screens/WatchFacePineTimeStyle.h"
#include "displayapp/screens/WatchFaceTerminal.h"
+#include "displayapp/screens/Weather.h"
namespace Pinetime {
namespace Applications {
diff --git a/src/displayapp/WeatherHelper.cpp b/src/displayapp/WeatherHelper.cpp
new file mode 100644
index 00000000..7a6e78a6
--- /dev/null
+++ b/src/displayapp/WeatherHelper.cpp
@@ -0,0 +1,110 @@
+/* Copyright (C) 2024 Caleb Fontenot
+
+ This file is part of InfiniTime.
+
+ InfiniTime 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 3 of the License, or
+ (at your option) any later version.
+
+ InfiniTime 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 .
+*/
+
+#include "WeatherHelper.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+using namespace Pinetime::Applications;
+ //Linear gradient temperature color calculator :)
+
+ int16_t WeatherHelper::RoundTemperature(int16_t temp) {
+ return temp = temp / 100 + (temp % 100 >= 50 ? 1 : 0);
+ }
+ std::tuple rgb565to888(int r, int g, int b) {
+ return {
+ ( r * 527 + 23 ) >> 6,
+ ( g * 259 + 33 ) >> 6,
+ ( b * 527 + 23 ) >> 6
+ };
+ }
+
+ const char* WeatherHelper::floatToRgbHex(lv_color_t rgb) {
+ std::tuple tuple = rgb565to888(LV_COLOR_GET_R(rgb), LV_COLOR_GET_G(rgb), LV_COLOR_GET_B(rgb));
+ char *rgbHex = new char[7];
+ snprintf(rgbHex, 7, "%02X%02X%02X", std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple));
+ return rgbHex;
+ }
+
+ lv_color_t hexToFloat(int rgb) {
+ return lv_color_hex(rgb);
+ }
+
+ float normalize(float value) {
+ if (value < 0.0f) {
+ return 0.0f;
+ } else if (value > 1.0f) {
+ return 1.0f;
+ } else {
+ return value;
+ }
+}
+
+ // reference: https://dev.to/ndesmic/linear-color-gradients-from-scratch-1a0e
+ const lv_color_t lerp(lv_color_t pointA, lv_color_t pointB, float normalValue) {
+ auto [redA, greenA, blueA] = rgb565to888(LV_COLOR_GET_R(pointA), LV_COLOR_GET_G(pointA), LV_COLOR_GET_B(pointA));
+ auto [redB, greenB, blueB] = rgb565to888(LV_COLOR_GET_R(pointB), LV_COLOR_GET_G(pointB), LV_COLOR_GET_B(pointB));
+ NRF_LOG_INFO("Normal value: %f", normalValue);
+
+ int outputRed = (redA + (redB - redA) * normalValue);
+ int outputGreen = (greenA + (greenB - greenA) * normalValue);
+ int outputBlue = (blueA + (blueB - blueA) * normalValue);
+
+ //increase brightness
+ float incAmount = 1.2;
+ outputRed = std::min(255, static_cast(outputRed*incAmount));
+ outputGreen = std::min(255, static_cast(outputGreen*incAmount));
+ outputBlue = std::min(255, static_cast(outputBlue*incAmount));
+
+ auto lerpOutput = LV_COLOR_MAKE(outputRed, outputGreen, outputBlue);
+ NRF_LOG_INFO("pointA: %i, %i, %i", redA, greenA, blueA);
+ NRF_LOG_INFO("pointB: %i, %i, %i", redB, greenB, blueB);
+ NRF_LOG_INFO("lerpOutput: %i, %i, %i", LV_COLOR_GET_R(lerpOutput), LV_COLOR_GET_G(lerpOutput), LV_COLOR_GET_B(lerpOutput));
+ return lerpOutput;
+ }
+
+ constexpr std::array getColors() {
+ const std::array colors = {0x5555ff, 0x00c9ff, 0xff9b00, 0xff0000};
+ std::array stops;
+ int8_t i = 0;
+ for (auto colorVal: colors) {
+ stops[i++] = (hexToFloat(colorVal));
+ }
+ return stops;
+ }
+
+ const lv_color_t WeatherHelper::TemperatureColor(int16_t temperature) {
+ std::array stops = getColors();
+ int tempRounded = RoundTemperature(temperature);
+ if (tempRounded < 0) {
+ tempRounded = 1;
+ }
+ // convert temperature to range between newMin and newMax
+ float oldRange = (oldMax - oldMin);
+ float newRange = (newMax - newMin);
+ float newValue = (((tempRounded - oldMin) * newRange) / oldRange) + newMin;
+ newValue = normalize(newValue);
+ return lerp(stops[0], stops[3], newValue);
+ }
diff --git a/src/displayapp/WeatherHelper.h b/src/displayapp/WeatherHelper.h
new file mode 100644
index 00000000..bb3aba81
--- /dev/null
+++ b/src/displayapp/WeatherHelper.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 2024 Caleb Fontenot
+
+ This file is part of InfiniTime.
+
+ InfiniTime 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 3 of the License, or
+ (at your option) any later version.
+
+ InfiniTime 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 .
+*/
+#pragma once
+#include
+#include
+
+namespace Pinetime {
+ namespace Applications {
+ class WeatherHelper {
+ public:
+ static int16_t RoundTemperature(int16_t temp);
+ static const lv_color_t TemperatureColor(int16_t temperature);
+ static const char* floatToRgbHex(lv_color_t rgb);
+ constexpr static float oldMax = 50;
+ constexpr static float oldMin = 0;
+ constexpr static float newMax = 1;
+ constexpr static float newMin = 0;
+ };
+ }
+ }
diff --git a/src/displayapp/screens/List.h b/src/displayapp/screens/List.h
index 17a25f82..b5e0e555 100644
--- a/src/displayapp/screens/List.h
+++ b/src/displayapp/screens/List.h
@@ -8,6 +8,7 @@
#include "displayapp/apps/Apps.h"
#include "components/settings/Settings.h"
+
#define MAXLISTITEMS 4
namespace Pinetime {
diff --git a/src/displayapp/screens/SystemInfo.cpp b/src/displayapp/screens/SystemInfo.cpp
index d265fddd..88e7e31e 100644
--- a/src/displayapp/screens/SystemInfo.cpp
+++ b/src/displayapp/screens/SystemInfo.cpp
@@ -80,7 +80,7 @@ std::unique_ptr SystemInfo::CreateScreen1() {
lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_recolor(label, true);
lv_label_set_text_fmt(label,
- "#FFFF00 InfiniTime#\n\n"
+ "#FFFF00 InfiniTime#\n"
"#808080 Version# %ld.%ld.%ld\n"
"#808080 Short Ref# %s\n"
"#808080 Build date#\n"
diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp
index 5321b7cc..c53c28a7 100644
--- a/src/displayapp/screens/Weather.cpp
+++ b/src/displayapp/screens/Weather.cpp
@@ -1,4 +1,5 @@
#include "displayapp/screens/Weather.h"
+#include "displayapp/WeatherHelper.h"
#include
#include "components/ble/SimpleWeatherService.h"
#include "components/datetime/DateTimeController.h"
@@ -9,34 +10,6 @@
using namespace Pinetime::Applications::Screens;
-namespace {
- lv_color_t TemperatureColor(int16_t temperature) {
- if (temperature <= 0) { // freezing
- return Colors::blue;
- } else if (temperature <= 400) { // ice
- return LV_COLOR_CYAN;
- } else if (temperature >= 2700) { // hot
- return Colors::deepOrange;
- }
- return Colors::orange; // normal
- }
-
- uint8_t TemperatureStyle(int16_t temperature) {
- if (temperature <= 0) { // freezing
- return LV_TABLE_PART_CELL3;
- } else if (temperature <= 400) { // ice
- return LV_TABLE_PART_CELL4;
- } else if (temperature >= 2700) { // hot
- return LV_TABLE_PART_CELL6;
- }
- return LV_TABLE_PART_CELL5; // normal
- }
-
- int16_t RoundTemperature(int16_t temp) {
- return temp = temp / 100 + (temp % 100 >= 50 ? 1 : 0);
- }
-}
-
Weather::Weather(Controllers::Settings& settingsController, Controllers::SimpleWeatherService& weatherService)
: settingsController {settingsController}, weatherService {weatherService} {
@@ -123,7 +96,7 @@ void Weather::Refresh() {
int16_t temp = optCurrentWeather->temperature;
int16_t minTemp = optCurrentWeather->minTemperature;
int16_t maxTemp = optCurrentWeather->maxTemperature;
- lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, TemperatureColor(temp));
+ lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, WeatherHelper::TemperatureColor(temp));
char tempUnit = 'C';
if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) {
temp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(temp);
@@ -133,9 +106,11 @@ void Weather::Refresh() {
}
lv_label_set_text(icon, Symbols::GetSymbol(optCurrentWeather->iconId));
lv_label_set_text(condition, Symbols::GetCondition(optCurrentWeather->iconId));
- lv_label_set_text_fmt(temperature, "%d°%c", RoundTemperature(temp), tempUnit);
- lv_label_set_text_fmt(minTemperature, "%d°", RoundTemperature(minTemp));
- lv_label_set_text_fmt(maxTemperature, "%d°", RoundTemperature(maxTemp));
+ lv_label_set_text_fmt(temperature, "%d°%c", WeatherHelper::RoundTemperature(temp), tempUnit);
+
+ lv_label_set_text_fmt(minTemperature, "%d°", WeatherHelper::RoundTemperature(minTemp));
+ lv_label_set_text_fmt(maxTemperature, "%d°", WeatherHelper::RoundTemperature(maxTemp));
+
} else {
lv_label_set_text(icon, "");
lv_label_set_text(condition, "");
@@ -155,8 +130,14 @@ void Weather::Refresh() {
for (int i = 0; i < Controllers::SimpleWeatherService::MaxNbForecastDays; i++) {
int16_t maxTemp = optCurrentForecast->days[i].maxTemperature;
int16_t minTemp = optCurrentForecast->days[i].minTemperature;
- lv_table_set_cell_type(forecast, 2, i, TemperatureStyle(maxTemp));
- lv_table_set_cell_type(forecast, 3, i, TemperatureStyle(minTemp));
+
+ auto color = WeatherHelper::TemperatureColor(maxTemp);
+ lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL5, LV_STATE_DEFAULT, color);
+ lv_table_set_cell_type(forecast, 2, i, LV_TABLE_PART_CELL5);
+
+ color = WeatherHelper::TemperatureColor(minTemp);
+ lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL6, LV_STATE_DEFAULT, color);
+ lv_table_set_cell_type(forecast, 3, i, LV_TABLE_PART_CELL6);
if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) {
maxTemp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(maxTemp);
minTemp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(minTemp);
@@ -165,8 +146,8 @@ void Weather::Refresh() {
if (wday > 7) {
wday -= 7;
}
- maxTemp = RoundTemperature(maxTemp);
- minTemp = RoundTemperature(minTemp);
+ maxTemp = WeatherHelper::RoundTemperature(maxTemp);
+ minTemp = WeatherHelper::RoundTemperature(minTemp);
const char* dayOfWeek = Controllers::DateTime::DayOfWeekShortToStringLow(static_cast(wday));
lv_table_set_cell_value(forecast, 0, i, dayOfWeek);
lv_table_set_cell_value(forecast, 1, i, Symbols::GetSymbol(optCurrentForecast->days[i].iconId));
@@ -181,7 +162,11 @@ void Weather::Refresh() {
maxPadding[0] = '\0';
minPadding[diff] = '\0';
}
+ //auto color = WeatherHelper::TemperatureColor(maxTemp);
+ //lv_obj_set_style_local_text_color(forecast, 2, i, color);
lv_table_set_cell_value_fmt(forecast, 2, i, "%s%d", maxPadding, maxTemp);
+ //color = WeatherHelper::TemperatureColor(minTemp);
+ //lv_obj_set_style_local_text_color(forecast, 3, i, color);
lv_table_set_cell_value_fmt(forecast, 3, i, "%s%d", minPadding, minTemp);
}
} else {
diff --git a/src/displayapp/screens/Weather.h b/src/displayapp/screens/Weather.h
index 6975311e..e72cc86e 100644
--- a/src/displayapp/screens/Weather.h
+++ b/src/displayapp/screens/Weather.h
@@ -24,7 +24,7 @@ namespace Pinetime {
~Weather() override;
void Refresh() override;
-
+
private:
Controllers::Settings& settingsController;
Controllers::SimpleWeatherService& weatherService;