1 Commits

Author SHA1 Message Date
b6ae30166b Add roman readme 2024-01-18 14:32:25 -08:00
27 changed files with 1835 additions and 256 deletions

View File

@@ -91,12 +91,6 @@ jobs:
- name: Add sunset lib to InfiniSim - name: Add sunset lib to InfiniSim
run: patch -i docker/infinisim-cmake.patch InfiniSim/CMakeLists.txt run: patch -i docker/infinisim-cmake.patch InfiniSim/CMakeLists.txt
- name: Remove Terminal from InfiniSim
run: patch -i docker/infinisim-terminal.patch InfiniSim/littlefs-do-main.cpp
- name: Remove Digital from InfiniSim
run: patch -i docker/infinisim-main.patch InfiniSim/main.cpp
- name: CMake - name: CMake
# disable BUILD_RESOURCES as this is already done when building the firmware # disable BUILD_RESOURCES as this is already done when building the firmware
run: | run: |

View File

@@ -4,15 +4,14 @@
Fast open-source firmware for the [PineTime smartwatch](https://www.pine64.org/pinetime/) with many features, written in modern C++. Fast open-source firmware for the [PineTime smartwatch](https://www.pine64.org/pinetime/) with many features, written in modern C++.
## Wadokei fork ## Roman Time
Based on [Sudrien's Watchy Wadokei](https://github.com/Sudrien/watchy_wadokei) -- This branch contains a sundial that tries to approximate a Roman sundial
displays an Edo-period Japanese clock face and a sunrise/sunset-based hour hand. as if it was mounted on a south-facing wall (i.e. rotates counterclockwise).
Also chimes hours according to the number on the face (9,8,7,6,5,4) at the top It's activated by selecting the Analog face and Fuzzy time format.
of each modern hour (so noon and 1pm will be 9 chimes, 2pm and 3pm will be 8, etc).
See https://github.com/Sudrien/watchy_wadokei/blob/main/Reckoning.md for more ideas! Based on (Sudrien's Roman watch face)[https://github.com/Sudrien/watchy_romantime]
## New to InfiniTime? ## New to InfiniTime?

View File

@@ -1,20 +0,0 @@
diff --git a/main.cpp b/main.cpp
index 8070db7..530ff4b 100644
--- a/main.cpp
+++ b/main.cpp
@@ -823,14 +823,10 @@ public:
void switch_to_screen(uint8_t screen_idx)
{
if (screen_idx == 1) {
- settingsController.SetWatchFace(Pinetime::Applications::WatchFace::Digital);
- displayApp.StartApp(Pinetime::Applications::Apps::Clock, Pinetime::Applications::DisplayApp::FullRefreshDirections::None);
- }
- else if (screen_idx == 2) {
settingsController.SetWatchFace(Pinetime::Applications::WatchFace::Analog);
displayApp.StartApp(Pinetime::Applications::Apps::Clock, Pinetime::Applications::DisplayApp::FullRefreshDirections::None);
}
- else if (screen_idx == 3) {
+ else if (screen_idx == 2) {
settingsController.SetWatchFace(Pinetime::Applications::WatchFace::PineTimeStyle);
displayApp.StartApp(Pinetime::Applications::Apps::Clock, Pinetime::Applications::DisplayApp::FullRefreshDirections::None);
}

View File

@@ -1,17 +0,0 @@
diff --git a/littlefs-do-main.cpp b/littlefs-do-main.cpp
index 0a5dfbd..3e818af 100644
--- a/littlefs-do-main.cpp
+++ b/littlefs-do-main.cpp
@@ -537,10 +537,10 @@ int command_settings(const std::string &program_name, const std::vector<std::str
{
auto clockface = settingsController.GetWatchFace();
auto clockface_str = [](auto val) {
- if (val == Pinetime::Applications::WatchFace::Digital) return "Digital";
+ //if (val == Pinetime::Applications::WatchFace::Digital) return "Digital";
if (val == Pinetime::Applications::WatchFace::Analog) return "Analog";
if (val == Pinetime::Applications::WatchFace::PineTimeStyle) return "PineTimeStyle";
- if (val == Pinetime::Applications::WatchFace::Terminal) return "Terminal";
+ //if (val == Pinetime::Applications::WatchFace::Terminal) return "Terminal";
return "unknown";
}(clockface);
std::cout << "ClockFace: " << static_cast<uint32_t>(clockface) << " " << clockface_str << std::endl;

View File

@@ -424,11 +424,11 @@ list(APPEND SOURCE_FILES
## Watch faces ## Watch faces
displayapp/screens/WatchFaceAnalog.cpp displayapp/screens/WatchFaceAnalog.cpp
#displayapp/screens/WatchFaceDigital.cpp displayapp/screens/WatchFaceDigital.cpp
#displayapp/screens/WatchFaceInfineat.cpp displayapp/screens/WatchFaceInfineat.cpp
#displayapp/screens/WatchFaceTerminal.cpp displayapp/screens/WatchFaceTerminal.cpp
displayapp/screens/WatchFacePineTimeStyle.cpp displayapp/screens/WatchFacePineTimeStyle.cpp
#displayapp/screens/WatchFaceCasioStyleG7710.cpp displayapp/screens/WatchFaceCasioStyleG7710.cpp
## ##
@@ -778,7 +778,7 @@ link_directories(
set(COMMON_FLAGS -MP -MD -mthumb -mabi=aapcs -ftree-vrp -ffunction-sections -fdata-sections -fno-strict-aliasing -fno-builtin -fshort-enums -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fstack-usage -fno-exceptions -fno-non-call-exceptions) set(COMMON_FLAGS -MP -MD -mthumb -mabi=aapcs -ftree-vrp -ffunction-sections -fdata-sections -fno-strict-aliasing -fno-builtin -fshort-enums -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fstack-usage -fno-exceptions -fno-non-call-exceptions)
set(WARNING_FLAGS -Wall -Wextra -Warray-bounds=2 -Wformat=2 -Wformat-overflow=2 -Wformat-truncation=2 -Wformat-nonliteral -Wno-missing-field-initializers -Wno-unknown-pragmas -Wno-expansion-to-defined -Wreturn-type -Werror=return-type -Werror) set(WARNING_FLAGS -Wall -Wextra -Warray-bounds=2 -Wformat=2 -Wformat-overflow=2 -Wformat-truncation=2 -Wformat-nonliteral -Wno-missing-field-initializers -Wno-unknown-pragmas -Wno-expansion-to-defined -Wreturn-type -Werror=return-type -Werror)
set(DEBUG_FLAGS -Og -g3) set(DEBUG_FLAGS -Og -g3)
set(DEBUG_FLAGS -Os) set(RELEASE_FLAGS -Os)
set(CXX_FLAGS -fno-rtti) set(CXX_FLAGS -fno-rtti)
set(ASM_FLAGS -x assembler-with-cpp) set(ASM_FLAGS -x assembler-with-cpp)
add_definitions(-DCONFIG_GPIO_AS_PINRESET) add_definitions(-DCONFIG_GPIO_AS_PINRESET)
@@ -847,7 +847,7 @@ add_subdirectory(displayapp/fonts)
target_compile_options(infinitime_fonts PUBLIC target_compile_options(infinitime_fonts PUBLIC
${COMMON_FLAGS} ${COMMON_FLAGS}
$<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}>
$<$<CONFIG:RELEASE>: ${DEBUG_FLAGS}> $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}>
$<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}>
$<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}>
) )
@@ -861,7 +861,7 @@ target_include_directories(nrf-sdk SYSTEM PUBLIC ${INCLUDES_FROM_LIBS})
target_compile_options(nrf-sdk PRIVATE target_compile_options(nrf-sdk PRIVATE
${COMMON_FLAGS} ${COMMON_FLAGS}
$<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}>
$<$<CONFIG:RELEASE>: ${DEBUG_FLAGS}> $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}>
$<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}>
$<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}>
-O3 -O3
@@ -874,7 +874,7 @@ target_include_directories(nimble SYSTEM PUBLIC ${INCLUDES_FROM_LIBS})
target_compile_options(nimble PRIVATE target_compile_options(nimble PRIVATE
${COMMON_FLAGS} ${COMMON_FLAGS}
$<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}>
$<$<CONFIG:RELEASE>: ${DEBUG_FLAGS}> $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}>
$<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}>
$<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}>
) )
@@ -886,7 +886,7 @@ target_include_directories(lvgl SYSTEM PUBLIC ${INCLUDES_FROM_LIBS})
target_compile_options(lvgl PRIVATE target_compile_options(lvgl PRIVATE
${COMMON_FLAGS} ${COMMON_FLAGS}
$<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}>
$<$<CONFIG:RELEASE>: ${DEBUG_FLAGS}> $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}>
$<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}>
$<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}>
) )
@@ -898,7 +898,7 @@ target_include_directories(littlefs SYSTEM PUBLIC ${INCLUDES_FROM_LIBS})
target_compile_options(littlefs PRIVATE target_compile_options(littlefs PRIVATE
${COMMON_FLAGS} ${COMMON_FLAGS}
$<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}>
$<$<CONFIG:RELEASE>: ${DEBUG_FLAGS}> $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}>
$<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}>
$<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}>
) )
@@ -910,7 +910,7 @@ target_include_directories(sunset SYSTEM PUBLIC ${INCLUDES_FROM_LIBS})
target_compile_options(sunset PRIVATE target_compile_options(sunset PRIVATE
${COMMON_FLAGS} ${COMMON_FLAGS}
$<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}>
$<$<CONFIG:RELEASE>: ${DEBUG_FLAGS}> $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}>
$<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}>
$<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}>
) )
@@ -926,7 +926,7 @@ target_compile_options(${EXECUTABLE_NAME} PUBLIC
${COMMON_FLAGS} ${COMMON_FLAGS}
${WARNING_FLAGS} ${WARNING_FLAGS}
$<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}>
$<$<CONFIG:RELEASE>: ${DEBUG_FLAGS}> $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}>
$<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}>
$<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}>
) )
@@ -961,7 +961,7 @@ target_compile_options(${EXECUTABLE_MCUBOOT_NAME} PUBLIC
${COMMON_FLAGS} ${COMMON_FLAGS}
${WARNING_FLAGS} ${WARNING_FLAGS}
$<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}>
$<$<CONFIG:RELEASE>: ${DEBUG_FLAGS}> $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}>
$<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}>
$<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}>
) )
@@ -1004,7 +1004,7 @@ target_compile_options(${EXECUTABLE_RECOVERY_NAME} PUBLIC
${COMMON_FLAGS} ${COMMON_FLAGS}
${WARNING_FLAGS} ${WARNING_FLAGS}
$<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}>
$<$<CONFIG:RELEASE>: ${DEBUG_FLAGS}> $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}>
$<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}>
$<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}>
) )
@@ -1036,7 +1036,7 @@ target_compile_options(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PUBLIC
${COMMON_FLAGS} ${COMMON_FLAGS}
${WARNING_FLAGS} ${WARNING_FLAGS}
$<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}>
$<$<CONFIG:RELEASE>: ${DEBUG_FLAGS}> $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}>
$<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}>
$<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}>
) )
@@ -1075,7 +1075,7 @@ target_compile_options(${EXECUTABLE_RECOVERYLOADER_NAME} PUBLIC
${COMMON_FLAGS} ${COMMON_FLAGS}
${WARNING_FLAGS} ${WARNING_FLAGS}
$<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}>
$<$<CONFIG:RELEASE>: ${DEBUG_FLAGS}> $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}>
$<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}>
$<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}>
) )
@@ -1110,7 +1110,7 @@ target_compile_options(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} PUBLIC
${COMMON_FLAGS} ${COMMON_FLAGS}
${WARNING_FLAGS} ${WARNING_FLAGS}
$<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}>
$<$<CONFIG:RELEASE>: ${DEBUG_FLAGS}> $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}>
$<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}>
$<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}>
) )

View File

