InfiniTime.git

commit e9822108d2a9d3f3e3afe56bea731d3c67313f71

Author: Adam <git@apiote.xyz>

change world face to world hands and prepare weather

 src/components/datetime/DateTimeController.h | 2 
 src/displayapp/screens/Clock.cpp | 3 
 src/displayapp/screens/WatchFaceMine.cpp | 155 +++++++++++++++++----
 src/displayapp/screens/WatchFaceMine.h | 24 ++


diff --git a/src/components/datetime/DateTimeController.h b/src/components/datetime/DateTimeController.h
index aa88a423dede4eea082c9e28c6790a0653ecc1e8..00e73dcc84c7f545e7c484e6fdfd53ab1aadb159 100644
--- a/src/components/datetime/DateTimeController.h
+++ b/src/components/datetime/DateTimeController.h
@@ -143,7 +143,7 @@         return currentDateTime - std::chrono::seconds((tzOffset + dstOffset) * 15 * 60);
       }
 
       std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> WorldDateTime(uint8_t index) const {
-        return UTCDateTime() + std::chrono::seconds(worldOffset(index) * 15 * 60);
+        return UTCDateTime() + std::chrono::seconds((worldOffset(index) + dstOffset) * 15 * 60);  // pedantically, it should be dstOffset of the timezone at index, not main clock timezone
       }
 
       std::chrono::seconds Uptime() const {




diff --git a/src/displayapp/screens/Clock.cpp b/src/displayapp/screens/Clock.cpp
index 06372b8c56f05d3c5bea33c101b53eb1618f8c99..17b4f092af2898540a2f20fc50e23b3b51e9b226 100644
--- a/src/displayapp/screens/Clock.cpp
+++ b/src/displayapp/screens/Clock.cpp
@@ -130,5 +130,6 @@                                                   batteryController,
                                                   bleController,
                                                   notificationManager,
                                                   settingsController,
-                                                  motionController);
+                                                  motionController,
+                                                  weatherService);
 }




diff --git a/src/displayapp/screens/WatchFaceMine.cpp b/src/displayapp/screens/WatchFaceMine.cpp
index 4ba5f82ab344c58a9c1345c1dda44c41ff30f256..8e038b408783feeb55edb5d96c7de3e2bada867e 100644
--- a/src/displayapp/screens/WatchFaceMine.cpp
+++ b/src/displayapp/screens/WatchFaceMine.cpp
@@ -7,6 +7,7 @@ #include "displayapp/screens/BleIcon.h"
 #include "displayapp/screens/Symbols.h"
 #include "displayapp/screens/NotificationIcon.h"
 #include "components/settings/Settings.h"
+#include "components/ble/weather/WeatherService.h"
 #include "displayapp/InfiniTimeTheme.h"
 
 using namespace Pinetime::Applications::Screens;
@@ -48,14 +49,16 @@                                  const Controllers::Battery& batteryController,
                                  const Controllers::Ble& bleController,
                                  Controllers::NotificationManager& notificationManager,
                                  Controllers::Settings& settingsController,
-                                 Controllers::MotionController& motionController)
+                                 Controllers::MotionController& motionController,
+                                 Controllers::WeatherService& weatherService)
   : currentDateTime {{}},
     dateTimeController {dateTimeController},
     batteryController {batteryController},
     bleController {bleController},
     notificationManager {notificationManager},
     settingsController {settingsController},