@@ -318,7 +318,7 @@ namespace Pinetime {
WeatherFormat weatherFormat = WeatherFormat::Metric; WeatherFormat weatherFormat = WeatherFormat::Metric;
Notification notificationStatus = Notification::On; Notification notificationStatus = Notification::On;
Pinetime::Applications::WatchFace watchFace = Pinetime::Applications::WatchFace::Analog; //Digital Pinetime::Applications::WatchFace watchFace = Pinetime::Applications::WatchFace::Digital;
ChimesOption chimesOption = ChimesOption::None; ChimesOption chimesOption = ChimesOption::None;
PineTimeStyle PTS; PineTimeStyle PTS;

View File

@@ -232,11 +232,6 @@ void DisplayApp::Refresh() {
Messages msg; Messages msg;
if (xQueueReceive(msgQueue, &msg, queueTimeout) == pdTRUE) { if (xQueueReceive(msgQueue, &msg, queueTimeout) == pdTRUE) {
// let's do otaku chimes
uint8_t myHour = dateTimeController.Hours();
uint8_t myChimes = 9-(((int)floor(myHour/2))%6);
switch (msg) { switch (msg) {
case Messages::DimScreen: case Messages::DimScreen:
DimScreen(); DimScreen();
@@ -382,39 +377,7 @@ void DisplayApp::Refresh() {
break; break;
case Messages::Chime: case Messages::Chime:
LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::None); LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::None);
motorController.RunForDuration(35);
// hour chime
// 0 9
// 1 9
// 2 8
// 3 8
// 4 7
// 5 7
// 6 6
// 7 6
// 8 5
// 9 5
// 10 4
// 11 4
// 12 9
// 13 9
// 14 8
// 15 8
// 16 7
// 17 7
// 18 6
// 19 6
// 20 5
// 21 5
// 22 4
// 23 4
// NRF_LOG_INFO("buzzing %d times", myChimes);
for (uint8_t i=0; i<myChimes; i++){
// NRF_LOG_INFO("buzz!");
motorController.RunForDuration(15);
vTaskDelay(1000);
}
break; break;
case Messages::OnChargingEvent: case Messages::OnChargingEvent:
RestoreBrightness(); RestoreBrightness();

View File

@@ -7,12 +7,12 @@
#include "displayapp/screens/Twos.h" #include "displayapp/screens/Twos.h"
#include "displayapp/screens/Tile.h" #include "displayapp/screens/Tile.h"
#include "displayapp/screens/ApplicationList.h" #include "displayapp/screens/ApplicationList.h"
//#include "displayapp/screens/WatchFaceDigital.h" #include "displayapp/screens/WatchFaceDigital.h"
#include "displayapp/screens/WatchFaceAnalog.h" #include "displayapp/screens/WatchFaceAnalog.h"
// #include "displayapp/screens/WatchFaceCasioStyleG7710.h" #include "displayapp/screens/WatchFaceCasioStyleG7710.h"
// #include "displayapp/screens/WatchFaceInfineat.h" #include "displayapp/screens/WatchFaceInfineat.h"
#include "displayapp/screens/WatchFacePineTimeStyle.h" #include "displayapp/screens/WatchFacePineTimeStyle.h"
// #include "displayapp/screens/WatchFaceTerminal.h" #include "displayapp/screens/WatchFaceTerminal.h"
namespace Pinetime { namespace Pinetime {
namespace Applications { namespace Applications {

View File

@@ -46,8 +46,12 @@ namespace Pinetime {
}; };
enum class WatchFace : uint8_t { enum class WatchFace : uint8_t {
Digital,
Analog, Analog,
PineTimeStyle, PineTimeStyle,
Terminal,
Infineat,
CasioStyleG7710,
}; };
template <Apps> template <Apps>
@@ -68,8 +72,12 @@ namespace Pinetime {
static constexpr size_t Count = sizeof...(Ws); static constexpr size_t Count = sizeof...(Ws);
}; };
using UserWatchFaceTypes = WatchFaceTypeList<WatchFace::Analog, using UserWatchFaceTypes = WatchFaceTypeList<WatchFace::Digital,
WatchFace::PineTimeStyle>; WatchFace::Analog,
WatchFace::PineTimeStyle,
WatchFace::Terminal,
WatchFace::Infineat,
WatchFace::CasioStyleG7710>;
static_assert(UserWatchFaceTypes::Count >= 1); static_assert(UserWatchFaceTypes::Count >= 1);
} }

View File

@@ -1,9 +1,11 @@
#if(DEFINED ENABLE_USERAPPS) if(DEFINED ENABLE_USERAPPS)
# set(USERAPP_TYPES ${ENABLE_USERAPPS} CACHE STRING "List of user apps to build into the firmware") set(USERAPP_TYPES ${ENABLE_USERAPPS} CACHE STRING "List of user apps to build into the firmware")
#else () else ()
set(USERAPP_TYPES "Apps::Navigation, Apps::StopWatch, Apps::Timer, Apps::Alarm, Apps::Steps, Apps::HeartRate, Apps::Music, Apps::Twos" CACHE STRING "List of user apps to build into the firmware") set(USERAPP_TYPES "Apps::Navigation, Apps::StopWatch, Apps::Alarm, Apps::Timer, Apps::Steps, Apps::HeartRate, Apps::Music, Apps::Twos" CACHE STRING "List of user apps to build into the firmware")
#Apps::Paint, Apps::Metronome, Apps::Paddle #Apps::Paint,
#endif () #Apps::Metronome,
#Apps::Paddle,
endif ()
add_library(infinitime_apps INTERFACE) add_library(infinitime_apps INTERFACE)
target_sources(infinitime_apps INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/Apps.h") target_sources(infinitime_apps INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/Apps.h")

View File

@@ -1,4 +1,4 @@
set(FONTS jetbrains_mono_42 noto_serif_cjk_20 noto_serif_cjk_15 jetbrains_mono_76 jetbrains_mono_bold_20 set(FONTS jetbrains_mono_42 jetbrains_mono_76 jetbrains_mono_bold_20
jetbrains_mono_extrabold_compressed lv_font_sys_48 jetbrains_mono_extrabold_compressed lv_font_sys_48
open_sans_light fontawesome_weathericons) open_sans_light fontawesome_weathericons)
find_program(LV_FONT_CONV "lv_font_conv" NO_CACHE REQUIRED find_program(LV_FONT_CONV "lv_font_conv" NO_CACHE REQUIRED

View File

@@ -14,36 +14,15 @@
"size": 20, "size": 20,
"patches": ["jetbrains_mono_bold_20.c_zero.patch", "jetbrains_mono_bold_20.c_M.patch"] "patches": ["jetbrains_mono_bold_20.c_zero.patch", "jetbrains_mono_bold_20.c_M.patch"]
}, },
"noto_serif_cjk_20": {
"sources": [
{
"file": "NotoSerifCJKjp-VF.ttf",
"symbols": "丑寅卯辰巳午未申酉戌亥子四五六七八九"
}
],
"bpp": 1,
"size": 20
},
"noto_serif_cjk_15": {
"sources": [
{
"file": "NotoSerifCJKjp-VF.ttf",
"symbols": "四五六七八九"
}
],
"bpp": 1,
"size": 15
},
"jetbrains_mono_42": { "jetbrains_mono_42": {
"sources": [ "sources": [
{ {
"file": "JetBrainsMono-Regular.ttf", "file": "JetBrainsMono-Regular.ttf",
"disabledfile": "Vulf Mono Light Italic.ttf",
"range": "0x20, 0x25, 0x27, 0x2b, 0x2d, 0x30-0x3a, 0x4b-0x4d, 0x61-0x7a" "range": "0x20, 0x25, 0x27, 0x2b, 0x2d, 0x30-0x3a, 0x4b-0x4d, 0x61-0x7a"
} }
], ],
"bpp": 1, "bpp": 1,
"size": 30 "size": 42
}, },
"jetbrains_mono_76": { "jetbrains_mono_76": {
"sources": [ "sources": [

View File

@@ -1,7 +1,7 @@
#include "displayapp/screens/WatchFaceAnalog.h" #include "displayapp/screens/WatchFaceAnalog.h"
#include <cmath> #include <cmath>
#include <lvgl/lvgl.h> #include <lvgl/lvgl.h>
#include <nrf_log.h> // #include <nrf_log.h>
#include "displayapp/screens/BatteryIcon.h" #include "displayapp/screens/BatteryIcon.h"
#include "displayapp/screens/BleIcon.h" #include "displayapp/screens/BleIcon.h"
#include "displayapp/screens/Symbols.h" #include "displayapp/screens/Symbols.h"
@@ -44,41 +44,15 @@ namespace {
.y = CoordinateYRelocate(radius * static_cast<int32_t>(Cosine(angle)) / LV_TRIG_SCALE)}; .y = CoordinateYRelocate(radius * static_cast<int32_t>(Cosine(angle)) / LV_TRIG_SCALE)};
} }
void printKoku(const char* str, uint8_t i, bool big){ int16_t CoordinateYRelocateSundial(int16_t y) {
lv_obj_t* koku = lv_label_create(lv_scr_act(), NULL); return std::abs(y - SunDialVerticalOffset);
lv_label_set_align(koku, LV_LABEL_ALIGN_CENTER);
lv_label_set_text(koku, str);
lv_point_t pt;
if (big) {
pt = CoordinateRelocate(LV_HOR_RES/2-20, i*30);
lv_obj_set_style_local_text_font(koku, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &noto_serif_cjk_20);
} else {
pt = CoordinateRelocate(LV_HOR_RES/2-45, i*30);
lv_obj_set_style_local_text_font(koku, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &noto_serif_cjk_15);
}
lv_obj_align(koku, NULL, LV_ALIGN_CENTER, LV_HOR_RES/2-pt.x, LV_HOR_RES/2-pt.y);
lv_obj_set_style_local_text_color(koku, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
} }
void drawTime(lv_obj_t * obj, uint8_t hour, uint8_t minute, lv_color_t color, uint8_t x, uint8_t y) { lv_point_t CoordinateRelocateSundial(int16_t radius, int16_t angle) {
lv_label_set_align(obj, LV_LABEL_ALIGN_CENTER); return lv_point_t {.x = CoordinateXRelocate(radius * static_cast<int32_t>(Sine(angle)) / LV_TRIG_SCALE),
lv_label_set_text_fmt(obj, "%02d:%02d", hour, minute); .y = CoordinateYRelocateSundial(radius * static_cast<int32_t>(Cosine(angle)) / LV_TRIG_SCALE)};
lv_obj_set_pos(obj, 0, 0);
lv_obj_align(obj, NULL, LV_ALIGN_CENTER, x, y);
lv_obj_set_style_local_text_color(obj, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color);
lv_obj_set_style_local_text_font(obj, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20);
} }
void drawCircle(uint8_t width, bool left, lv_coord_t offset, lv_color_t color){
lv_obj_t * cir = lv_obj_create(lv_scr_act(), nullptr);
lv_obj_set_size(cir, width, width);
if (left)
lv_obj_align(cir, nullptr, LV_ALIGN_IN_LEFT_MID, offset, 0);
else
lv_obj_align(cir, nullptr, LV_ALIGN_IN_RIGHT_MID, offset, 0);
lv_obj_set_style_local_bg_color(cir, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, color);
lv_obj_set_style_local_radius(cir, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
}
} }
WatchFaceAnalog::WatchFaceAnalog(Controllers::DateTime& dateTimeController, WatchFaceAnalog::WatchFaceAnalog(Controllers::DateTime& dateTimeController,
@@ -100,53 +74,29 @@ WatchFaceAnalog::WatchFaceAnalog(Controllers::DateTime& dateTimeController,
location = settingsController.GetLocation(); location = settingsController.GetLocation();
// begin Japanese watch face // begin sundial watch face
if (settingsController.GetClockType() == Controllers::Settings::ClockType::Fuzzy) { if (settingsController.GetClockType() == Controllers::Settings::ClockType::Fuzzy) {
lv_obj_t * nighttime = lv_obj_create(lv_scr_act(), nullptr);
lv_obj_set_size(nighttime, LV_HOR_RES, LV_HOR_RES/2);
lv_obj_set_pos(nighttime, 0, 0);
lv_obj_set_style_local_bg_color(nighttime, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, DARK_GRAY);
lv_obj_set_style_local_radius(nighttime, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, 0);
drawCircle(35, true, 4, DARK_GRAY);
drawCircle(25, true, 33, DARK_GRAY);
drawCircle(35, false, -3, LV_COLOR_BLACK);
drawCircle(25, false, -32, LV_COLOR_BLACK);
major_scales = lv_linemeter_create(lv_scr_act(), nullptr); major_scales = lv_linemeter_create(lv_scr_act(), nullptr);
lv_linemeter_set_scale(major_scales, 360, 13); lv_linemeter_set_scale(major_scales, 165, 11);
lv_linemeter_set_angle_offset(major_scales, 15); lv_linemeter_set_angle_offset(major_scales, 180);
lv_obj_set_size(major_scales, 240, 240); lv_obj_set_size(major_scales, 240, 240);
lv_obj_align(major_scales, nullptr, LV_ALIGN_CENTER, 0, 0); lv_obj_align(major_scales, nullptr, LV_ALIGN_IN_TOP_MID, 0, -LV_HOR_RES/2+SunDialVerticalOffset);
lv_obj_set_style_local_bg_opa(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); lv_obj_set_style_local_bg_opa(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
lv_obj_set_style_local_scale_width(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 50); lv_obj_set_style_local_scale_width(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 40);
lv_obj_set_style_local_scale_end_line_width(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 1); lv_obj_set_style_local_scale_end_line_width(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 1);
lv_obj_set_style_local_scale_end_color(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); lv_obj_set_style_local_scale_end_color(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
axis = lv_arc_create(lv_scr_act(), NULL); one = lv_label_create(lv_scr_act(), NULL);
lv_obj_set_size(axis, 70, 70); lv_label_set_align(one, LV_LABEL_ALIGN_LEFT);
lv_arc_set_bg_angles(axis, 0, 360); lv_label_set_text(one, "I");
lv_arc_set_end_angle(axis, 360); lv_obj_align(one, NULL, LV_ALIGN_IN_TOP_LEFT, 20, SunDialVerticalOffset-20);
lv_obj_align(axis, NULL, LV_ALIGN_CENTER, 0, 0); lv_obj_set_style_local_text_color(one, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_obj_set_style_local_line_width(axis, LV_ARC_PART_INDIC, LV_STATE_DEFAULT, 40);
lv_obj_set_style_local_line_color(axis, LV_ARC_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_WHITE);
const char* kokuZodiac[] = {"","","","","","","","","","","",""}; twelve = lv_label_create(lv_scr_act(), NULL);
const char* kokuNums[] = {"","","","","",""}; lv_label_set_align(twelve, LV_LABEL_ALIGN_RIGHT);
lv_label_set_text(twelve, "XII");
twelve = lv_label_create(lv_scr_act(), nullptr); lv_obj_align(twelve, NULL, LV_ALIGN_IN_TOP_RIGHT, -20, SunDialVerticalOffset-20);
lv_obj_set_style_local_text_color(twelve, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
for (int i=0;i<12;i++) {
printKoku(kokuZodiac[i], i, true);
printKoku(kokuNums[i%6], i, false);
}
lv_style_init(&hour_line_style);
lv_style_set_line_width(&hour_line_style, LV_STATE_DEFAULT, 10);
lv_style_set_line_rounded(&hour_line_style, LV_STATE_DEFAULT, true);
lv_style_init(&hour_line_style_trace);
lv_style_set_line_width(&hour_line_style_trace, LV_STATE_DEFAULT, 10);
lv_style_set_line_rounded(&hour_line_style_trace, LV_STATE_DEFAULT, true);
} else { } else {
minor_scales = lv_linemeter_create(lv_scr_act(), nullptr); minor_scales = lv_linemeter_create(lv_scr_act(), nullptr);
lv_linemeter_set_scale(minor_scales, 300, 51); lv_linemeter_set_scale(minor_scales, 300, 51);
@@ -183,11 +133,6 @@ WatchFaceAnalog::WatchFaceAnalog(Controllers::DateTime& dateTimeController,
lv_label_set_text_static(twelve, "12"); lv_label_set_text_static(twelve, "12");
lv_obj_set_pos(twelve, 110, 10); lv_obj_set_pos(twelve, 110, 10);
lv_obj_set_style_local_text_color(twelve, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_AQUA); lv_obj_set_style_local_text_color(twelve, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_AQUA);
lv_style_init(&hour_line_style);
lv_style_set_line_width(&hour_line_style, LV_STATE_DEFAULT, 7);
lv_style_init(&hour_line_style_trace);
lv_style_set_line_width(&hour_line_style_trace, LV_STATE_DEFAULT, 3);
} }
batteryIcon.Create(lv_scr_act()); batteryIcon.Create(lv_scr_act());
@@ -237,10 +182,16 @@ WatchFaceAnalog::WatchFaceAnalog(Controllers::DateTime& dateTimeController,
lv_style_set_line_rounded(&minute_line_style_trace, LV_STATE_DEFAULT, false); lv_style_set_line_rounded(&minute_line_style_trace, LV_STATE_DEFAULT, false);
lv_obj_add_style(minute_body_trace, LV_LINE_PART_MAIN, &minute_line_style_trace); lv_obj_add_style(minute_body_trace, LV_LINE_PART_MAIN, &minute_line_style_trace);
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_WHITE); lv_style_set_line_color(&hour_line_style, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_style_set_line_rounded(&hour_line_style, LV_STATE_DEFAULT, true);
lv_obj_add_style(hour_body, LV_LINE_PART_MAIN, &hour_line_style); lv_obj_add_style(hour_body, LV_LINE_PART_MAIN, &hour_line_style);
lv_style_init(&hour_line_style_trace);
lv_style_set_line_width(&hour_line_style_trace, LV_STATE_DEFAULT, 3);
lv_style_set_line_color(&hour_line_style_trace, LV_STATE_DEFAULT, LV_COLOR_WHITE); lv_style_set_line_color(&hour_line_style_trace, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_style_set_line_rounded(&hour_line_style_trace, LV_STATE_DEFAULT, false);
lv_obj_add_style(hour_body_trace, LV_LINE_PART_MAIN, &hour_line_style_trace); lv_obj_add_style(hour_body_trace, LV_LINE_PART_MAIN, &hour_line_style_trace);
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
@@ -261,64 +212,69 @@ WatchFaceAnalog::~WatchFaceAnalog() {
} }
void WatchFaceAnalog::drawWatchFaceWadokei(){ void WatchFaceAnalog::drawWatchFaceModeNight(){
uint8_t hour = dateTimeController.Hours(); uint8_t hour = dateTimeController.Hours();
uint8_t minute = dateTimeController.Minutes(); uint8_t minute = dateTimeController.Minutes();
if (sHour != hour || sMinute != minute) { if (sHour != hour || sMinute != minute) {
// sun.setPosition(settings.lat.toFloat(), settings.lon.toFloat(), settings.gmtOffset / 3600);
sun.setPosition((float)location.latitude, (float)location.longitude, location.tzOffset); sun.setPosition((float)location.latitude, (float)location.longitude, location.tzOffset);
//from minutes past midnight //from minutes past midnight
sun.setCurrentDate(dateTimeController.Year(), static_cast<uint8_t>(dateTimeController.Month())+1, dateTimeController.Day()); sun.setCurrentDate(dateTimeController.Year(), static_cast<uint8_t>(dateTimeController.Month())+1, dateTimeController.Day());
sun.setTZOffset(location.tzOffset); sun.setTZOffset(location.tzOffset);
minutesSunrise = sun.calcSunrise(); minutesSunrise = sun.calcSunrise(); //360;
minutesSunset = sun.calcSunset(); minutesSunset = sun.calcSunset(); //1080;
minutesDaytime = (minutesSunset - minutesSunrise); minutesDaytime = (minutesSunset - minutesSunrise);
minutesNighttime = (1440 - minutesDaytime); minutesNighttime = (1440 - minutesDaytime);
minutesBeforeSunset = minutesSunset - (hour * 60 + minute); // i.e.zero degrees minutesBeforeSunset = minutesSunset - (hour * 60 + minute); // i.e.zero degrees
HourLength = 40; // wadokei hand length HourLength = 90; // sundial hand length
int16_t hourAngle=0; int16_t hourAngle;
// auto const hourAngle = ((hour * 15 + minute / 2)+180)%360; //24-hr rotation with 0/24 at the bottom
if(minutesBeforeSunset > minutesDaytime) { if(minutesBeforeSunset > 0 && minutesBeforeSunset < minutesDaytime) { // day (after sunrise)
hourAngle = -180.0 - 180.0 * (minutesBeforeSunset - minutesDaytime) / minutesNighttime; hourAngle = 180.0 * minutesBeforeSunset / minutesDaytime + 90;
} } else { // night (before sunrise or after sunset)
else if(minutesBeforeSunset > 0 ) { lv_style_set_line_color(&hour_line_style, LV_STATE_DEFAULT, DARK_GRAY);
hourAngle = -180.0 * minutesBeforeSunset / minutesDaytime; lv_style_set_line_color(&hour_line_style_trace, LV_STATE_DEFAULT, DARK_GRAY);
} lv_obj_set_style_local_scale_end_color(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, DARK_GRAY);
else { lv_obj_set_style_local_text_color(label_date_day, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, DARK_ORANGE);
hourAngle = -180.0 * minutesBeforeSunset / minutesNighttime; lv_obj_set_style_local_text_color(one, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, DARK_GRAY);
} lv_obj_set_style_local_text_color(twelve, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, DARK_GRAY);
// NRF_LOG_INFO("angle: %d, day: %d, night: %d, bef: %d", if(minutesBeforeSunset > minutesDaytime) { // before sunrise
// hourAngle+90, hourAngle = 180.0 * (minutesBeforeSunset - minutesDaytime) / minutesNighttime + 90;
// minutesDaytime, } else { // after sunset
// minutesNighttime, hourAngle = 180 + 180.0 * minutesBeforeSunset / minutesNighttime + 90;
// minutesBeforeSunset); }
}
/*NRF_LOG_INFO("a: %d, la: %f, lo: %f, ri: %d, se: %d, be: %d",
hourAngle,
(float)location.latitude,
(float)location.longitude,
minutesSunrise,
minutesSunset,
minutesBeforeSunset);*/
sHour = hour; sHour = hour;
sMinute = minute; sMinute = minute;
hour_point_trace[0] = CoordinateRelocate(28, hourAngle+90-66); //axis radius minus line stroke hour_point_trace[0] = CoordinateRelocateSundial(HourLength*.75, hourAngle);
hour_point_trace[1] = CoordinateRelocate(HourLength, hourAngle+90); hour_point_trace[1] = CoordinateRelocateSundial(HourLength, hourAngle);
hour_point[0] = CoordinateRelocate(28, hourAngle+90+66); //axis radius minus line stroke hour_point[0] = CoordinateRelocateSundial(0, hourAngle);
hour_point[1] = CoordinateRelocate(HourLength, hourAngle+90); hour_point[1] = CoordinateRelocateSundial(HourLength*.75, hourAngle);
lv_line_set_points(hour_body, hour_point, 2); lv_line_set_points(hour_body, hour_point, 2);
lv_line_set_points(hour_body_trace, hour_point_trace, 2); lv_line_set_points(hour_body_trace, hour_point_trace, 2);
drawTime(twelve, hour, minute, LV_COLOR_BLACK, 0, 0);
lv_obj_move_foreground(twelve);
} }
} }
void WatchFaceAnalog::UpdateClock() { void WatchFaceAnalog::UpdateClock() {
if (settingsController.GetClockType() == Controllers::Settings::ClockType::Fuzzy) { if (settingsController.GetClockType() == Controllers::Settings::ClockType::Fuzzy) {
drawWatchFaceWadokei(); drawWatchFaceModeNight();
return; return;
} }
@@ -410,14 +366,14 @@ void WatchFaceAnalog::Refresh() {
currentDate = std::chrono::time_point_cast<days>(currentDateTime.Get()); currentDate = std::chrono::time_point_cast<days>(currentDateTime.Get());
if (currentDate.IsUpdated()) { if (currentDate.IsUpdated()) {
if (settingsController.GetClockType() == Controllers::Settings::ClockType::Fuzzy) { if (settingsController.GetClockType() == Controllers::Settings::ClockType::Fuzzy) {
/*char const* MonthsString[] = {"--", "IANUARIUS","FEBRUARIUS","MARTIUS","APRILIS","MARTIUSIUNIUS","QUINTILIS","SEXTILIS","SEPTEMBER","OCTOBER","NOVEMBER","DECEMBER"}; char const* MonthsString[] = {"--", "IANUARIUS","FEBRUARIUS","MARTIUS","APRILIS","MARTIUSIUNIUS","QUINTILIS","SEXTILIS","SEPTEMBER","OCTOBER","NOVEMBER","DECEMBER"};
char const* DaysString[] = {"--", "LUNAE", "MARTIS", "MERCURII", "IOVIS", "VENERIS", "SATURNI", "SOLIS"}; char const* DaysString[] = {"--", "LUNAE", "MARTIS", "MERCURII", "IOVIS", "VENERIS", "SATURNI", "SOLIS"};
char const* RomanNumeralsString[] = {"--", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII"}; char const* RomanNumeralsString[] = {"--", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII"};
lv_label_set_text_fmt(label_date_day, "%s\n%s %s", lv_label_set_text_fmt(label_date_day, "%s\n%s %s",
DaysString[static_cast<uint8_t>(dateTimeController.DayOfWeek())], DaysString[static_cast<uint8_t>(dateTimeController.DayOfWeek())],
RomanNumeralsString[static_cast<uint8_t>(dateTimeController.Day())], RomanNumeralsString[static_cast<uint8_t>(dateTimeController.Day())],
MonthsString[static_cast<uint8_t>(dateTimeController.Month())]);*/ MonthsString[static_cast<uint8_t>(dateTimeController.Month())]);
lv_obj_align(label_date_day, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, -2000); lv_obj_align(label_date_day, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, -20);
} else { } else {
lv_label_set_text_fmt(label_date_day, "%s\n%02i", dateTimeController.DayOfWeekShortToString(), dateTimeController.Day()); lv_label_set_text_fmt(label_date_day, "%s\n%02i", dateTimeController.DayOfWeekShortToString(), dateTimeController.Day());
} }

View File

@@ -52,7 +52,6 @@ namespace Pinetime {
lv_obj_t* large_scales; lv_obj_t* large_scales;
lv_obj_t* one; lv_obj_t* one;
lv_obj_t* twelve; lv_obj_t* twelve;
lv_obj_t* axis;
lv_obj_t* hour_body; lv_obj_t* hour_body;
lv_obj_t* hour_body_trace; lv_obj_t* hour_body_trace;
@@ -71,7 +70,6 @@ namespace Pinetime {
lv_style_t minute_line_style; lv_style_t minute_line_style;
lv_style_t minute_line_style_trace; lv_style_t minute_line_style_trace;
lv_style_t second_line_style; lv_style_t second_line_style;
lv_style_t axis_style;
lv_obj_t* label_date_day; lv_obj_t* label_date_day;
lv_obj_t* plugIcon; lv_obj_t* plugIcon;
@@ -94,7 +92,7 @@ namespace Pinetime {
Controllers::NotificationManager& notificationManager; Controllers::NotificationManager& notificationManager;
Controllers::Settings& settingsController; Controllers::Settings& settingsController;
void drawWatchFaceWadokei(); void drawWatchFaceModeNight();
void UpdateClock(); void UpdateClock();
void SetBatteryIcon(); void SetBatteryIcon();

View File

@@ -0,0 +1,334 @@
#include "displayapp/screens/WatchFaceCasioStyleG7710.h"
#include <lvgl/lvgl.h>
#include <cstdio>
#include "displayapp/screens/BatteryIcon.h"
#include "displayapp/screens/BleIcon.h"
#include "displayapp/screens/NotificationIcon.h"
#include "displayapp/screens/Symbols.h"
#include "components/battery/BatteryController.h"
#include "components/ble/BleController.h"
#include "components/ble/NotificationManager.h"
#include "components/heartrate/HeartRateController.h"
#include "components/motion/MotionController.h"
#include "components/settings/Settings.h"
using namespace Pinetime::Applications::Screens;
WatchFaceCasioStyleG7710::WatchFaceCasioStyleG7710(Controllers::DateTime& dateTimeController,
const Controllers::Battery& batteryController,
const Controllers::Ble& bleController,
Controllers::NotificationManager& notificatioManager,
Controllers::Settings& settingsController,
Controllers::HeartRateController& heartRateController,
Controllers::MotionController& motionController,
Controllers::FS& filesystem)
: currentDateTime {{}},
batteryIcon(false),
dateTimeController {dateTimeController},
batteryController {batteryController},
bleController {bleController},
notificatioManager {notificatioManager},
settingsController {settingsController},
heartRateController {heartRateController},
motionController {motionController} {
lfs_file f = {};
if (filesystem.FileOpen(&f, "/fonts/lv_font_dots_40.bin", LFS_O_RDONLY) >= 0) {
filesystem.FileClose(&f);
font_dot40 = lv_font_load("F:/fonts/lv_font_dots_40.bin");
}
if (filesystem.FileOpen(&f, "/fonts/7segments_40.bin", LFS_O_RDONLY) >= 0) {
filesystem.FileClose(&f);
font_segment40 = lv_font_load("F:/fonts/7segments_40.bin");
}
if (filesystem.FileOpen(&f, "/fonts/7segments_115.bin", LFS_O_RDONLY) >= 0) {
filesystem.FileClose(&f);
font_segment115 = lv_font_load("F:/fonts/7segments_115.bin");
}
label_battery_value = lv_label_create(lv_scr_act(), nullptr);
lv_obj_align(label_battery_value, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, 0, 0);
lv_obj_set_style_local_text_color(label_battery_value, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
lv_label_set_text_static(label_battery_value, "00%");
batteryIcon.Create(lv_scr_act());
batteryIcon.SetColor(color_text);
lv_obj_align(batteryIcon.GetObject(), label_battery_value, LV_ALIGN_OUT_LEFT_MID, -5, 0);
batteryPlug = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(batteryPlug, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
lv_label_set_text_static(batteryPlug, Symbols::plug);
lv_obj_align(batteryPlug, batteryIcon.GetObject(), LV_ALIGN_OUT_LEFT_MID, -5, 0);
bleIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
lv_label_set_text_static(bleIcon, Symbols::bluetooth);
lv_obj_align(bleIcon, batteryPlug, LV_ALIGN_OUT_LEFT_MID, -5, 0);
notificationIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false));
lv_obj_align(notificationIcon, bleIcon, LV_ALIGN_OUT_LEFT_MID, -5, 0);
label_day_of_week = lv_label_create(lv_scr_act(), nullptr);
lv_obj_align(label_day_of_week, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, 64);
lv_obj_set_style_local_text_color(label_day_of_week, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
lv_obj_set_style_local_text_font(label_day_of_week, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_dot40);
lv_label_set_text_static(label_day_of_week, "SUN");
label_week_number = lv_label_create(lv_scr_act(), nullptr);
lv_obj_align(label_week_number, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 5, 22);
lv_obj_set_style_local_text_color(label_week_number, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
lv_obj_set_style_local_text_font(label_week_number, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_dot40);
lv_label_set_text_static(label_week_number, "WK26");
label_day_of_year = lv_label_create(lv_scr_act(), nullptr);
lv_obj_align(label_day_of_year, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 100, 30);
lv_obj_set_style_local_text_color(label_day_of_year, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
lv_obj_set_style_local_text_font(label_day_of_year, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_segment40);
lv_label_set_text_static(label_day_of_year, "181-184");
lv_style_init(&style_line);
lv_style_set_line_width(&style_line, LV_STATE_DEFAULT, 2);
lv_style_set_line_color(&style_line, LV_STATE_DEFAULT, color_text);
lv_style_set_line_rounded(&style_line, LV_STATE_DEFAULT, true);
lv_style_init(&style_border);
lv_style_set_line_width(&style_border, LV_STATE_DEFAULT, 6);
lv_style_set_line_color(&style_border, LV_STATE_DEFAULT, color_text);
lv_style_set_line_rounded(&style_border, LV_STATE_DEFAULT, true);
line_icons = lv_line_create(lv_scr_act(), nullptr);
lv_line_set_points(line_icons, line_icons_points, 3);
lv_obj_add_style(line_icons, LV_LINE_PART_MAIN, &style_line);
lv_obj_align(line_icons, nullptr, LV_ALIGN_IN_TOP_RIGHT, -10, 18);
line_day_of_week_number = lv_line_create(lv_scr_act(), nullptr);
lv_line_set_points(line_day_of_week_number, line_day_of_week_number_points, 4);
lv_obj_add_style(line_day_of_week_number, LV_LINE_PART_MAIN, &style_border);
lv_obj_align(line_day_of_week_number, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 8);
line_day_of_year = lv_line_create(lv_scr_act(), nullptr);
lv_line_set_points(line_day_of_year, line_day_of_year_points, 3);
lv_obj_add_style(line_day_of_year, LV_LINE_PART_MAIN, &style_line);
lv_obj_align(line_day_of_year, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 60);
label_date = lv_label_create(lv_scr_act(), nullptr);
lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 100, 70);
lv_obj_set_style_local_text_color(label_date, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
lv_obj_set_style_local_text_font(label_date, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_segment40);
lv_label_set_text_static(label_date, "6-30");
line_date = lv_line_create(lv_scr_act(), nullptr);
lv_line_set_points(line_date, line_date_points, 3);
lv_obj_add_style(line_date, LV_LINE_PART_MAIN, &style_line);
lv_obj_align(line_date, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 100);
label_time = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
lv_obj_set_style_local_text_font(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_segment115);
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_CENTER, 0, 40);
line_time = lv_line_create(lv_scr_act(), nullptr);
lv_line_set_points(line_time, line_time_points, 3);
lv_obj_add_style(line_time, LV_LINE_PART_MAIN, &style_line);
lv_obj_align(line_time, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, -25);
label_time_ampm = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(label_time_ampm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
lv_label_set_text_static(label_time_ampm, "");
lv_obj_align(label_time_ampm, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 5, -5);
backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_click(backgroundLabel, true);
lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP);
lv_obj_set_size(backgroundLabel, 240, 240);
lv_obj_set_pos(backgroundLabel, 0, 0);
lv_label_set_text_static(backgroundLabel, "");
heartbeatIcon = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_text_static(heartbeatIcon, Symbols::heartBeat);
lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
lv_obj_align(heartbeatIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 5, -2);
heartbeatValue = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(heartbeatValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
lv_label_set_text_static(heartbeatValue, "");
lv_obj_align(heartbeatValue, heartbeatIcon, LV_ALIGN_OUT_RIGHT_MID, 5, 0);
stepValue = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
lv_label_set_text_static(stepValue, "0");
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -5, -2);
stepIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
lv_label_set_text_static(stepIcon, Symbols::shoe);
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
Refresh();
}
WatchFaceCasioStyleG7710::~WatchFaceCasioStyleG7710() {
lv_task_del(taskRefresh);
lv_style_reset(&style_line);
lv_style_reset(&style_border);
if (font_dot40 != nullptr) {
lv_font_free(font_dot40);
}
if (font_segment40 != nullptr) {
lv_font_free(font_segment40);
}
if (font_segment115 != nullptr) {
lv_font_free(font_segment115);
}
lv_obj_clean(lv_scr_act());
}
void WatchFaceCasioStyleG7710::Refresh() {
powerPresent = batteryController.IsPowerPresent();
if (powerPresent.IsUpdated()) {
lv_label_set_text_static(batteryPlug, BatteryIcon::GetPlugIcon(powerPresent.Get()));
}
batteryPercentRemaining = batteryController.PercentRemaining();
if (batteryPercentRemaining.IsUpdated()) {
auto batteryPercent = batteryPercentRemaining.Get();
batteryIcon.SetBatteryPercentage(batteryPercent);
lv_label_set_text_fmt(label_battery_value, "%d%%", batteryPercent);
}
bleState = bleController.IsConnected();
bleRadioEnabled = bleController.IsRadioEnabled();
if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) {
lv_label_set_text_static(bleIcon, BleIcon::GetIcon(bleState.Get()));
}
lv_obj_realign(label_battery_value);
lv_obj_realign(batteryIcon.GetObject());
lv_obj_realign(batteryPlug);
lv_obj_realign(bleIcon);
lv_obj_realign(notificationIcon);
notificationState = notificatioManager.AreNewNotificationsAvailable();
if (notificationState.IsUpdated()) {
lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(notificationState.Get()));
}
currentDateTime = std::chrono::time_point_cast<std::chrono::minutes>(dateTimeController.CurrentDateTime());
if (currentDateTime.IsUpdated()) {
uint8_t hour = dateTimeController.Hours();
uint8_t minute = dateTimeController.Minutes();
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
char ampmChar[2] = "A";
if (hour == 0) {
hour = 12;
} else if (hour == 12) {
ampmChar[0] = 'P';
} else if (hour > 12) {
hour = hour - 12;
ampmChar[0] = 'P';
}
lv_label_set_text(label_time_ampm, ampmChar);
lv_label_set_text_fmt(label_time, "%2d:%02d", hour, minute);
} else {
lv_label_set_text_fmt(label_time, "%02d:%02d", hour, minute);
}
lv_obj_realign(label_time);
currentDate = std::chrono::time_point_cast<days>(currentDateTime.Get());
if (currentDate.IsUpdated()) {
const char* weekNumberFormat = "%V";
uint16_t year = dateTimeController.Year();
Controllers::DateTime::Months month = dateTimeController.Month();
uint8_t day = dateTimeController.Day();
int dayOfYear = dateTimeController.DayOfYear();
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) {
// 24h mode: ddmmyyyy, first DOW=Monday;
lv_label_set_text_fmt(label_date, "%3d-%2d", day, month);
weekNumberFormat = "%V"; // Replaced by the week number of the year (Monday as the first day of the week) as a decimal number
// [01,53]. If the week containing 1 January has four or more days in the new year, then it is considered
// week 1. Otherwise, it is the last week of the previous year, and the next week is week 1. Both January
// 4th and the first Thursday of January are always in week 1. [ tm_year, tm_wday, tm_yday]
} else {
// 12h mode: mmddyyyy, first DOW=Sunday;
lv_label_set_text_fmt(label_date, "%3d-%2d", month, day);
weekNumberFormat = "%U"; // Replaced by the week number of the year as a decimal number [00,53]. The first Sunday of January is the
// first day of week 1; days in the new year before this are in week 0. [ tm_year, tm_wday, tm_yday]
}
time_t ttTime =
std::chrono::system_clock::to_time_t(std::chrono::time_point_cast<std::chrono::system_clock::duration>(currentDateTime.Get()));
tm* tmTime = std::localtime(&ttTime);
// TODO: When we start using C++20, use std::chrono::year::is_leap
int daysInCurrentYear = (year % 4 == 0 && year % 100 != 0) || year % 400 == 0 ? 366 : 365;
uint16_t daysTillEndOfYearNumber = daysInCurrentYear - dayOfYear;
char buffer[8];
strftime(buffer, 8, weekNumberFormat, tmTime);
uint8_t weekNumber = atoi(buffer);
lv_label_set_text_fmt(label_day_of_week, "%s", dateTimeController.DayOfWeekShortToString());
lv_label_set_text_fmt(label_day_of_year, "%3d-%3d", dayOfYear, daysTillEndOfYearNumber);
lv_label_set_text_fmt(label_week_number, "WK%02d", weekNumber);
lv_obj_realign(label_day_of_week);
lv_obj_realign(label_day_of_year);
lv_obj_realign(label_week_number);
lv_obj_realign(label_date);
}
}
heartbeat = heartRateController.HeartRate();
heartbeatRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped;
if (heartbeat.IsUpdated() || heartbeatRunning.IsUpdated()) {
if (heartbeatRunning.Get()) {
lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
lv_label_set_text_fmt(heartbeatValue, "%d", heartbeat.Get());
} else {
lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x1B1B1B));
lv_label_set_text_static(heartbeatValue, "");
}
lv_obj_realign(heartbeatIcon);
lv_obj_realign(heartbeatValue);
}
stepCount = motionController.NbSteps();
if (stepCount.IsUpdated()) {
lv_label_set_text_fmt(stepValue, "%lu", stepCount.Get());
lv_obj_realign(stepValue);
lv_obj_realign(stepIcon);
}
}
bool WatchFaceCasioStyleG7710::IsAvailable(Pinetime::Controllers::FS& filesystem) {
lfs_file file = {};
if (filesystem.FileOpen(&file, "/fonts/lv_font_dots_40.bin", LFS_O_RDONLY) < 0) {
return false;
}
filesystem.FileClose(&file);
if (filesystem.FileOpen(&file, "/fonts/7segments_40.bin", LFS_O_RDONLY) < 0) {
return false;
}
filesystem.FileClose(&file);
if (filesystem.FileOpen(&file, "/fonts/7segments_115.bin", LFS_O_RDONLY) < 0) {
return false;
}
filesystem.FileClose(&file);
return true;
}

View File

@@ -0,0 +1,127 @@
#pragma once
#include <displayapp/screens/BatteryIcon.h>
#include <lvgl/src/lv_core/lv_obj.h>
#include <chrono>
#include <cstdint>
#include <memory>
#include <displayapp/Controllers.h>
#include "displayapp/screens/Screen.h"
#include "components/datetime/DateTimeController.h"
#include "components/ble/BleController.h"
#include "utility/DirtyValue.h"
#include "displayapp/apps/Apps.h"
namespace Pinetime {
namespace Controllers {
class Settings;
class Battery;
class Ble;
class NotificationManager;
class HeartRateController;
class MotionController;
}
namespace Applications {
namespace Screens {
class WatchFaceCasioStyleG7710 : public Screen {
public:
WatchFaceCasioStyleG7710(Controllers::DateTime& dateTimeController,
const Controllers::Battery& batteryController,
const Controllers::Ble& bleController,
Controllers::NotificationManager& notificatioManager,
Controllers::Settings& settingsController,
Controllers::HeartRateController& heartRateController,
Controllers::MotionController& motionController,
Controllers::FS& filesystem);
~WatchFaceCasioStyleG7710() override;
void Refresh() override;
static bool IsAvailable(Pinetime::Controllers::FS& filesystem);
private:
Utility::DirtyValue<uint8_t> batteryPercentRemaining {};
Utility::DirtyValue<bool> powerPresent {};
Utility::DirtyValue<bool> bleState {};
Utility::DirtyValue<bool> bleRadioEnabled {};
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::minutes>> currentDateTime {};
Utility::DirtyValue<uint32_t> stepCount {};
Utility::DirtyValue<uint8_t> heartbeat {};
Utility::DirtyValue<bool> heartbeatRunning {};
Utility::DirtyValue<bool> notificationState {};
using days = std::chrono::duration<int32_t, std::ratio<86400>>; // TODO: days is standard in c++20
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, days>> currentDate;
lv_point_t line_icons_points[3] {{0, 5}, {117, 5}, {122, 0}};
lv_point_t line_day_of_week_number_points[4] {{0, 0}, {100, 0}, {95, 95}, {0, 95}};
lv_point_t line_day_of_year_points[3] {{0, 5}, {130, 5}, {135, 0}};
lv_point_t line_date_points[3] {{0, 5}, {135, 5}, {140, 0}};
lv_point_t line_time_points[3] {{0, 0}, {230, 0}, {235, 5}};
lv_color_t color_text = lv_color_hex(0x98B69A);
lv_style_t style_line;
lv_style_t style_border;
lv_obj_t* label_time;
lv_obj_t* line_time;
lv_obj_t* label_time_ampm;
lv_obj_t* label_date;
lv_obj_t* line_date;
lv_obj_t* label_day_of_week;
lv_obj_t* label_week_number;
lv_obj_t* line_day_of_week_number;
lv_obj_t* label_day_of_year;
lv_obj_t* line_day_of_year;
lv_obj_t* backgroundLabel;
lv_obj_t* bleIcon;
lv_obj_t* batteryPlug;
lv_obj_t* label_battery_value;
lv_obj_t* heartbeatIcon;
lv_obj_t* heartbeatValue;
lv_obj_t* stepIcon;
lv_obj_t* stepValue;
lv_obj_t* notificationIcon;
lv_obj_t* line_icons;
BatteryIcon batteryIcon;
Controllers::DateTime& dateTimeController;
const Controllers::Battery& batteryController;
const Controllers::Ble& bleController;
Controllers::NotificationManager& notificatioManager;
Controllers::Settings& settingsController;
Controllers::HeartRateController& heartRateController;
Controllers::MotionController& motionController;
lv_task_t* taskRefresh;
lv_font_t* font_dot40 = nullptr;
lv_font_t* font_segment40 = nullptr;
lv_font_t* font_segment115 = nullptr;
};
}
template <>
struct WatchFaceTraits<WatchFace::CasioStyleG7710> {
static constexpr WatchFace watchFace = WatchFace::CasioStyleG7710;
static constexpr const char* name = "Casio G7710";
static Screens::Screen* Create(AppControllers& controllers) {
return new Screens::WatchFaceCasioStyleG7710(controllers.dateTimeController,
controllers.batteryController,
controllers.bleController,
controllers.notificationManager,
controllers.settingsController,
controllers.heartRateController,
controllers.motionController,
controllers.filesystem);
};
static bool IsAvailable(Pinetime::Controllers::FS& filesystem) {
return Screens::WatchFaceCasioStyleG7710::IsAvailable(filesystem);
}
};
}
}

View File

@@ -0,0 +1,245 @@
#include "displayapp/screens/WatchFaceDigital.h"
#include <lvgl/lvgl.h>
#include <cstdio>
#include "displayapp/screens/NotificationIcon.h"
#include "displayapp/screens/Symbols.h"
#include "components/battery/BatteryController.h"
#include "components/ble/BleController.h"
#include "components/ble/NotificationManager.h"
#include "components/heartrate/HeartRateController.h"
#include "components/motion/MotionController.h"
#include "components/settings/Settings.h"
using namespace Pinetime::Applications::Screens;
WatchFaceDigital::WatchFaceDigital(Controllers::DateTime& dateTimeController,
const Controllers::Battery& batteryController,
const Controllers::Ble& bleController,
Controllers::NotificationManager& notificationManager,
Controllers::Settings& settingsController,
Controllers::HeartRateController& heartRateController,
Controllers::MotionController& motionController)
: currentDateTime {{}},
dateTimeController {dateTimeController},
notificationManager {notificationManager},
settingsController {settingsController},
heartRateController {heartRateController},
motionController {motionController},
statusIcons(batteryController, bleController) {
sHour = 99;
sMinute = 99;
statusIcons.Create();
notificationIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_LIME);
lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false));
lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
label_date = lv_label_create(lv_scr_act(), nullptr);
lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_CENTER, 0, 60);
lv_obj_set_style_local_text_color(label_date, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999));
label_time = lv_label_create(lv_scr_act(), nullptr);
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, 0);
if (settingsController.GetClockType() == Controllers::Settings::ClockType::Fuzzy) {
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
lv_obj_set_style_local_text_font(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
} else if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, 0);
lv_obj_set_style_local_text_font(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed);
} else {
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
lv_obj_set_style_local_text_font(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed);
}
label_time_ampm = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_text_static(label_time_ampm, "");
lv_obj_align(label_time_ampm, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -30, -55);
heartbeatIcon = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_text_static(heartbeatIcon, Symbols::heartBeat);
lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B));
lv_obj_align(heartbeatIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
heartbeatValue = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(heartbeatValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B));
lv_label_set_text_static(heartbeatValue, "");
lv_obj_align(heartbeatValue, heartbeatIcon, LV_ALIGN_OUT_RIGHT_MID, 5, 0);
stepValue = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7));
lv_label_set_text_static(stepValue, "0");
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
stepIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7));
lv_label_set_text_static(stepIcon, Symbols::shoe);
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
Refresh();
}
WatchFaceDigital::~WatchFaceDigital() {
lv_task_del(taskRefresh);
lv_obj_clean(lv_scr_act());
}
void WatchFaceDigital::Refresh() {
statusIcons.Update();
notificationState = notificationManager.AreNewNotificationsAvailable();
if (notificationState.IsUpdated()) {
lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(notificationState.Get()));
}
currentDateTime = dateTimeController.CurrentDateTime();
if (currentDateTime.IsUpdated()) {
uint8_t hour = dateTimeController.Hours();
uint8_t minute = dateTimeController.Minutes();
if (sHour != hour || sMinute != minute || forceRefresh == true) {
forceRefresh = false;
sHour = hour;
sMinute = minute;
/* Begin difference from WatchFaceDigital*/
if (settingsController.GetClockType() == Controllers::Settings::ClockType::Fuzzy) {
std::string hourStr, timeStr;
hour = hour % 12; // 12 becomes 0, 13 becomes 1
auto sector = minute / 15 + (minute % 15 > 7);
// advance the hour modulo 12 and reset the minutes if we're close to the top
// so we get "quarter to $hour+1" instead of needing "three quarters past $hour"
if (sector > 3) {
hour = (hour + 1) % 12;
sector = 0;
}
timeStr = timeSectors[sector];
if (timeStr.find("%1") != std::string::npos) {
hour = (hour + 1) % 12;
}
//hourStr = std::string("#") + timeAccent + " " + hourNames[hour] + "#";
hourStr = hourNames[hour];
timeStr.replace(timeStr.find("%"), 2, hourStr);
lv_label_set_text(label_time_ampm, "");
lv_label_set_text(label_time, timeStr.c_str());
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_CENTER, 0, -10);
lv_obj_set_style_local_text_font(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
/* End difference from WatchFaceDigital*/
} else if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
char ampmChar[3] = "AM";
if (hour == 0) {
hour = 12;
} else if (hour == 12) {
ampmChar[0] = 'P';
} else if (hour > 12) {
hour = hour - 12;
ampmChar[0] = 'P';
}
lv_label_set_text(label_time_ampm, ampmChar);
lv_label_set_text_fmt(label_time, "%2d:%02d", hour, minute);
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, 0);
lv_obj_set_style_local_text_font(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed);
} else {
lv_label_set_text_fmt(label_time, "%02d:%02d", hour, minute);
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
lv_obj_set_style_local_text_font(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed);
}
lv_obj_realign(label_time);
}
currentDate = std::chrono::time_point_cast<days>(currentDateTime.Get());
if (currentDate.IsUpdated()) {
uint16_t year = dateTimeController.Year();
uint8_t day = dateTimeController.Day();
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) {
lv_label_set_text_fmt(label_date,
"%s %d %s %d",
dateTimeController.DayOfWeekShortToString(),
day,
dateTimeController.MonthShortToString(),
year);
} else {
lv_label_set_text_fmt(label_date,
"%s %s %d %d",
dateTimeController.DayOfWeekShortToString(),
dateTimeController.MonthShortToString(),
day,
year);
}
lv_obj_realign(label_date);
}
}
heartbeat = heartRateController.HeartRate();
heartbeatRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped;
if (heartbeat.IsUpdated() || heartbeatRunning.IsUpdated()) {
if (heartbeatRunning.Get()) {
lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B));
lv_label_set_text_fmt(heartbeatValue, "%d", heartbeat.Get());
} else {
lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x1B1B1B));
lv_label_set_text_static(heartbeatValue, "");
}
lv_obj_realign(heartbeatIcon);
lv_obj_realign(heartbeatValue);
}
stepCount = motionController.NbSteps();
if (stepCount.IsUpdated()) {
lv_label_set_text_fmt(stepValue, "%lu", stepCount.Get());
lv_obj_realign(stepValue);
lv_obj_realign(stepIcon);
}
}
bool WatchFaceDigital::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
if ((event == Pinetime::Applications::TouchEvents::LongTap)) {
Pinetime::Controllers::Settings::ClockType clockType = settingsController.GetClockType();
if (clockType == Pinetime::Controllers::Settings::ClockType::Fuzzy) {
settingsController.SetClockType(Pinetime::Controllers::Settings::ClockType::H12);
} else {
settingsController.SetClockType(Pinetime::Controllers::Settings::ClockType::Fuzzy);
}
settingsController.SaveSettings();
forceRefresh=true;
WatchFaceDigital::Refresh();
return true;
}
return false;
}
/* Inspired by XFCE4-panel's fuzzy clock.
*
* https://salsa.debian.org/xfce-team/desktop/xfce4-panel/-/blob/debian/master/plugins/clock/clock-fuzzy.c
*
* Strings contain either a `%0` or a `%1`, indicating the position of
* the `hour` or `hour+1`, respectively.
*/
const char* WatchFaceDigital::timeSectors[] = {
"%0\no'clock",
"quarter\npast\n%0",
"half past\n%0",
"quarter\nto %1",
};
const char* WatchFaceDigital::hourNames[] = {
"twelve",
"one",
"two",
"three",
"four",
"five",
"six",
"seven",
"eight",
"nine",
"ten",
"eleven",
};

View File

@@ -0,0 +1,101 @@
#pragma once
#include <lvgl/src/lv_core/lv_obj.h>
#include <chrono>
#include <cstdint>
#include <memory>
#include "displayapp/screens/Screen.h"
#include "components/datetime/DateTimeController.h"
#include "components/ble/BleController.h"
#include "displayapp/widgets/StatusIcons.h"
#include "utility/DirtyValue.h"
#include "displayapp/apps/Apps.h"
namespace Pinetime {
namespace Controllers {
class Settings;
class Battery;
class Ble;
class NotificationManager;
class HeartRateController;
class MotionController;
}
namespace Applications {
namespace Screens {
class WatchFaceDigital : public Screen {
public:
WatchFaceDigital(Controllers::DateTime& dateTimeController,
const Controllers::Battery& batteryController,
const Controllers::Ble& bleController,
Controllers::NotificationManager& notificationManager,
Controllers::Settings& settingsController,
Controllers::HeartRateController& heartRateController,
Controllers::MotionController& motionController);
~WatchFaceDigital() override;
bool OnTouchEvent(TouchEvents event) override;
void Refresh() override;
private:
uint8_t sHour, sMinute;
uint8_t displayedHour = -1;
uint8_t displayedMinute = -1;
static const char* timeSectors[4];
static const char* hourNames[12];
Utility::DirtyValue<uint8_t> batteryPercentRemaining {};
Utility::DirtyValue<bool> powerPresent {};
Utility::DirtyValue<bool> bleState {};
Utility::DirtyValue<bool> bleRadioEnabled {};
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>> currentDateTime;
Utility::DirtyValue<uint32_t> stepCount {};
Utility::DirtyValue<uint8_t> heartbeat {};
Utility::DirtyValue<bool> heartbeatRunning {};
Utility::DirtyValue<bool> notificationState {};
using days = std::chrono::duration<int32_t, std::ratio<86400>>; // TODO: days is standard in c++20
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, days>> currentDate;
lv_obj_t* label_time;
lv_obj_t* label_time_ampm;
lv_obj_t* label_date;
lv_obj_t* heartbeatIcon;
lv_obj_t* heartbeatValue;
lv_obj_t* stepIcon;
lv_obj_t* stepValue;
lv_obj_t* notificationIcon;
Controllers::DateTime& dateTimeController;
Controllers::NotificationManager& notificationManager;
Controllers::Settings& settingsController;
Controllers::HeartRateController& heartRateController;
Controllers::MotionController& motionController;
lv_task_t* taskRefresh;
bool forceRefresh=false;
Widgets::StatusIcons statusIcons;
};
}
template <>
struct WatchFaceTraits<WatchFace::Digital> {
static constexpr WatchFace watchFace = WatchFace::Digital;
static constexpr const char* name = "Digital face";
static Screens::Screen* Create(AppControllers& controllers) {
return new Screens::WatchFaceDigital(controllers.dateTimeController,
controllers.batteryController,
controllers.bleController,
controllers.notificationManager,
controllers.settingsController,
controllers.heartRateController,
controllers.motionController);
};
static bool IsAvailable(Pinetime::Controllers::FS& /*filesystem*/) {
return true;
}
};
}
}