-    motionController {motionController} {
+    motionController {motionController},
+    weatherService {weatherService} {
 
   sHour = 99;
   sMinute = 99;
@@ -78,6 +81,18 @@   lv_obj_set_style_local_text_color(bluetoothIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x0082fc));
   lv_label_set_text_static(bluetoothIcon, BleIcon::GetIcon(false));
   lv_obj_align(bluetoothIcon, NULL, LV_ALIGN_IN_TOP_RIGHT, -30, 0);
 
+  weatherIcon = lv_label_create(lv_scr_act(), nullptr);
+  lv_obj_set_style_local_text_color(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x7b7e82));
+  lv_obj_set_style_local_text_font(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &fontawesome_weathericons);
+  lv_label_set_text(weatherIcon, "");
+  lv_obj_align(weatherIcon, nullptr, LV_ALIGN_IN_TOP_MID, -15, 50);
+  lv_obj_set_auto_realign(weatherIcon, true);
+
+  temperature = lv_label_create(lv_scr_act(), nullptr);
+  lv_label_set_text(temperature, "");
+  lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x7b7e82));
+  lv_obj_align(temperature, nullptr, LV_ALIGN_IN_TOP_MID, 15, 50);
+
 
   lv_style_init(&tick_style);
   lv_style_set_line_width(&tick_style, LV_STATE_DEFAULT, 5);
@@ -94,28 +109,18 @@   lv_style_set_line_rounded(&tick_style_six, LV_STATE_DEFAULT, true);
 
   for (int i = 0; i < 24; ++i) {
     tick[i] = lv_line_create(lv_scr_act(), NULL);
-    tick_world[i] = lv_line_create(lv_scr_act(), NULL);
     if (i == 0) {
       lv_obj_add_style(tick[i], LV_LINE_PART_MAIN, &tick_style_zero);
-      lv_obj_add_style(tick_world[i], LV_LINE_PART_MAIN, &tick_style_zero);
     } else if (i%3 == 0) {
       lv_obj_add_style(tick[i], LV_LINE_PART_MAIN, &tick_style_six);
-      lv_obj_add_style(tick_world[i], LV_LINE_PART_MAIN, &tick_style_six);
     } else {
       lv_obj_add_style(tick[i], LV_LINE_PART_MAIN, &tick_style);
-      lv_obj_add_style(tick_world[i], LV_LINE_PART_MAIN, &tick_style);
     }
   }
 
   clockType = settingsController.GetClockType();
   DrawFace();
 
-  if (dateTimeController.isWorldTimeEnabled(0)) {
-    worldClockOffset = dateTimeController.worldOffset(0);
-    DrawOffsetFace();
-  }
-
-
   label_date_greg = lv_label_create(lv_scr_act(), NULL);
   lv_obj_set_style_local_text_color(label_date_greg, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x919191));
   lv_label_set_text_fmt(label_date_greg, "%s\n%02i", dateTimeController.DayOfWeekShortToString(), dateTimeController.Day());
@@ -129,7 +134,9 @@   lv_label_set_align(label_date_world, LV_LABEL_ALIGN_CENTER);
   lv_obj_align(label_date_world, NULL, LV_ALIGN_CENTER, -50, 0);
 
 
+  minute_body_world = lv_line_create(lv_scr_act(), NULL);
   minute_body = lv_line_create(lv_scr_act(), NULL);
+  hour_body_world = lv_line_create(lv_scr_act(), NULL);
   hour_body = lv_line_create(lv_scr_act(), NULL);
   second_body = lv_line_create(lv_scr_act(), NULL);
 
@@ -142,12 +149,24 @@   lv_style_set_line_color(&second_line_style, LV_STATE_DEFAULT, lv_color_hex(0xff5c57));
   lv_style_set_line_rounded(&second_line_style, LV_STATE_DEFAULT, true);
   lv_obj_add_style(second_body, LV_LINE_PART_MAIN, &second_line_style);
 
+  lv_style_init(&minute_line_style_world);
+  lv_style_set_line_width(&minute_line_style_world, LV_STATE_DEFAULT, 5);
+  lv_style_set_line_color(&minute_line_style_world, LV_STATE_DEFAULT, lv_color_hex(0x5d3636));
+  lv_style_set_line_rounded(&minute_line_style_world, LV_STATE_DEFAULT, true);
+  lv_obj_add_style(minute_body_world, LV_LINE_PART_MAIN, &minute_line_style_world);
+
   lv_style_init(&minute_line_style);
   lv_style_set_line_width(&minute_line_style, LV_STATE_DEFAULT, 5);
   lv_style_set_line_color(&minute_line_style, LV_STATE_DEFAULT, lv_color_hex(0xfafafa));
   lv_style_set_line_rounded(&minute_line_style, LV_STATE_DEFAULT, true);
   lv_obj_add_style(minute_body, LV_LINE_PART_MAIN, &minute_line_style);
 