View File

@@ -0,0 +1,508 @@
#include "displayapp/screens/WatchFaceInfineat.h"
#include <lvgl/lvgl.h>
#include <cstdio>
#include "displayapp/screens/Symbols.h"
#include "displayapp/screens/BleIcon.h"
#include "components/settings/Settings.h"
#include "components/battery/BatteryController.h"
#include "components/ble/BleController.h"
#include "components/ble/NotificationManager.h"
#include "components/motion/MotionController.h"
using namespace Pinetime::Applications::Screens;
namespace {
void event_handler(lv_obj_t* obj, lv_event_t event) {
auto* screen = static_cast<WatchFaceInfineat*>(obj->user_data);
screen->UpdateSelected(obj, event);
}
enum class colors {
orange,
blue,
green,
rainbow,
gray,
nordBlue,
nordGreen,
};
constexpr int nColors = 7; // must match number of colors in InfineatColors
constexpr int nLines = WatchFaceInfineat::nLines;
constexpr std::array<lv_color_t, nLines> orangeColors = {LV_COLOR_MAKE(0xfd, 0x87, 0x2b),
LV_COLOR_MAKE(0xdb, 0x33, 0x16),
LV_COLOR_MAKE(0x6f, 0x10, 0x00),
LV_COLOR_MAKE(0xfd, 0x7a, 0x0a),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xe8, 0x51, 0x02),
LV_COLOR_MAKE(0xea, 0x1c, 0x00)};
constexpr std::array<lv_color_t, nLines> blueColors = {LV_COLOR_MAKE(0xe7, 0xf8, 0xff),
LV_COLOR_MAKE(0x22, 0x32, 0xd0),
LV_COLOR_MAKE(0x18, 0x2a, 0x8b),
LV_COLOR_MAKE(0xe7, 0xf8, 0xff),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0x59, 0x91, 0xff),
LV_COLOR_MAKE(0x16, 0x36, 0xff)};
constexpr std::array<lv_color_t, nLines> greenColors = {LV_COLOR_MAKE(0xb8, 0xff, 0x9b),
LV_COLOR_MAKE(0x08, 0x86, 0x08),
LV_COLOR_MAKE(0x00, 0x4a, 0x00),
LV_COLOR_MAKE(0xb8, 0xff, 0x9b),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0x62, 0xd5, 0x15),
LV_COLOR_MAKE(0x00, 0x74, 0x00)};
constexpr std::array<lv_color_t, nLines> rainbowColors = {LV_COLOR_MAKE(0x2d, 0xa4, 0x00),
LV_COLOR_MAKE(0xac, 0x09, 0xc4),
LV_COLOR_MAKE(0xfe, 0x03, 0x03),
LV_COLOR_MAKE(0x0d, 0x57, 0xff),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xe0, 0xb9, 0x00),
LV_COLOR_MAKE(0xe8, 0x51, 0x02)};
constexpr std::array<lv_color_t, nLines> grayColors = {LV_COLOR_MAKE(0xee, 0xee, 0xee),
LV_COLOR_MAKE(0x98, 0x95, 0x9b),
LV_COLOR_MAKE(0x19, 0x19, 0x19),
LV_COLOR_MAKE(0xee, 0xee, 0xee),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0x91, 0x91, 0x91),
LV_COLOR_MAKE(0x3a, 0x3a, 0x3a)};
constexpr std::array<lv_color_t, nLines> nordBlueColors = {LV_COLOR_MAKE(0xc3, 0xda, 0xf2),
LV_COLOR_MAKE(0x4d, 0x78, 0xce),
LV_COLOR_MAKE(0x15, 0x34, 0x51),
LV_COLOR_MAKE(0xc3, 0xda, 0xf2),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0x5d, 0x8a, 0xd2),
LV_COLOR_MAKE(0x21, 0x51, 0x8a)};
constexpr std::array<lv_color_t, nLines> nordGreenColors = {LV_COLOR_MAKE(0xd5, 0xf0, 0xe9),
LV_COLOR_MAKE(0x23, 0x83, 0x73),
LV_COLOR_MAKE(0x1d, 0x41, 0x3f),
LV_COLOR_MAKE(0xd5, 0xf0, 0xe9),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0x2f, 0xb8, 0xa2),
LV_COLOR_MAKE(0x11, 0x70, 0x5a)};
constexpr const std::array<lv_color_t, nLines>* returnColor(colors color) {
if (color == colors::orange) {
return &orangeColors;
}
if (color == colors::blue) {
return &blueColors;
}
if (color == colors::green) {
return &greenColors;
}
if (color == colors::rainbow) {
return &rainbowColors;
}
if (color == colors::gray) {
return &grayColors;
}
if (color == colors::nordBlue) {
return &nordBlueColors;
}
return &nordGreenColors;
}
}
WatchFaceInfineat::WatchFaceInfineat(Controllers::DateTime& dateTimeController,
const Controllers::Battery& batteryController,
const Controllers::Ble& bleController,
Controllers::NotificationManager& notificationManager,
Controllers::Settings& settingsController,
Controllers::MotionController& motionController,
Controllers::FS& filesystem)
: currentDateTime {{}},
dateTimeController {dateTimeController},
batteryController {batteryController},
bleController {bleController},
notificationManager {notificationManager},
settingsController {settingsController},
motionController {motionController} {
lfs_file f = {};
if (filesystem.FileOpen(&f, "/fonts/teko.bin", LFS_O_RDONLY) >= 0) {
filesystem.FileClose(&f);
font_teko = lv_font_load("F:/fonts/teko.bin");
}
if (filesystem.FileOpen(&f, "/fonts/bebas.bin", LFS_O_RDONLY) >= 0) {
filesystem.FileClose(&f);
font_bebas = lv_font_load("F:/fonts/bebas.bin");
}
// Side Cover
static constexpr lv_point_t linePoints[nLines][2] = {{{30, 25}, {68, -8}},
{{26, 167}, {43, 216}},
{{27, 40}, {27, 196}},
{{12, 182}, {65, 249}},
{{17, 99}, {17, 144}},
{{14, 81}, {40, 127}},
{{14, 163}, {40, 118}},
{{-20, 124}, {25, -11}},
{{-29, 89}, {27, 254}}};
static constexpr lv_style_int_t lineWidths[nLines] = {18, 15, 14, 22, 20, 18, 18, 52, 48};
const std::array<lv_color_t, nLines>* colors = returnColor(static_cast<enum colors>(settingsController.GetInfineatColorIndex()));
for (int i = 0; i < nLines; i++) {
lines[i] = lv_line_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_line_width(lines[i], LV_LINE_PART_MAIN, LV_STATE_DEFAULT, lineWidths[i]);
lv_color_t color = (*colors)[i];
lv_obj_set_style_local_line_color(lines[i], LV_LINE_PART_MAIN, LV_STATE_DEFAULT, color);
lv_line_set_points(lines[i], linePoints[i], 2);
}
logoPine = lv_img_create(lv_scr_act(), nullptr);
lv_img_set_src(logoPine, "F:/images/pine_small.bin");
lv_obj_set_pos(logoPine, 15, 106);
lineBattery = lv_line_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_line_width(lineBattery, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 24);
lv_obj_set_style_local_line_color(lineBattery, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, (*colors)[4]);
lv_obj_set_style_local_line_opa(lineBattery, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 190);
lineBatteryPoints[0] = {27, 105};
lineBatteryPoints[1] = {27, 106};
lv_line_set_points(lineBattery, lineBatteryPoints, 2);
lv_obj_move_foreground(lineBattery);
notificationIcon = lv_obj_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_bg_color(notificationIcon, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, (*colors)[7]);
lv_obj_set_style_local_radius(notificationIcon, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
lv_obj_set_size(notificationIcon, 13, 13);
lv_obj_set_hidden(notificationIcon, true);
if (!settingsController.GetInfineatShowSideCover()) {
ToggleBatteryIndicatorColor(false);
for (auto& line : lines) {
lv_obj_set_hidden(line, true);
}
}
timeContainer = lv_obj_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_bg_opa(timeContainer, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
lv_obj_set_size(timeContainer, 185, 185);
lv_obj_align(timeContainer, lv_scr_act(), LV_ALIGN_CENTER, 0, -10);
labelHour = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_text_static(labelHour, "01");
lv_obj_set_style_local_text_font(labelHour, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_bebas);
lv_obj_align(labelHour, timeContainer, LV_ALIGN_IN_TOP_MID, 0, 0);
labelMinutes = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(labelMinutes, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_bebas);
lv_label_set_text_static(labelMinutes, "00");
lv_obj_align(labelMinutes, timeContainer, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
labelTimeAmPm = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(labelTimeAmPm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_teko);
lv_label_set_text_static(labelTimeAmPm, "");
lv_obj_align(labelTimeAmPm, timeContainer, LV_ALIGN_OUT_RIGHT_TOP, 0, 15);
dateContainer = lv_obj_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_bg_opa(dateContainer, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
lv_obj_set_size(dateContainer, 60, 30);
lv_obj_align(dateContainer, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, 5);
static constexpr lv_color_t grayColor = LV_COLOR_MAKE(0x99, 0x99, 0x99);
labelDate = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(labelDate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, grayColor);
lv_obj_set_style_local_text_font(labelDate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_teko);
lv_obj_align(labelDate, dateContainer, LV_ALIGN_IN_TOP_MID, 0, 0);
lv_label_set_text_static(labelDate, "Mon 01");
bleIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, grayColor);
lv_label_set_text_static(bleIcon, Symbols::bluetooth);
lv_obj_align(bleIcon, dateContainer, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
stepValue = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, grayColor);
lv_obj_set_style_local_text_font(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_teko);
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 10, 0);
lv_label_set_text_static(stepValue, "0");
stepIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, grayColor);
lv_label_set_text_static(stepIcon, Symbols::shoe);
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
// Setting buttons
btnClose = lv_btn_create(lv_scr_act(), nullptr);
btnClose->user_data = this;
lv_obj_set_size(btnClose, 60, 60);
lv_obj_align(btnClose, lv_scr_act(), LV_ALIGN_CENTER, 0, -80);
lv_obj_set_style_local_bg_opa(btnClose, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_70);
lv_obj_t* lblClose = lv_label_create(btnClose, nullptr);
lv_label_set_text_static(lblClose, "X");
lv_obj_set_event_cb(btnClose, event_handler);
lv_obj_set_hidden(btnClose, true);
btnNextColor = lv_btn_create(lv_scr_act(), nullptr);
btnNextColor->user_data = this;
lv_obj_set_size(btnNextColor, 60, 60);
lv_obj_align(btnNextColor, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -15, 0);
lv_obj_set_style_local_bg_opa(btnNextColor, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_70);
lv_obj_t* lblNextColor = lv_label_create(btnNextColor, nullptr);
lv_label_set_text_static(lblNextColor, ">");
lv_obj_set_event_cb(btnNextColor, event_handler);
lv_obj_set_hidden(btnNextColor, true);
btnPrevColor = lv_btn_create(lv_scr_act(), nullptr);
btnPrevColor->user_data = this;
lv_obj_set_size(btnPrevColor, 60, 60);
lv_obj_align(btnPrevColor, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 15, 0);
lv_obj_set_style_local_bg_opa(btnPrevColor, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_70);
lv_obj_t* lblPrevColor = lv_label_create(btnPrevColor, nullptr);
lv_label_set_text_static(lblPrevColor, "<");
lv_obj_set_event_cb(btnPrevColor, event_handler);
lv_obj_set_hidden(btnPrevColor, true);
btnToggleCover = lv_btn_create(lv_scr_act(), nullptr);
btnToggleCover->user_data = this;
lv_obj_set_size(btnToggleCover, 60, 60);
lv_obj_align(btnToggleCover, lv_scr_act(), LV_ALIGN_CENTER, 0, 80);
lv_obj_set_style_local_bg_opa(btnToggleCover, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_70);
const char* labelToggle = settingsController.GetInfineatShowSideCover() ? "ON" : "OFF";
lblToggle = lv_label_create(btnToggleCover, nullptr);
lv_label_set_text_static(lblToggle, labelToggle);
lv_obj_set_event_cb(btnToggleCover, event_handler);
lv_obj_set_hidden(btnToggleCover, true);
// Button to access the settings
btnSettings = lv_btn_create(lv_scr_act(), nullptr);
btnSettings->user_data = this;
lv_obj_set_size(btnSettings, 150, 150);
lv_obj_align(btnSettings, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
lv_obj_set_style_local_radius(btnSettings, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 30);
lv_obj_set_style_local_bg_opa(btnSettings, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_70);
lv_obj_set_event_cb(btnSettings, event_handler);
labelBtnSettings = lv_label_create(btnSettings, nullptr);
lv_obj_set_style_local_text_font(labelBtnSettings, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &lv_font_sys_48);
lv_label_set_text_static(labelBtnSettings, Symbols::settings);
lv_obj_set_hidden(btnSettings, true);
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
Refresh();
}
WatchFaceInfineat::~WatchFaceInfineat() {
lv_task_del(taskRefresh);
if (font_bebas != nullptr) {
lv_font_free(font_bebas);
}
if (font_teko != nullptr) {
lv_font_free(font_teko);
}
lv_obj_clean(lv_scr_act());
}
bool WatchFaceInfineat::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
if ((event == Pinetime::Applications::TouchEvents::LongTap) && lv_obj_get_hidden(btnSettings)) {
lv_obj_set_hidden(btnSettings, false);
savedTick = lv_tick_get();
return true;
}
// Prevent screen from sleeping when double tapping with settings on
if ((event == Pinetime::Applications::TouchEvents::DoubleTap) && !lv_obj_get_hidden(btnClose)) {
return true;
}
return false;
}
void WatchFaceInfineat::CloseMenu() {
settingsController.SaveSettings();
lv_obj_set_hidden(btnClose, true);
lv_obj_set_hidden(btnNextColor, true);
lv_obj_set_hidden(btnPrevColor, true);
lv_obj_set_hidden(btnToggleCover, true);
}
bool WatchFaceInfineat::OnButtonPushed() {
if (!lv_obj_get_hidden(btnClose)) {
CloseMenu();
return true;
}
return false;
}
void WatchFaceInfineat::UpdateSelected(lv_obj_t* object, lv_event_t event) {
if (event == LV_EVENT_CLICKED) {
bool showSideCover = settingsController.GetInfineatShowSideCover();
int colorIndex = settingsController.GetInfineatColorIndex();
if (object == btnSettings) {
lv_obj_set_hidden(btnSettings, true);
lv_obj_set_hidden(btnClose, false);
lv_obj_set_hidden(btnNextColor, !showSideCover);
lv_obj_set_hidden(btnPrevColor, !showSideCover);
lv_obj_set_hidden(btnToggleCover, false);
}
if (object == btnClose) {
CloseMenu();
}
if (object == btnToggleCover) {
settingsController.SetInfineatShowSideCover(!showSideCover);
ToggleBatteryIndicatorColor(!showSideCover);
for (auto& line : lines) {
lv_obj_set_hidden(line, showSideCover);
}
lv_obj_set_hidden(btnNextColor, showSideCover);
lv_obj_set_hidden(btnPrevColor, showSideCover);
const char* labelToggle = showSideCover ? "OFF" : "ON";
lv_label_set_text_static(lblToggle, labelToggle);
}
if (object == btnNextColor) {
colorIndex = (colorIndex + 1) % nColors;
settingsController.SetInfineatColorIndex(colorIndex);
}
if (object == btnPrevColor) {
colorIndex -= 1;
if (colorIndex < 0)
colorIndex = nColors - 1;
settingsController.SetInfineatColorIndex(colorIndex);
}
if (object == btnNextColor || object == btnPrevColor) {
const std::array<lv_color_t, nLines>* colors = returnColor(static_cast<enum colors>(settingsController.GetInfineatColorIndex()));
for (int i = 0; i < nLines; i++) {
lv_color_t color = (*colors)[i];
lv_obj_set_style_local_line_color(lines[i], LV_LINE_PART_MAIN, LV_STATE_DEFAULT, color);
}
lv_obj_set_style_local_line_color(lineBattery, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, (*colors)[4]);
lv_obj_set_style_local_bg_color(notificationIcon, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, (*colors)[7]);
}
}
}
void WatchFaceInfineat::Refresh() {
notificationState = notificationManager.AreNewNotificationsAvailable();
if (notificationState.IsUpdated()) {
lv_obj_set_hidden(notificationIcon, !notificationState.Get());
lv_obj_align(notificationIcon, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, 0, 0);
}
currentDateTime = std::chrono::time_point_cast<std::chrono::minutes>(dateTimeController.CurrentDateTime());
if (currentDateTime.IsUpdated()) {
uint8_t hour = dateTimeController.Hours();
uint8_t minute = dateTimeController.Minutes();
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
char ampmChar[3] = "AM";
if (hour == 0) {
hour = 12;
} else if (hour == 12) {
ampmChar[0] = 'P';
} else if (hour > 12) {
hour = hour - 12;
ampmChar[0] = 'P';
}
lv_label_set_text(labelTimeAmPm, ampmChar);
}
lv_label_set_text_fmt(labelHour, "%02d", hour);
lv_label_set_text_fmt(labelMinutes, "%02d", minute);
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
lv_obj_align(labelTimeAmPm, timeContainer, LV_ALIGN_OUT_RIGHT_TOP, 0, 10);
lv_obj_align(labelHour, timeContainer, LV_ALIGN_IN_TOP_MID, 0, 5);
lv_obj_align(labelMinutes, timeContainer, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
}
currentDate = std::chrono::time_point_cast<days>(currentDateTime.Get());
if (currentDate.IsUpdated()) {
uint8_t day = dateTimeController.Day();
lv_label_set_text_fmt(labelDate, "%s %02d", dateTimeController.DayOfWeekShortToStringLow(), day);
lv_obj_realign(labelDate);
}
}
batteryPercentRemaining = batteryController.PercentRemaining();
isCharging = batteryController.IsCharging();
if (batteryController.IsCharging()) { // Charging battery animation
chargingBatteryPercent += 1;
if (chargingBatteryPercent > 100) {
chargingBatteryPercent = batteryPercentRemaining.Get();
}
SetBatteryLevel(chargingBatteryPercent);
} else if (isCharging.IsUpdated() || batteryPercentRemaining.IsUpdated()) {
chargingBatteryPercent = batteryPercentRemaining.Get();
SetBatteryLevel(chargingBatteryPercent);
}
bleState = bleController.IsConnected();
bleRadioEnabled = bleController.IsRadioEnabled();
if (bleState.IsUpdated()) {
lv_label_set_text_static(bleIcon, BleIcon::GetIcon(bleState.Get()));
lv_obj_align(bleIcon, dateContainer, LV_ALIGN_OUT_BOTTOM_MID, 0, 3);
}
stepCount = motionController.NbSteps();
if (stepCount.IsUpdated()) {
lv_label_set_text_fmt(stepValue, "%lu", stepCount.Get());
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 10, 0);
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
}
if (!lv_obj_get_hidden(btnSettings)) {
if ((savedTick > 0) && (lv_tick_get() - savedTick > 3000)) {
lv_obj_set_hidden(btnSettings, true);
savedTick = 0;
}
}
}
void WatchFaceInfineat::SetBatteryLevel(uint8_t batteryPercent) {
// starting point (y) + Pine64 logo height * (100 - batteryPercent) / 100
lineBatteryPoints[1] = {27, static_cast<lv_coord_t>(105 + 32 * (100 - batteryPercent) / 100)};
lv_line_set_points(lineBattery, lineBatteryPoints, 2);
}
void WatchFaceInfineat::ToggleBatteryIndicatorColor(bool showSideCover) {
if (!showSideCover) { // make indicator and notification icon color white
lv_obj_set_style_local_image_recolor_opa(logoPine, LV_IMG_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_100);
lv_obj_set_style_local_image_recolor(logoPine, LV_IMG_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_obj_set_style_local_line_color(lineBattery, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_obj_set_style_local_bg_color(notificationIcon, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
} else {
lv_obj_set_style_local_image_recolor_opa(logoPine, LV_IMG_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_0);
const std::array<lv_color_t, nLines>* colors = returnColor(static_cast<enum colors>(settingsController.GetInfineatColorIndex()));
lv_obj_set_style_local_line_color(lineBattery, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, (*colors)[4]);
lv_obj_set_style_local_bg_color(notificationIcon, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, (*colors)[7]);
}
}
bool WatchFaceInfineat::IsAvailable(Pinetime::Controllers::FS& filesystem) {
lfs_file file = {};
if (filesystem.FileOpen(&file, "/fonts/teko.bin", LFS_O_RDONLY) < 0) {
return false;
}
filesystem.FileClose(&file);
if (filesystem.FileOpen(&file, "/fonts/bebas.bin", LFS_O_RDONLY) < 0) {
return false;
}
filesystem.FileClose(&file);
if (filesystem.FileOpen(&file, "/images/pine_small.bin", LFS_O_RDONLY) < 0) {
return false;
}
filesystem.FileClose(&file);
return true;
}

View File

@@ -0,0 +1,124 @@
#pragma once
#include <lvgl/lvgl.h>
#include <chrono>
#include <cstdint>
#include <memory>
#include <displayapp/Controllers.h>
#include "displayapp/screens/Screen.h"
#include "components/datetime/DateTimeController.h"
#include "utility/DirtyValue.h"
#include "displayapp/apps/Apps.h"
namespace Pinetime {
namespace Controllers {
class Settings;
class Battery;
class Ble;
class NotificationManager;
class MotionController;
}
namespace Applications {
namespace Screens {
class WatchFaceInfineat : public Screen {
public:
static constexpr int nLines = 9;
WatchFaceInfineat(Controllers::DateTime& dateTimeController,
const Controllers::Battery& batteryController,
const Controllers::Ble& bleController,
Controllers::NotificationManager& notificationManager,
Controllers::Settings& settingsController,
Controllers::MotionController& motionController,
Controllers::FS& fs);
~WatchFaceInfineat() override;
bool OnTouchEvent(TouchEvents event) override;
bool OnButtonPushed() override;
void UpdateSelected(lv_obj_t* object, lv_event_t event);
void CloseMenu();
void Refresh() override;
static bool IsAvailable(Pinetime::Controllers::FS& filesystem);
private:
uint32_t savedTick = 0;
uint8_t chargingBatteryPercent = 101; // not a mistake ;)
Utility::DirtyValue<uint8_t> batteryPercentRemaining {};
Utility::DirtyValue<bool> isCharging {};
Utility::DirtyValue<bool> bleState {};
Utility::DirtyValue<bool> bleRadioEnabled {};
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::minutes>> currentDateTime {};
Utility::DirtyValue<uint32_t> stepCount {};
Utility::DirtyValue<bool> notificationState {};
using days = std::chrono::duration<int32_t, std::ratio<86400>>; // TODO: days is standard in c++20
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, days>> currentDate;
// Lines making up the side cover
lv_obj_t* lineBattery;
lv_point_t lineBatteryPoints[2];
lv_obj_t* logoPine;
lv_obj_t* timeContainer;
lv_obj_t* labelHour;
lv_obj_t* labelMinutes;
lv_obj_t* labelTimeAmPm;
lv_obj_t* dateContainer;
lv_obj_t* labelDate;
lv_obj_t* bleIcon;
lv_obj_t* stepIcon;
lv_obj_t* stepValue;
lv_obj_t* notificationIcon;
lv_obj_t* btnClose;
lv_obj_t* btnNextColor;
lv_obj_t* btnToggleCover;
lv_obj_t* btnPrevColor;
lv_obj_t* btnSettings;
lv_obj_t* labelBtnSettings;
lv_obj_t* lblToggle;
lv_obj_t* lines[nLines];
Controllers::DateTime& dateTimeController;
const Controllers::Battery& batteryController;
const Controllers::Ble& bleController;
Controllers::NotificationManager& notificationManager;
Controllers::Settings& settingsController;
Controllers::MotionController& motionController;
void SetBatteryLevel(uint8_t batteryPercent);
void ToggleBatteryIndicatorColor(bool showSideCover);
lv_task_t* taskRefresh;
lv_font_t* font_teko = nullptr;
lv_font_t* font_bebas = nullptr;
};
}
template <>
struct WatchFaceTraits<WatchFace::Infineat> {
static constexpr WatchFace watchFace = WatchFace::Infineat;
static constexpr const char* name = "Infineat face";
static Screens::Screen* Create(AppControllers& controllers) {
return new Screens::WatchFaceInfineat(controllers.dateTimeController,
controllers.batteryController,
controllers.bleController,
controllers.notificationManager,
controllers.settingsController,
controllers.motionController,
controllers.filesystem);
};
static bool IsAvailable(Pinetime::Controllers::FS& filesystem) {
return Screens::WatchFaceInfineat::IsAvailable(filesystem);
}
};
}
}

View File

@@ -0,0 +1,151 @@
#include <lvgl/lvgl.h>
#include "displayapp/screens/WatchFaceTerminal.h"
#include "displayapp/screens/BatteryIcon.h"
#include "displayapp/screens/NotificationIcon.h"
#include "displayapp/screens/Symbols.h"
#include "components/battery/BatteryController.h"
#include "components/ble/BleController.h"
#include "components/ble/NotificationManager.h"
#include "components/heartrate/HeartRateController.h"
#include "components/motion/MotionController.h"
#include "components/settings/Settings.h"
using namespace Pinetime::Applications::Screens;
WatchFaceTerminal::WatchFaceTerminal(Controllers::DateTime& dateTimeController,
const Controllers::Battery& batteryController,
const Controllers::Ble& bleController,
Controllers::NotificationManager& notificationManager,
Controllers::Settings& settingsController,
Controllers::HeartRateController& heartRateController,
Controllers::MotionController& motionController)
: currentDateTime {{}},
dateTimeController {dateTimeController},
batteryController {batteryController},
bleController {bleController},
notificationManager {notificationManager},
settingsController {settingsController},
heartRateController {heartRateController},
motionController {motionController} {
batteryValue = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_recolor(batteryValue, true);
lv_obj_align(batteryValue, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -20);
connectState = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_recolor(connectState, true);
lv_obj_align(connectState, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 40);
notificationIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_LEFT_MID, 0, -100);
label_date = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_recolor(label_date, true);
lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -40);
label_prompt_1 = lv_label_create(lv_scr_act(), nullptr);
lv_obj_align(label_prompt_1, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -80);
lv_label_set_text_static(label_prompt_1, "user@watch:~ $ now");
label_prompt_2 = lv_label_create(lv_scr_act(), nullptr);
lv_obj_align(label_prompt_2, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 60);
lv_label_set_text_static(label_prompt_2, "user@watch:~ $");
label_time = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_recolor(label_time, true);
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -60);
heartbeatValue = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_recolor(heartbeatValue, true);
lv_obj_align(heartbeatValue, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 20);
stepValue = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_recolor(stepValue, true);
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 0);
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
Refresh();
}
WatchFaceTerminal::~WatchFaceTerminal() {
lv_task_del(taskRefresh);
lv_obj_clean(lv_scr_act());
}
void WatchFaceTerminal::Refresh() {
powerPresent = batteryController.IsPowerPresent();
batteryPercentRemaining = batteryController.PercentRemaining();
if (batteryPercentRemaining.IsUpdated() || powerPresent.IsUpdated()) {
lv_label_set_text_fmt(batteryValue, "[BATT]#387b54 %d%%", batteryPercentRemaining.Get());
if (batteryController.IsPowerPresent()) {
lv_label_ins_text(batteryValue, LV_LABEL_POS_LAST, " Charging");
}
}
bleState = bleController.IsConnected();
bleRadioEnabled = bleController.IsRadioEnabled();
if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) {
if (!bleRadioEnabled.Get()) {
lv_label_set_text_static(connectState, "[STAT]#0082fc Disabled#");
} else {
if (bleState.Get()) {
lv_label_set_text_static(connectState, "[STAT]#0082fc Connected#");
} else {
lv_label_set_text_static(connectState, "[STAT]#0082fc Disconnected#");
}
}
}
notificationState = notificationManager.AreNewNotificationsAvailable();
if (notificationState.IsUpdated()) {
if (notificationState.Get()) {
lv_label_set_text_static(notificationIcon, "You have mail.");
} else {
lv_label_set_text_static(notificationIcon, "");
}
}
currentDateTime = std::chrono::time_point_cast<std::chrono::seconds>(dateTimeController.CurrentDateTime());
if (currentDateTime.IsUpdated()) {
uint8_t hour = dateTimeController.Hours();
uint8_t minute = dateTimeController.Minutes();
uint8_t second = dateTimeController.Seconds();
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
char ampmChar[3] = "AM";
if (hour == 0) {
hour = 12;
} else if (hour == 12) {
ampmChar[0] = 'P';
} else if (hour > 12) {
hour = hour - 12;
ampmChar[0] = 'P';
}
lv_label_set_text_fmt(label_time, "[TIME]#11cc55 %02d:%02d:%02d %s#", hour, minute, second, ampmChar);
} else {
lv_label_set_text_fmt(label_time, "[TIME]#11cc55 %02d:%02d:%02d", hour, minute, second);
}
currentDate = std::chrono::time_point_cast<days>(currentDateTime.Get());
if (currentDate.IsUpdated()) {
uint16_t year = dateTimeController.Year();
Controllers::DateTime::Months month = dateTimeController.Month();
uint8_t day = dateTimeController.Day();
lv_label_set_text_fmt(label_date, "[DATE]#007fff %04d-%02d-%02d#", short(year), char(month), char(day));
}
}
heartbeat = heartRateController.HeartRate();
heartbeatRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped;
if (heartbeat.IsUpdated() || heartbeatRunning.IsUpdated()) {
if (heartbeatRunning.Get()) {
lv_label_set_text_fmt(heartbeatValue, "[L_HR]#ee3311 %d bpm#", heartbeat.Get());
} else {
lv_label_set_text_static(heartbeatValue, "[L_HR]#ee3311 ---#");
}
}
stepCount = motionController.NbSteps();
if (stepCount.IsUpdated()) {
lv_label_set_text_fmt(stepValue, "[STEP]#ee3377 %lu steps#", stepCount.Get());
}
}