+  lv_style_init(&hour_line_style_world);
+  lv_style_set_line_width(&hour_line_style_world, LV_STATE_DEFAULT, 7);
+  lv_style_set_line_color(&hour_line_style_world, LV_STATE_DEFAULT, lv_color_hex(0x5d3636));
+  lv_style_set_line_rounded(&hour_line_style_world, LV_STATE_DEFAULT, true);
+  lv_obj_add_style(hour_body_world, LV_LINE_PART_MAIN, &hour_line_style_world);
+
   lv_style_init(&hour_line_style);
   lv_style_set_line_width(&hour_line_style, LV_STATE_DEFAULT, 7);
   lv_style_set_line_color(&hour_line_style, LV_STATE_DEFAULT, lv_color_hex(0xfafafa));
@@ -182,7 +201,9 @@ WatchFaceMine::~WatchFaceMine() {
   lv_task_del(taskRefresh);
 
   lv_style_reset(&hour_line_style);
+  lv_style_reset(&hour_line_style_world);
   lv_style_reset(&minute_line_style);
+  lv_style_reset(&minute_line_style_world);
   lv_style_reset(&second_line_style);
 
   lv_style_reset(&tick_style);
@@ -215,34 +236,36 @@     lv_line_set_points(tick[i], tick_point[i], 2);
   }
 }
 
-void WatchFaceMine::DrawOffsetFace() {
+void WatchFaceMine::DrawOffsetHands(uint8_t sHour, uint8_t sMinute, uint8_t hour, uint8_t minute) {  // from https://github.com/InfiniTimeOrg/InfiniTime/pull/1454
   worldClockOffset.Get();
   using days = std::chrono::duration<int, std::ratio<86400>>;
   auto worldDateTime = dateTimeController.WorldDateTime(0);
   auto worldDp = std::chrono::floor<days>(worldDateTime);
   auto worldTime = worldDateTime - worldDp;
   uint8_t worldHour = std::chrono::floor<std::chrono::hours>(worldTime).count();
-  int8_t offset = worldHour - dateTimeController.Hours();
-  uint8_t div = 1;
-  switch (clockType.Get()) {
-    case Controllers::Settings::ClockType::H24:
-      div = 24;
-    break;
-    case Controllers::Settings::ClockType::H12:
-      div = 12;
-    break;
-  };
-  for (int i = 0; i < div; ++i) {
-    if (offset != 0) {
-      auto angle = ((i-offset) * 30) / (div / 12);
-      tick_world_point[i][0] = CoordinateRelocate(68, angle);
-      tick_world_point[i][1] = CoordinateRelocate(70, angle);
+
+  auto worldHp = std::chrono::floor<std::chrono::hours>(worldTime);
+  worldTime = worldTime - worldHp;
+  uint8_t worldMinute = std::chrono::floor<std::chrono::minutes>(worldTime).count();
+
+  if (sMinute != minute) {
+    auto const angle = worldMinute * 6;
+    minute_point_world[0] = CoordinateRelocate(0, angle);
+    minute_point_world[1] = CoordinateRelocate(MinuteLength, angle);
+
+    lv_line_set_points(minute_body_world, minute_point_world, 2);
+  }
+
+  if (sHour != hour || sMinute != minute) {
+    auto angle = (worldHour * 30 + worldMinute / 2);
+    if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) {
+      angle /= 2;
     }
-    else {
-      tick_world_point[i][0] = {.x = 0, .y = 0};
-      tick_world_point[i][1] = {.x = 0, .y = 0};
-    }
-    lv_line_set_points(tick_world[i], tick_world_point[i], 2);
+
+    hour_point_world[0] = CoordinateRelocate(0, angle);
+    hour_point_world[1] = CoordinateRelocate(HourLength, angle);
+
+    lv_line_set_points(hour_body_world, hour_point_world, 2);
   }
 }
 
@@ -258,8 +281,8 @@     DrawFace();
   }
 
   worldClockOffset = dateTimeController.worldOffset(0);
-  if (dateTimeController.isWorldTimeEnabled(0) && (worldClockOffset.IsUpdated() || clockTypeUpdated || sHour != hour)) {
-    DrawOffsetFace();
+  if (dateTimeController.isWorldTimeEnabled(0) && (worldClockOffset.IsUpdated() || clockTypeUpdated || sHour != hour || sMinute != minute)) {
+    DrawOffsetHands(sHour, sMinute, hour, minute);
   }
 
   if (sSecond != second) {
@@ -295,6 +318,37 @@     lv_line_set_points(hour_body, hour_point, 2);
   }
 }
 
+void WatchFaceMine::DrawWeather() {  // from https://github.com/InfiniTimeOrg/InfiniTime/pull/1856
+  if (weatherService.GetCurrentTemperature()->timestamp != 0 && weatherService.GetCurrentClouds()->timestamp != 0 &&
+      weatherService.GetCurrentPrecipitation()->timestamp != 0) {
+    nowTemp = (weatherService.GetCurrentTemperature()->temperature / 100);
+    clouds = (weatherService.GetCurrentClouds()->amount);
+    precip = (weatherService.GetCurrentPrecipitation()->amount);
+    if (nowTemp.IsUpdated()) {
+      std::string hawaii = decimalToDozenal(1.8 * nowTemp.Get() - 36);
+      lv_label_set_text_fmt(temperature, "%s", hawaii.c_str());
+      if ((clouds <= 30) && (precip == 0)) {
+        lv_label_set_text(weatherIcon, Symbols::sun);
+      } else if ((clouds >= 70) && (clouds <= 90) && (precip == 1)) {
+        lv_label_set_text(weatherIcon, Symbols::cloudSunRain);
+      } else if ((clouds > 90) && (precip == 0)) {
+        lv_label_set_text(weatherIcon, Symbols::cloud);
+      } else if ((clouds > 70) && (precip >= 2)) {
+        lv_label_set_text(weatherIcon, Symbols::cloudShowersHeavy);
+      } else {
+        lv_label_set_text(weatherIcon, Symbols::cloudSun);
+      };
+      lv_obj_realign(temperature);
+      lv_obj_realign(weatherIcon);
+    }
+  } else {
+    lv_label_set_text_static(temperature, "");
+    lv_label_set_text(weatherIcon, "");
+    lv_obj_realign(temperature);
+    lv_obj_realign(weatherIcon);
+  }
+}
+
 void WatchFaceMine::SetBatteryIcon() {
   auto batteryPercent = batteryPercentRemaining.Get();
   batteryIcon.SetBatteryPercentage(batteryPercent);
@@ -371,6 +425,8 @@     } else {
       lv_obj_add_style(steps_body_trace, LV_LINE_PART_MAIN, &steps_line_style_trace);
     }
   }
+
+  // DrawWeather();
 }
 
 std::string WatchFaceMine::gregorianToFixed(uint8_t day, Pinetime::Controllers::DateTime::Months month, uint16_t year) {
@@ -445,3 +501,32 @@   sprintf(buf, "%s\n%s%c %d%d", weekdays[ordinal%7], moons1[moon], moons2[moon], week, sun);
 
   return std::string(buf);
 }
+
+std::string WatchFaceMine::decimalToDozenal(int16_t decimal) {
+  std::string result = "";
+  if (decimal < 0) {
+    result = "-";
+    decimal = -decimal;
+  }
+  uint16_t p12, rem;
+  while (true) {
+    p12 = decimal / 12;
+    rem = decimal % 12;
+    char ch;
+    if (rem == 11) {
+      ch = 'E';
+    } else if (rem == 10) {
+      ch = 'X';
+    } else {
+      ch = '0' + rem;
+    }
+    result += ch;
+
+    if (p12 == 0){
+      break;
+    }
+  }
+
+  return result;
+}
+