View File

@@ -0,0 +1,93 @@
#pragma once
#include <lvgl/src/lv_core/lv_obj.h>
#include <chrono>
#include <cstdint>
#include <memory>
#include <displayapp/Controllers.h>
#include "displayapp/screens/Screen.h"
#include "components/datetime/DateTimeController.h"
#include "utility/DirtyValue.h"
namespace Pinetime {
namespace Controllers {
class Settings;
class Battery;
class Ble;
class NotificationManager;
class HeartRateController;
class MotionController;
}
namespace Applications {
namespace Screens {
class WatchFaceTerminal : public Screen {
public:
WatchFaceTerminal(Controllers::DateTime& dateTimeController,
const Controllers::Battery& batteryController,
const Controllers::Ble& bleController,
Controllers::NotificationManager& notificationManager,
Controllers::Settings& settingsController,
Controllers::HeartRateController& heartRateController,
Controllers::MotionController& motionController);
~WatchFaceTerminal() override;
void Refresh() override;
private:
Utility::DirtyValue<int> batteryPercentRemaining {};
Utility::DirtyValue<bool> powerPresent {};
Utility::DirtyValue<bool> bleState {};
Utility::DirtyValue<bool> bleRadioEnabled {};
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>> currentDateTime {};
Utility::DirtyValue<uint32_t> stepCount {};
Utility::DirtyValue<uint8_t> heartbeat {};
Utility::DirtyValue<bool> heartbeatRunning {};
Utility::DirtyValue<bool> notificationState {};
using days = std::chrono::duration<int32_t, std::ratio<86400>>; // TODO: days is standard in c++20
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, days>> currentDate;
lv_obj_t* label_time;
lv_obj_t* label_date;
lv_obj_t* label_prompt_1;
lv_obj_t* label_prompt_2;
lv_obj_t* batteryValue;
lv_obj_t* heartbeatValue;
lv_obj_t* stepValue;
lv_obj_t* notificationIcon;
lv_obj_t* connectState;
Controllers::DateTime& dateTimeController;
const Controllers::Battery& batteryController;
const Controllers::Ble& bleController;
Controllers::NotificationManager& notificationManager;
Controllers::Settings& settingsController;
Controllers::HeartRateController& heartRateController;
Controllers::MotionController& motionController;
lv_task_t* taskRefresh;
};
}
template <>
struct WatchFaceTraits<WatchFace::Terminal> {
static constexpr WatchFace watchFace = WatchFace::Terminal;
static constexpr const char* name = "Terminal";
static Screens::Screen* Create(AppControllers& controllers) {
return new Screens::WatchFaceTerminal(controllers.dateTimeController,
controllers.batteryController,
controllers.bleController,
controllers.notificationManager,
controllers.settingsController,
controllers.heartRateController,
controllers.motionController);
};
static bool IsAvailable(Pinetime::Controllers::FS& /*filesystem*/) {
return true;
}
};
}
}