diff --git a/src/displayapp/screens/WatchFaceMine.h b/src/displayapp/screens/WatchFaceMine.h
index c885297200c25a3fe8694431b871b1ea4d46df9c..986e930b41d66e7c93753ea541e124c761f49c30 100644
--- a/src/displayapp/screens/WatchFaceMine.h
+++ b/src/displayapp/screens/WatchFaceMine.h
@@ -8,6 +8,7 @@ #include "components/datetime/DateTimeController.h"
 #include "components/battery/BatteryController.h"
 #include "components/ble/BleController.h"
 #include "components/ble/NotificationManager.h"
+#include "components/ble/weather/WeatherService.h"
 #include "displayapp/screens/BatteryIcon.h"
 #include "utility/DirtyValue.h"
 
@@ -29,7 +30,8 @@                         const Controllers::Battery& batteryController,
                         const Controllers::Ble& bleController,
                         Controllers::NotificationManager& notificationManager,
                         Controllers::Settings& settingsController,
-                        Controllers::MotionController& motionController);
+                        Controllers::MotionController& motionController,
+                        Controllers::WeatherService& weather);
 
         ~WatchFaceMine() override;
 
@@ -58,15 +60,16 @@
         lv_obj_t* tick[24];
         lv_point_t tick_point[24][2];
 
-        lv_obj_t* tick_world[24];
-        lv_point_t tick_world_point[24][2];
-
         lv_obj_t* hour_body;
+        lv_obj_t* hour_body_world;
         lv_obj_t* minute_body;
+        lv_obj_t* minute_body_world;
         lv_obj_t* second_body;
 
         lv_point_t hour_point[2];
+        lv_point_t hour_point_world[2];
         lv_point_t minute_point[2];
+        lv_point_t minute_point_world[2];
         lv_point_t second_point[2];
 
         lv_style_t tick_style;
@@ -74,7 +77,9 @@         lv_style_t tick_style_zero;
         lv_style_t tick_style_six;
 
         lv_style_t hour_line_style;
+        lv_style_t hour_line_style_world;
         lv_style_t minute_line_style;
+        lv_style_t minute_line_style_world;
         lv_style_t second_line_style;
 
         lv_obj_t* label_date_greg;
@@ -82,6 +87,12 @@         lv_obj_t* label_date_world;
         lv_obj_t* plugIcon;
         lv_obj_t* notificationIcon;
         lv_obj_t* bluetoothIcon;
+        lv_obj_t* weatherIcon;
+        lv_obj_t* temperature;
+
+        Utility::DirtyValue<int16_t> nowTemp {};
+        int16_t clouds = 0;
+        int16_t precip = 0;
 
         lv_obj_t* steps_body;
         lv_obj_t* steps_body_trace;
@@ -99,15 +110,18 @@         const Controllers::Ble& bleController;
         Controllers::NotificationManager& notificationManager;
         Controllers::Settings& settingsController;
         Controllers::MotionController& motionController;
+        Controllers::WeatherService& weatherService;
 
         void DrawFace();
-        void DrawOffsetFace();
+        void DrawOffsetHands(uint8_t, uint8_t, uint8_t, uint8_t);
         void UpdateClock();
         void SetBatteryIcon();
+        void DrawWeather();
         std::string gregorianToFixed(uint8_t, Pinetime::Controllers::DateTime::Months, uint16_t);
         bool isLeapYear(uint16_t);
         uint16_t gregorianToOrdinal(uint8_t, Pinetime::Controllers::DateTime::Months, bool);
         std::string ordinalToFixed(uint16_t, bool);
+        std::string decimalToDozenal(int16_t);
 
         lv_task_t* taskRefresh;
       };