View File

@@ -42,8 +42,8 @@ SettingSetTime::SettingSetTime(Pinetime::Controllers::DateTime& dateTimeControll
lv_obj_t* staticLabel = lv_label_create(lv_scr_act(), nullptr); lv_obj_t* staticLabel = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(staticLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42); lv_obj_set_style_local_text_font(staticLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
lv_label_set_text_static(staticLabel, ":00"); lv_label_set_text_static(staticLabel, "00:00:00");
lv_obj_align(staticLabel, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -33, POS_Y_TEXT); lv_obj_align(staticLabel, lv_scr_act(), LV_ALIGN_CENTER, 0, POS_Y_TEXT);
hourCounter.Create(); hourCounter.Create();
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {

View File

@@ -9,8 +9,8 @@
#include "displayapp/screens/Screen.h" #include "displayapp/screens/Screen.h"
#include "displayapp/screens/Symbols.h" #include "displayapp/screens/Symbols.h"
#include "displayapp/screens/CheckboxList.h" #include "displayapp/screens/CheckboxList.h"
// #include "displayapp/screens/WatchFaceInfineat.h" #include "displayapp/screens/WatchFaceInfineat.h"
// #include "displayapp/screens/WatchFaceCasioStyleG7710.h" #include "displayapp/screens/WatchFaceCasioStyleG7710.h"
namespace Pinetime { namespace Pinetime {

View File

@@ -417,8 +417,6 @@ typedef void* lv_indev_drv_user_data_t; /*Type of user data in the in
LV_FONT_DECLARE(jetbrains_mono_extrabold_compressed) \ LV_FONT_DECLARE(jetbrains_mono_extrabold_compressed) \
LV_FONT_DECLARE(jetbrains_mono_42) \ LV_FONT_DECLARE(jetbrains_mono_42) \
LV_FONT_DECLARE(jetbrains_mono_76) \ LV_FONT_DECLARE(jetbrains_mono_76) \
LV_FONT_DECLARE(noto_serif_cjk_20) \
LV_FONT_DECLARE(noto_serif_cjk_15) \
LV_FONT_DECLARE(open_sans_light) \ LV_FONT_DECLARE(open_sans_light) \
LV_FONT_DECLARE(fontawesome_weathericons) \ LV_FONT_DECLARE(fontawesome_weathericons) \
LV_FONT_DECLARE(lv_font_sys_48) LV_FONT_DECLARE(lv_font_sys_48)

View File

@@ -22,5 +22,41 @@
"size": 120, "size": 120,
"format": "bin", "format": "bin",
"target_path": "/fonts/" "target_path": "/fonts/"
},
"lv_font_dots_40": {
"sources": [
{
"file": "fonts/repetitionscrolling.ttf",
"symbols": "0123456789-MONTUEWEDTHUFRISATSUN WK"
}
],
"bpp": 1,
"size": 40,
"format": "bin",
"target_path": "/fonts/"
},
"7segments_40" : {
"sources": [
{
"file": "fonts/7segment.woff",
"symbols": "0123456789: -"
}
],
"bpp": 1,
"size": 40,
"format": "bin",
"target_path": "/fonts/"
},
"7segments_115" : {
"sources": [
{
"file": "fonts/7segment.woff",
"symbols": "0123456789: -"
}
],
"bpp": 1,
"size": 115,
"format": "bin",
"target_path": "/fonts/"
} }
} }