This commit is contained in:
Eve C 2024-10-02 12:28:03 +02:00
commit b7b68f6362
50 changed files with 1276 additions and 283 deletions

View file

@ -1,5 +0,0 @@
[core]
whitespace = blank-at-eol,blank-at-eof,space-before-tab
autocrlf = input
[apply]
whitespace = fix

4
.gitignore vendored
View file

@ -13,6 +13,10 @@ build
tools
node_modules
# My stuff
#draft_pictures
node_modules
# Resulting binary files
*.a
*.so

View file

@ -1,16 +1,48 @@
# [InfiniTime](https://github.com/InfiniTimeOrg/InfiniTime)
# [InfiniTime](https://github.com/Eve1374/InfiniTime)
![InfiniTime logo](doc/logo/infinitime-logo-small.jpg "InfiniTime Logo")
Fast open-source firmware for the [PineTime smartwatch](https://pine64.org/devices/pinetime/) with many features, written in modern C++.
## Quick notes on this InfiniTime version
- I copied the source code from this git repo : [InfiniTime](https://github.com/InfiniTimeOrg/InfiniTime)
- I added a watch face "WatchFaceMeow" whose main features are to be pink and have info about the alarm status
- I stored the compile commands in scripts compile.sh to run from InfiniTime/ folder, and make_pine_mcu.sh to build the image must be run from InfiniTime/build/ (compile.sh copies make_pine_mcu.sh to build/
- The file to flash to the pinetime is InfiniTime/build/pinetime-mcuboot-app-dfu-1.14.0.zip : I didn't change the version compared to the one I downloaded from [InfiniTime](https://github.com/InfiniTimeOrg/InfiniTime) so make sure not to keep keep a copy of it
Here are pictures with and without alarm set :
![Meow alarm set](doc/ui/meow_alarmset.png "Meow WatchFace, alarm set") ![Meow alarm not set](doc/ui/meow_alarmnotset.png "Meow WatchFace, alarm not set")
Original repo : [InfiniTime](https://github.com/InfiniTimeOrg/InfiniTime)
- [Getting started with InfiniTime](doc/gettingStarted/gettingStarted-1.0.md)
- [Updating the software](doc/gettingStarted/updating-software.md)
- [About the firmware and bootloader](doc/gettingStarted/about-software.md)
- [PineTimeStyle Watch face](https://pine64.org/documentation/PineTime/Watchfaces/PineTimeStyle)
- [Weather integration](https://pine64.org/documentation/PineTime/Software/InfiniTime_weather/)
## Welcome to my InfiniTime fork ?!
Branches :
- main : shows this doc
- alarm-status-on-infineat : shows the alarm status on infineat, can be enabled or disabled from the settigns menu that is updated accordingly :
![Infineat settings](doc/ui/infineat_settings.png "Infineat settings")
- my-custom-infinitime : branch were I put things that I want for myself, like a watchface with paw instead of shoe icon for steps counter :
![Meow watchface](doc/ui/meow_alarmset.png "Meow watchface")
## New to InfiniTime?
- [Getting started with InfiniTime](doc/gettingStarted/gettingStarted-1.0.md)
- [Updating the software](doc/gettingStarted/updating-software.md)
- [About the firmware and bootloader](doc/gettingStarted/about-software.md)
- [PineTimeStyle Watch face](https://wiki.pine64.org/wiki/PineTimeStyle)
- [Weather integration](https://wiki.pine64.org/wiki/Infinitime-Weather)
- [PineTimeStyle Watch face](https://pine64.org/documentation/PineTime/Watchfaces/PineTimeStyle)
- [Weather integration](https://pine64.org/documentation/PineTime/Software/InfiniTime_weather/)
### Companion apps

8
compile.sh Executable file
View file

@ -0,0 +1,8 @@
#!/bin/bash
rm -r build
cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=/home/eve/Work/gcc-arm-none-eabi-10.3-2021.10 -DNRF5_SDK_PATH=/home/eve/Work/nRF5_SDK_17.1.0_ddde560 -DTARGET_DEVICE=PINETIME -DBUILD_DFU=1 -DBUILD_RESOURCES=1 -B build -DCMAKE_BUILD_TYPE=Release
cp make_pine_mcu.sh build/

BIN
doc/lvgl_align.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
doc/palettes.xcf Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

BIN
doc/ui/meow_alarmnotset.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
doc/ui/meow_alarmset.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6 KiB

BIN
draft_pictures/cat.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

BIN
draft_pictures/cat.xcf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

6
make_pine.sh Executable file
View file

@ -0,0 +1,6 @@
#!/bin/bash
#cp ./displayapp/apps/Apps.h ../src/displayapp/apps/Apps.h
make -j4 pinetime-app

6
make_pine_mcu.sh Executable file
View file

@ -0,0 +1,6 @@
#!/bin/bash
#cp ./displayapp/apps/Apps.h ../src/displayapp/apps/Apps.h
make clean -j4 pinetime-mcuboot-app

183
package-lock.json generated
View file

@ -1,183 +0,0 @@
{
"name": "InfiniTime",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"dependencies": {
"lv_font_conv": "^1.5.2"
}
},
"node_modules/lv_font_conv": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/lv_font_conv/-/lv_font_conv-1.5.2.tgz",
"integrity": "sha512-0UapRSTkVP/pnB8Z4r2HDHx5p2dJx/xUG1+14u/WXo59mwuC7BahR+Bnx/66jKoDrG1wFQwn9ZzoyMxRHOD9bg==",
"bundleDependencies": [
"argparse",
"bit-buffer",
"debug",
"make-error",
"mkdirp",
"opentype.js",
"pngjs"
],
"dependencies": {
"argparse": "^2.0.0",
"bit-buffer": "^0.2.5",
"debug": "^4.1.1",
"make-error": "^1.3.5",
"mkdirp": "^1.0.4",
"opentype.js": "^1.1.0",
"pngjs": "^6.0.0"
},
"bin": {
"lv_font_conv": "lv_font_conv.js"
}
},
"node_modules/lv_font_conv/node_modules/argparse": {
"version": "2.0.1",
"inBundle": true,
"license": "Python-2.0"
},
"node_modules/lv_font_conv/node_modules/bit-buffer": {
"version": "0.2.5",
"inBundle": true,
"license": "MIT"
},
"node_modules/lv_font_conv/node_modules/debug": {
"version": "4.3.1",
"inBundle": true,
"license": "MIT",
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/lv_font_conv/node_modules/make-error": {
"version": "1.3.6",
"inBundle": true,
"license": "ISC"
},
"node_modules/lv_font_conv/node_modules/mkdirp": {
"version": "1.0.4",
"inBundle": true,
"license": "MIT",
"bin": {
"mkdirp": "bin/cmd.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/lv_font_conv/node_modules/ms": {
"version": "2.1.2",
"inBundle": true,
"license": "MIT"
},
"node_modules/lv_font_conv/node_modules/opentype.js": {
"version": "1.3.3",
"inBundle": true,
"license": "MIT",
"dependencies": {
"string.prototype.codepointat": "^0.2.1",
"tiny-inflate": "^1.0.3"
},
"bin": {
"ot": "bin/ot"
},
"engines": {
"node": ">= 8.0.0"
}
},
"node_modules/lv_font_conv/node_modules/pngjs": {
"version": "6.0.0",
"inBundle": true,
"license": "MIT",
"engines": {
"node": ">=12.13.0"
}
},
"node_modules/lv_font_conv/node_modules/string.prototype.codepointat": {
"version": "0.2.1",
"inBundle": true,
"license": "MIT"
},
"node_modules/lv_font_conv/node_modules/tiny-inflate": {
"version": "1.0.3",
"inBundle": true,
"license": "MIT"
}
},
"dependencies": {
"lv_font_conv": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/lv_font_conv/-/lv_font_conv-1.5.2.tgz",
"integrity": "sha512-0UapRSTkVP/pnB8Z4r2HDHx5p2dJx/xUG1+14u/WXo59mwuC7BahR+Bnx/66jKoDrG1wFQwn9ZzoyMxRHOD9bg==",
"requires": {
"argparse": "^2.0.0",
"bit-buffer": "^0.2.5",
"debug": "^4.1.1",
"make-error": "^1.3.5",
"mkdirp": "^1.0.4",
"opentype.js": "^1.1.0",
"pngjs": "^6.0.0"
},
"dependencies": {
"argparse": {
"version": "2.0.1",
"bundled": true
},
"bit-buffer": {
"version": "0.2.5",
"bundled": true
},
"debug": {
"version": "4.3.1",
"bundled": true,
"requires": {
"ms": "2.1.2"
}
},
"make-error": {
"version": "1.3.6",
"bundled": true
},
"mkdirp": {
"version": "1.0.4",
"bundled": true
},
"ms": {
"version": "2.1.2",
"bundled": true
},
"opentype.js": {
"version": "1.3.3",
"bundled": true,
"requires": {
"string.prototype.codepointat": "^0.2.1",
"tiny-inflate": "^1.0.3"
}
},
"pngjs": {
"version": "6.0.0",
"bundled": true
},
"string.prototype.codepointat": {
"version": "0.2.1",
"bundled": true
},
"tiny-inflate": {
"version": "1.0.3",
"bundled": true
}
}
}
}
}

View file

@ -1,5 +1,5 @@
{
"dependencies": {
"lv_font_conv": "^1.5.2"
"lv_font_conv": "^1.5.3"
}
}

View file

@ -371,7 +371,7 @@ list(APPEND SOURCE_FILES
displayapp/screens/StopWatch.cpp
displayapp/screens/BatteryIcon.cpp
displayapp/screens/BleIcon.cpp
displayapp/screens/AlarmIcon.cpp
displayapp/screens/AlarmIcon.cpp
displayapp/screens/NotificationIcon.cpp
displayapp/screens/SystemInfo.cpp
displayapp/screens/Label.cpp

View file

@ -19,4 +19,4 @@ namespace Pinetime {
static constexpr const char* commitHash = "@PROJECT_GIT_COMMIT_HASH@";
static constexpr const char* versionString = "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@";
};
}
}

View file

@ -80,7 +80,7 @@ int WeatherCallback(uint16_t /*connHandle*/, uint16_t /*attrHandle*/, struct ble
return static_cast<Pinetime::Controllers::SimpleWeatherService*>(arg)->OnCommand(ctxt);
}
SimpleWeatherService::SimpleWeatherService(const DateTime& dateTimeController) : dateTimeController(dateTimeController) {
SimpleWeatherService::SimpleWeatherService(DateTime& dateTimeController) : dateTimeController(dateTimeController) {
}
void SimpleWeatherService::Init() {

View file

@ -40,7 +40,7 @@ namespace Pinetime {
class SimpleWeatherService {
public:
explicit SimpleWeatherService(const DateTime& dateTimeController);
explicit SimpleWeatherService(DateTime& dateTimeController);
void Init();
@ -140,7 +140,7 @@ namespace Pinetime {
uint16_t eventHandle {};
const Pinetime::Controllers::DateTime& dateTimeController;
Pinetime::Controllers::DateTime& dateTimeController;
std::optional<CurrentWeather> currentWeather;
std::optional<Forecast> forecast;

View file

@ -1,6 +1,8 @@
#include "components/datetime/DateTimeController.h"
#include <libraries/log/nrf_log.h>
#include <systemtask/SystemTask.h>
#include <hal/nrf_rtc.h>
#include "nrf_assert.h"
using namespace Pinetime::Controllers;
@ -12,11 +14,16 @@ namespace {
}
DateTime::DateTime(Controllers::Settings& settingsController) : settingsController {settingsController} {
mutex = xSemaphoreCreateMutex();
ASSERT(mutex != nullptr);
xSemaphoreGive(mutex);
}
void DateTime::SetCurrentTime(std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> t) {
xSemaphoreTake(mutex, portMAX_DELAY);
this->currentDateTime = t;
UpdateTime(previousSystickCounter); // Update internal state without updating the time
UpdateTime(previousSystickCounter, true); // Update internal state without updating the time
xSemaphoreGive(mutex);
}
void DateTime::SetTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) {
@ -29,13 +36,15 @@ void DateTime::SetTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour,
/* .tm_year = */ year - 1900,
};
tm.tm_isdst = -1; // Use DST value from local time zone
currentDateTime = std::chrono::system_clock::from_time_t(std::mktime(&tm));
NRF_LOG_INFO("%d %d %d ", day, month, year);
NRF_LOG_INFO("%d %d %d ", hour, minute, second);
UpdateTime(previousSystickCounter);
tm.tm_isdst = -1; // Use DST value from local time zone
xSemaphoreTake(mutex, portMAX_DELAY);
currentDateTime = std::chrono::system_clock::from_time_t(std::mktime(&tm));
UpdateTime(previousSystickCounter, true);
xSemaphoreGive(mutex);
systemTask->PushMessage(System::Messages::OnNewTime);
}
@ -45,25 +54,34 @@ void DateTime::SetTimeZone(int8_t timezone, int8_t dst) {
dstOffset = dst;
}
void DateTime::UpdateTime(uint32_t systickCounter) {
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> DateTime::CurrentDateTime() {
xSemaphoreTake(mutex, portMAX_DELAY);
UpdateTime(nrf_rtc_counter_get(portNRF_RTC_REG), false);
xSemaphoreGive(mutex);
return currentDateTime;
}
void DateTime::UpdateTime(uint32_t systickCounter, bool forceUpdate) {
// Handle systick counter overflow
uint32_t systickDelta = 0;
if (systickCounter < previousSystickCounter) {
systickDelta = 0xffffff - previousSystickCounter;
systickDelta = static_cast<uint32_t>(portNRF_RTC_MAXTICKS) - previousSystickCounter;
systickDelta += systickCounter + 1;
} else {
systickDelta = systickCounter - previousSystickCounter;
}
/*
* 1000 ms = 1024 ticks
*/
auto correctedDelta = systickDelta / 1024;
auto rest = systickDelta % 1024;
auto correctedDelta = systickDelta / configTICK_RATE_HZ;
// If a second hasn't passed, there is nothing to do
// If the time has been changed, set forceUpdate to trigger internal state updates
if (correctedDelta == 0 && !forceUpdate) {
return;
}
auto rest = systickDelta % configTICK_RATE_HZ;
if (systickCounter >= rest) {
previousSystickCounter = systickCounter - rest;
} else {
previousSystickCounter = 0xffffff - (rest - systickCounter);
previousSystickCounter = static_cast<uint32_t>(portNRF_RTC_MAXTICKS) - (rest - systickCounter - 1);
}
currentDateTime += std::chrono::seconds(correctedDelta);

View file

@ -5,6 +5,8 @@
#include <ctime>
#include <string>
#include "components/settings/Settings.h"
#include <FreeRTOS.h>
#include <semphr.h>
namespace Pinetime {
namespace System {
@ -45,8 +47,6 @@ namespace Pinetime {
*/
void SetTimeZone(int8_t timezone, int8_t dst);
void UpdateTime(uint32_t systickCounter);
uint16_t Year() const {
return 1900 + localTime.tm_year;
}
@ -124,12 +124,10 @@ namespace Pinetime {
static const char* MonthShortToStringLow(Months month);
static const char* DayOfWeekShortToStringLow(Days day);
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> CurrentDateTime() const {
return currentDateTime;
}
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> CurrentDateTime();
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> UTCDateTime() const {
return currentDateTime - std::chrono::seconds((tzOffset + dstOffset) * 15 * 60);
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> UTCDateTime() {
return CurrentDateTime() - std::chrono::seconds((tzOffset + dstOffset) * 15 * 60);
}
std::chrono::seconds Uptime() const {
@ -141,10 +139,14 @@ namespace Pinetime {
std::string FormattedTime();
private:
void UpdateTime(uint32_t systickCounter, bool forceUpdate);
std::tm localTime;
int8_t tzOffset = 0;
int8_t dstOffset = 0;
SemaphoreHandle_t mutex = nullptr;
uint32_t previousSystickCounter = 0;
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> currentDateTime;
std::chrono::seconds uptime {0};

View file

@ -0,0 +1,41 @@
# Refactoring needed
## Context
The [PR #2041 - Continuous time updates](https://github.com/InfiniTimeOrg/InfiniTime/pull/2041) highlighted some
limitations in the design of DateTimeController: the granularity of the time returned by `DateTime::CurrentDateTime()`
is limited by the frequency at which SystemTask calls `DateTime::UpdateTime()`, which is currently set to 100ms.
@mark9064 provided more details
in [this comment](https://github.com/InfiniTimeOrg/InfiniTime/pull/2041#issuecomment-2048528967).
The [PR #2041 - Continuous time updates](https://github.com/InfiniTimeOrg/InfiniTime/pull/2041) provided some changes
to `DateTime` controller that improves the granularity of the time returned by `DateTime::CurrentDateTime()`.
However, the review showed that `DateTime` cannot be `const` anymore, even when it's only used to get the current time,
since `DateTime::CurrentDateTime()` changes the internal state of the instance.
We tried to identify alternative implementation that would have maintained the "const correctness" but we eventually
figured that this would lead to a re-design of `DateTime` which was out of scope of the initial PR (Continuous time
updates and always on display).
So we decided to merge this PR #2041 and agree to fix/improve `DateTime` later on.
## What needs to be done?
Improve/redesign `DateTime` so that it
* provides a very granular (ideally down to the millisecond) date and time via `CurrentDateTime()`.
* can be declared/passed as `const` when it's only used to **get** the time.
* limits the use of mutex as much as possible (an ideal implementation would not use any mutex, but this might not be
possible).
* improves the design of `DateTime::Seconds()`, `DateTime::Minutes()`, `DateTime::Hours()`, etc as
explained [in this comment](https://github.com/InfiniTimeOrg/InfiniTime/pull/2054#pullrequestreview-2037033105).
Once this redesign is implemented, all instances/references to `DateTime` should be reviewed and updated to use `const`
where appropriate.
Please check the following PR to get more context about this redesign:
* [#2041 - Continuous time updates by @mark9064](https://github.com/InfiniTimeOrg/InfiniTime/pull/2041)
* [#2054 - Continuous time update - Alternative implementation to #2041 by @JF002](https://github.com/InfiniTimeOrg/InfiniTime/pull/2054)

View file

@ -124,17 +124,6 @@ namespace Pinetime {
return settings.watchFaceInfineat.showSideCover;
};
void SetInfineatShowAlarmStatus(bool show) {
if (show != settings.watchFaceInfineat.showAlarmStatus) {
settings.watchFaceInfineat.showAlarmStatus = show;
settingsChanged = true;
}
};
bool GetInfineatShowAlarmStatus() const {
return settings.watchFaceInfineat.showAlarmStatus;
};
void SetInfineatColorIndex(int index) {
if (index != settings.watchFaceInfineat.colorIndex) {
settings.watchFaceInfineat.colorIndex = index;

View file

@ -19,6 +19,7 @@
#include "displayapp/screens/Metronome.h"
#include "displayapp/screens/Music.h"
#include "displayapp/screens/Navigation.h"
#include "displayapp/screens/Calendar.h"
#include "displayapp/screens/Notifications.h"
#include "displayapp/screens/SystemInfo.h"
#include "displayapp/screens/Tile.h"
@ -125,6 +126,7 @@ void DisplayApp::Start(System::BootErrors error) {
bootError = error;
lvgl.Init();
motorController.Init();
if (error == System::BootErrors::TouchController) {
LoadNewScreen(Apps::Error, DisplayApp::FullRefreshDirections::None);
@ -150,7 +152,6 @@ void DisplayApp::Process(void* instance) {
void DisplayApp::InitHw() {
brightnessController.Init();
ApplyBrightness();
motorController.Init();
lcd.Init();
}

View file

@ -8,6 +8,7 @@ namespace Colors {
static constexpr lv_color_t green = LV_COLOR_MAKE(0x0, 0xb0, 0x0);
static constexpr lv_color_t blue = LV_COLOR_MAKE(0x0, 0x50, 0xff);
static constexpr lv_color_t lightGray = LV_COLOR_MAKE(0xb0, 0xb0, 0xb0);
static constexpr lv_color_t gray = LV_COLOR_MAKE(0x50, 0x50, 0x50);
static constexpr lv_color_t bg = LV_COLOR_MAKE(0x5d, 0x69, 0x7e);
static constexpr lv_color_t bgAlt = LV_COLOR_MAKE(0x38, 0x38, 0x38);

View file

@ -12,6 +12,7 @@
#include "displayapp/screens/WatchFaceAnalog.h"
#include "displayapp/screens/WatchFaceCasioStyleG7710.h"
#include "displayapp/screens/WatchFaceInfineat.h"
#include "displayapp/screens/WatchFaceMeow.h"
#include "displayapp/screens/WatchFacePineTimeStyle.h"
#include "displayapp/screens/WatchFaceTerminal.h"

View file

@ -23,6 +23,7 @@ namespace Pinetime {
Twos,
HeartRate,
Navigation,
Calendar,
StopWatch,
Metronome,
Motion,
@ -51,6 +52,7 @@ namespace Pinetime {
PineTimeStyle,
Terminal,
Infineat,
Meow,
CasioStyleG7710,
};

View file

@ -8,12 +8,13 @@ else ()
set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::HeartRate")
set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Music")
set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Paint")
set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Paddle")
#set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Paddle")
set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Twos")
set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Dice")
set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Metronome")
set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Navigation")
set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Weather")
#set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Navigation")
#set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Weather")
set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Calendar")
#set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Motion")
set(USERAPP_TYPES "${DEFAULT_USER_APP_TYPES}" CACHE STRING "List of user apps to build into the firmware")
endif ()
@ -21,10 +22,11 @@ endif ()
if(DEFINED ENABLE_WATCHFACES)
set(WATCHFACE_TYPES ${ENABLE_WATCHFACES} CACHE STRING "List of watch faces to build into the firmware")
else()
set(DEFAULT_WATCHFACE_TYPES "WatchFace::Digital")
set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Analog")
set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::PineTimeStyle")
set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Terminal")
set(DEFAULT_WATCHFACE_TYPES "WatchFace::Meow")
set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Digital")
#set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Analog")
#set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::PineTimeStyle")
#set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Terminal")
set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Infineat")
set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::CasioStyleG7710")
set(WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}" CACHE STRING "List of watch faces to build into the firmware")

View file

@ -0,0 +1,96 @@
/* Copyright (C) 2024 thnikk, Boteium, JustScott
This file is part of InfiniTime.
InfiniTime is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
InfiniTime is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "displayapp/screens/Calendar.h"
#include "components/datetime/DateTimeController.h"
#include "displayapp/InfiniTimeTheme.h"
using namespace Pinetime::Applications::Screens;
Calendar::Calendar(Controllers::DateTime& dateTimeController) : dateTimeController {dateTimeController} {
// Create calendar object
calendar = lv_calendar_create(lv_scr_act(), NULL);
// Set size
lv_obj_set_size(calendar, LV_HOR_RES, LV_VER_RES);
// Set alignment
lv_obj_align(calendar, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, -5);
// Disable clicks
lv_obj_set_click(calendar, false);
// Set style of today's date
lv_obj_set_style_local_text_color(calendar, LV_CALENDAR_PART_DATE, LV_STATE_FOCUSED, Colors::deepOrange);
// Set style of inactive month's days
lv_obj_set_style_local_text_color(calendar, LV_CALENDAR_PART_DATE, LV_STATE_DISABLED, Colors::gray);
// Get today's date
current.year = static_cast<int>(dateTimeController.Year());
current.month = static_cast<int>(dateTimeController.Month());
current.day = static_cast<int>(dateTimeController.Day());
// Set today's date
lv_calendar_set_today_date(calendar, &current);
lv_calendar_set_showed_date(calendar, &current);
}
bool Calendar::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
switch (event) {
case TouchEvents::SwipeLeft: {
if (current.month == 12) {
current.month = 1;
current.year++;
} else {
current.month++;
}
lv_calendar_set_showed_date(calendar, &current);
return true;
}
case TouchEvents::SwipeRight: {
if (current.month == 1) {
current.month = 12;
current.year--;
} else {
current.month--;
}
lv_calendar_set_showed_date(calendar, &current);
return true;
}
/*
case TouchEvents::SwipeUp: {
current.year++;
lv_calendar_set_showed_date(calendar, &current);
return true;
}
case TouchEvents::SwipeDown: {
current.year--;
lv_calendar_set_showed_date(calendar, &current);
return true;
}
*/
default: {
return false;
}
}
}
Calendar::~Calendar() {
lv_obj_clean(lv_scr_act());
}

View file

@ -0,0 +1,59 @@
/* Copyright (C) 2024 thnikk, Boteium, JustScott
This file is part of InfiniTime.
InfiniTime is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
InfiniTime is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "displayapp/apps/Apps.h"
#include "displayapp/Controllers.h"
#include "displayapp/screens/Screen.h"
#include "components/datetime/DateTimeController.h"
#include <lvgl/lvgl.h>
#include "Symbols.h"
namespace Pinetime {
namespace Controllers {
class Settings;
}
namespace Applications {
namespace Screens {
class Calendar : public Screen {
public:
Calendar(Controllers::DateTime& dateTimeController);
~Calendar() override;
private:
bool OnTouchEvent(TouchEvents event);
Controllers::DateTime& dateTimeController;
lv_obj_t* calendar;
lv_calendar_date_t current;
};
}
template <>
struct AppTraits<Apps::Calendar> {
static constexpr Apps app = Apps::Calendar;
static constexpr const char* icon = Screens::Symbols::calendar;
static Screens::Screen* Create(AppControllers& controllers) {
return new Screens::Calendar(controllers.dateTimeController);
};
};
}
}

View file

@ -0,0 +1,10 @@
# Add a new watchface :
## Modify the following files with the names of your source files :
- /src/displayapp/apps/Apps.h.in
- /src/components/settings/Settings.h
- /src/displayapp/UserApps.h
- /src/displayapp/apps/CMakeLists.txt
- CMakelists.txt

View file

@ -75,7 +75,7 @@ namespace Pinetime {
BatteryIcon batteryIcon;
const Controllers::DateTime& dateTimeController;
Controllers::DateTime& dateTimeController;
const Controllers::Battery& batteryController;
const Controllers::Ble& bleController;
Controllers::NotificationManager& notificationManager;

View file

@ -4,10 +4,12 @@
#include <cstdio>
#include "displayapp/screens/BatteryIcon.h"
#include "displayapp/screens/BleIcon.h"
#include "displayapp/screens/AlarmIcon.h"
#include "displayapp/screens/NotificationIcon.h"
#include "displayapp/screens/Symbols.h"
#include "components/battery/BatteryController.h"
#include "components/ble/BleController.h"
#include "components/alarm/AlarmController.h"
#include "components/ble/NotificationManager.h"
#include "components/heartrate/HeartRateController.h"
#include "components/motion/MotionController.h"
@ -17,6 +19,7 @@ using namespace Pinetime::Applications::Screens;
WatchFaceCasioStyleG7710::WatchFaceCasioStyleG7710(Controllers::DateTime& dateTimeController,
const Controllers::Battery& batteryController,
const Controllers::Ble& bleController,
Controllers::AlarmController& alarmController,
Controllers::NotificationManager& notificatioManager,
Controllers::Settings& settingsController,
Controllers::HeartRateController& heartRateController,
@ -27,6 +30,7 @@ WatchFaceCasioStyleG7710::WatchFaceCasioStyleG7710(Controllers::DateTime& dateTi
dateTimeController {dateTimeController},
batteryController {batteryController},
bleController {bleController},
alarmController {alarmController},
notificatioManager {notificatioManager},
settingsController {settingsController},
heartRateController {heartRateController},
@ -168,6 +172,23 @@ WatchFaceCasioStyleG7710::WatchFaceCasioStyleG7710(Controllers::DateTime& dateTi
lv_label_set_text_static(stepIcon, Symbols::shoe);
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
alarmIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(alarmIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
lv_label_set_text_static(alarmIcon, Symbols::notbell);
lv_obj_align(alarmIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 5, -2);
labelAlarm = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(labelAlarm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
// lv_obj_set_style_local_text_font(labelAlarm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_teko);
lv_obj_align(labelAlarm, alarmIcon, LV_ALIGN_OUT_RIGHT_MID, 3, 0);
lv_label_set_text_static(labelAlarm, "00:00");
labelTimeAmPmAlarm = lv_label_create(lv_scr_act(), nullptr);
// lv_obj_set_style_local_text_font(labelTimeAmPmAlarm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_teko);
lv_label_set_text_static(labelTimeAmPmAlarm, "");
lv_obj_set_style_local_text_color(labelTimeAmPmAlarm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color_text);
lv_obj_align(labelTimeAmPmAlarm, labelAlarm, LV_ALIGN_OUT_RIGHT_MID, 3, 0);
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
Refresh();
}
@ -310,6 +331,41 @@ void WatchFaceCasioStyleG7710::Refresh() {
lv_obj_realign(stepValue);
lv_obj_realign(stepIcon);
}
alarmState = alarmController.State()==Pinetime::Controllers::AlarmController::AlarmState::Set;
// sets the icon as bell or barred bell
lv_label_set_text_static(alarmIcon, AlarmIcon::GetIcon(alarmState));
//displays the time of the alarm or nothing if the alarm is not set
if (alarmState) {
uint8_t alarmHours = alarmController.Hours();
uint8_t alarmMinutes = alarmController.Minutes();
//handles the am pm format.
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
char ampmChar[3] = "AM";
if (alarmHours == 0) {
alarmHours = 12;
} else if (alarmHours == 12) {
ampmChar[0]='P';
} else if (alarmHours > 12) {
alarmHours = alarmHours - 12;
ampmChar[0]='P';
}
lv_label_set_text(labelTimeAmPmAlarm, ampmChar);
// lv_obj_set_style_local_text_font(labelTimeAmPmAlarm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_teko);
lv_obj_align(labelTimeAmPmAlarm, labelAlarm, LV_ALIGN_OUT_RIGHT_MID, 3, 0);
}
lv_label_set_text_fmt(labelAlarm, "%02d:%02d", alarmHours, alarmMinutes);
lv_obj_align(alarmIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 5, -2);
lv_obj_align(labelAlarm, alarmIcon, LV_ALIGN_OUT_RIGHT_MID, 3, 0);
}
else {
lv_label_set_text_static(labelAlarm, Symbols::none);
lv_obj_align(alarmIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 5, -2);
lv_obj_align(labelAlarm, alarmIcon, LV_ALIGN_OUT_RIGHT_MID, 3, 0);
}
}
bool WatchFaceCasioStyleG7710::IsAvailable(Pinetime::Controllers::FS& filesystem) {

View file

@ -30,6 +30,7 @@ namespace Pinetime {
WatchFaceCasioStyleG7710(Controllers::DateTime& dateTimeController,
const Controllers::Battery& batteryController,
const Controllers::Ble& bleController,
Controllers::AlarmController& alarmController,
Controllers::NotificationManager& notificatioManager,
Controllers::Settings& settingsController,
Controllers::HeartRateController& heartRateController,
@ -46,6 +47,7 @@ namespace Pinetime {
Utility::DirtyValue<bool> powerPresent {};
Utility::DirtyValue<bool> bleState {};
Utility::DirtyValue<bool> bleRadioEnabled {};
bool alarmState {};
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::minutes>> currentDateTime {};
Utility::DirtyValue<uint32_t> stepCount {};
Utility::DirtyValue<uint8_t> heartbeat {};
@ -76,6 +78,9 @@ namespace Pinetime {
lv_obj_t* line_day_of_year;
lv_obj_t* backgroundLabel;
lv_obj_t* bleIcon;
lv_obj_t* labelAlarm;
lv_obj_t* labelTimeAmPmAlarm;
lv_obj_t* alarmIcon;
lv_obj_t* batteryPlug;
lv_obj_t* label_battery_value;
lv_obj_t* heartbeatIcon;
@ -90,6 +95,7 @@ namespace Pinetime {
Controllers::DateTime& dateTimeController;
const Controllers::Battery& batteryController;
const Controllers::Ble& bleController;
Controllers::AlarmController& alarmController;
Controllers::NotificationManager& notificatioManager;
Controllers::Settings& settingsController;
Controllers::HeartRateController& heartRateController;
@ -111,6 +117,7 @@ namespace Pinetime {
return new Screens::WatchFaceCasioStyleG7710(controllers.dateTimeController,
controllers.batteryController,
controllers.bleController,
controllers.alarmController,
controllers.notificationManager,
controllers.settingsController,
controllers.heartRateController,

View file

@ -0,0 +1,683 @@
/*********************************************************/
/*
* I modified the watchface Infineat :
* - added alarm info on the screen
* - modified the colors
* - modified step count icon
* Except colors, modifications are at line 254 and 500
*/
/*********************************************************/
#include "displayapp/screens/WatchFaceMeow.h"
#include <lvgl/lvgl.h>
#include <cstdio>
#include "displayapp/screens/Symbols.h"
#include "displayapp/screens/BleIcon.h"
//#include "displayapp/screens/AlarmIcon.h"
#include "components/settings/Settings.h"
#include "components/battery/BatteryController.h"
#include "components/ble/BleController.h"
#include "components/alarm/AlarmController.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<WatchFaceMeow*>(obj->user_data);
screen->UpdateSelected(obj, event);
}
enum class colors {
orange,
blue,
green,
rainbow,
vivid,
pink,
nordGreen,
};
constexpr int nColors = 7; // must match number of colors in InfineatColorsColors
constexpr int nLines = WatchFaceMeow::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)};
//added comments to say which color is which triangle
constexpr std::array<lv_color_t, nLines> rainbowColors = {LV_COLOR_MAKE(0x2d, 0xa4, 0x00), //green, small triangle on top
LV_COLOR_MAKE(0xac, 0x09, 0xc4), //purple, smalltriangle in the bottom half part on the clock display side
LV_COLOR_MAKE(0xfe, 0x03, 0x03), //red, the two small triangles above and below the battery
LV_COLOR_MAKE(0x0d, 0x57, 0xff), //blue, the small triangle at the bottom
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xe0, 0xb9, 0x00), //Yellow, large triangle on top left
LV_COLOR_MAKE(0xe8, 0x51, 0x02)}; //orange, large triangle on bottom left
// Add new colors, still rainbow but more pastel like
constexpr std::array<lv_color_t, nLines> rainbowVividColors ={LV_COLOR_MAKE(0xa5, 0xeb, 0x64),
LV_COLOR_MAKE(0xfc, 0x42, 0xb5),
LV_COLOR_MAKE(0xe7, 0xc1, 0xff),
LV_COLOR_MAKE(0x11, 0xdf, 0xfa),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xff, 0xec, 0x5d),
LV_COLOR_MAKE(0xff, 0x93, 0xaf)};
constexpr std::array<lv_color_t, nLines> pinkColors = {LV_COLOR_MAKE(0xff, 0xe5, 0xec),
LV_COLOR_MAKE(0xff, 0xb3, 0xc6),
LV_COLOR_MAKE(0xfb, 0x6f, 0x92),
LV_COLOR_MAKE(0xff, 0xe5, 0xec),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xff, 0xc2, 0xd1),
LV_COLOR_MAKE(0xff, 0x8f, 0xab)};
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)};
//define colors for texts and symbols
// gray is used for text symbols and time. I changed it to pink, because I can.
//static constexpr lv_color_t grayColor = LV_COLOR_MAKE(0x99, 0x99, 0x99);
static constexpr lv_color_t pinkColor = LV_COLOR_MAKE(0xfc, 0x42, 0xb5);
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::vivid) {
return &rainbowVividColors;
}
if (color == colors::pink) {
return &pinkColors;
}
return &nordGreenColors;
}
}
WatchFaceMeow::WatchFaceMeow(Controllers::DateTime& dateTimeController,
const Controllers::Battery& batteryController,
const Controllers::Ble& bleController,
Controllers::AlarmController& alarmController,
Controllers::Timer& timerController,
Controllers::NotificationManager& notificationManager,
Controllers::Settings& settingsController,
Controllers::MotionController& motionController,
Controllers::FS& filesystem)
: currentDateTime {{}},
dateTimeController {dateTimeController},
batteryController {batteryController},
bleController {bleController},
alarmController {alarmController},
timerController {timerController},
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
//paires de points pour chaque ligne
// les lignes sont pas les contours des triangles, elles sont des grosses bandes superposées
static constexpr lv_point_t linePoints[nLines][2] = {{{30, 25}, {68, -8}}, //1 small triangle on top
{{26, 167}, {43, 216}}, //2 purple, smalltriangle in the bottom half part on the clock display side
{{27, 40}, {27, 196}},// 3 small triangles up above and below battery
{{12, 182}, {65, 249}}, //4 most bottom right triangle
{{17, 97}, {17, 147}}, // 5 left part of battery zone, overlapped after by the large triangles
{{16, 81}, {42, 127}}, //6 upper part of battery zone
{{16, 163}, {42, 118}}, //7 lower part of battery zone
{{-20, 124}, {25, -11}}, //8 large upper triangle
{{-29, 89}, {27, 254}}}; //9 large lower triangle
//largeur des bandes
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);
}
//Battery indicator
logoCat = lv_img_create(lv_scr_act(), nullptr);
lv_img_set_src(logoCat, "F:/images/cat_small.bin");
lv_obj_set_pos(logoCat, 12, 108);
//adjust position for cat
lineBattery = lv_line_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_line_width(lineBattery, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 30);
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, 107};//27 = image x offset + image width / 2
lineBatteryPoints[1] = {27, 108};// the line covering the image is initialized as 1 px high
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_set_style_local_text_color(labelHour, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, pinkColor);
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_obj_set_style_local_text_color(labelMinutes, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, pinkColor);
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_obj_set_style_local_text_color(labelTimeAmPm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, pinkColor);
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);
labelDate = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(labelDate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, pinkColor);
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, pinkColor);
lv_label_set_text_static(bleIcon, Symbols::bluetooth);
lv_obj_align(bleIcon, dateContainer, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
// Based on existing code, I understand that items on the screen (date, bluteooth status..)
// are declared here with default states, and later below the state (date, ...) is assigned
// So I do the same to add the alarm status : I put a symbol that has a default value
// and a text that has a default value
// text
labelAlarm = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(labelAlarm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, pinkColor);
lv_obj_set_style_local_text_font(labelAlarm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_teko);
//lv_obj_align(labelAlarm, dateContainer, LV_ALIGN_OUT_BOTTOM_MID, -10, 0);
lv_obj_align(labelAlarm, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -3, 0);
lv_label_set_text_static(labelAlarm, "00:00");
labelTimeAmPmAlarm = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(labelTimeAmPmAlarm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_teko);
lv_label_set_text_static(labelTimeAmPmAlarm, "");
lv_obj_set_style_local_text_color(labelTimeAmPmAlarm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, pinkColor);
lv_obj_align(labelTimeAmPmAlarm, labelAlarm, LV_ALIGN_OUT_TOP_RIGHT, 0, 0);
// symbol
alarmIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(alarmIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, pinkColor);
lv_label_set_text_static(alarmIcon, Symbols::zzz);
lv_obj_align(alarmIcon, labelAlarm, LV_ALIGN_OUT_LEFT_MID, -3, 0);
// don't show the icons jsut set if we don't show alarm status
if (!settingsController.GetInfineatShowAlarmStatus()) {
lv_obj_set_hidden(labelAlarm, true);
lv_obj_set_hidden(alarmIcon, true);
lv_obj_set_hidden(labelTimeAmPmAlarm, true);
}
// text
labelTimer = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(labelTimer, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, pinkColor);
lv_obj_set_style_local_text_font(labelTimer, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_teko);
//lv_obj_align(labelAlarm, dateContainer, LV_ALIGN_OUT_BOTTOM_MID, -10, 0);
lv_obj_align(labelAlarm, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -3, 0);
lv_label_set_text_static(labelTimer, "00:00");
// symbol
timerIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(timerIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, pinkColor);
lv_label_set_text_static(timerIcon, Symbols::hourGlass);
lv_obj_align(timerIcon, labelTimer, LV_ALIGN_OUT_LEFT_MID, -3, 0);
// don't show the icons jsut set if we don't show alarm status
if (!settingsController.GetInfineatShowAlarmStatus()) {
lv_obj_set_hidden(labelTimer, true);
lv_obj_set_hidden(timerIcon, true);
}
stepValue = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, pinkColor);
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");
pawIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(pawIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, pinkColor);
lv_label_set_text_static(pawIcon, Symbols::paw);
lv_obj_align(pawIcon, 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, 0);
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);
btnToggleAlarm = lv_btn_create(lv_scr_act(), nullptr);
btnToggleAlarm->user_data = this;
lv_obj_set_size(btnToggleAlarm, 60, 60);
lv_obj_align(btnToggleAlarm, lv_scr_act(), LV_ALIGN_CENTER, 0, 80);
lv_obj_set_style_local_bg_opa(btnToggleAlarm, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_70);
const char* labelToggleAlarm = settingsController.GetInfineatShowAlarmStatus() ? Symbols::bell : Symbols::notbell;
lblAlarm = lv_label_create(btnToggleAlarm, nullptr);
lv_label_set_text_static(lblAlarm, labelToggleAlarm);
lv_obj_set_event_cb(btnToggleAlarm, event_handler);
lv_obj_set_hidden(btnToggleAlarm, 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();
}
WatchFaceMeow::~WatchFaceMeow() {
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 WatchFaceMeow::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 WatchFaceMeow::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);
lv_obj_set_hidden(btnToggleAlarm, true);
}
bool WatchFaceMeow::OnButtonPushed() {
if (!lv_obj_get_hidden(btnClose)) {
CloseMenu();
return true;
}
return false;
}
void WatchFaceMeow::UpdateSelected(lv_obj_t* object, lv_event_t event) {
if (event == LV_EVENT_CLICKED) {
bool showSideCover = settingsController.GetInfineatShowSideCover();
int colorIndex = settingsController.GetInfineatColorIndex();
bool showAlarmStatus = settingsController.GetInfineatShowAlarmStatus();
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);
lv_obj_set_hidden(btnToggleAlarm, 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 == btnToggleAlarm) {
settingsController.SetInfineatShowAlarmStatus(!showAlarmStatus);
bool newShowAlarmStatus = settingsController.GetInfineatShowAlarmStatus();
lv_obj_set_hidden(labelAlarm, !newShowAlarmStatus);
lv_obj_set_hidden(alarmIcon, !newShowAlarmStatus);
lv_obj_set_hidden(labelTimeAmPmAlarm, !newShowAlarmStatus);
const char* labelToggleAlarm = newShowAlarmStatus ? Symbols::bell : Symbols::notbell;
lv_label_set_text_static(lblAlarm, labelToggleAlarm);
}
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 WatchFaceMeow::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<std::chrono::days>(currentDateTime.Get());
if (currentDate.IsUpdated()) {
uint8_t day = dateTimeController.Day();
Controllers::DateTime::Days dayOfWeek = dateTimeController.DayOfWeek();
lv_label_set_text_fmt(labelDate, "%s %02d", dateTimeController.DayOfWeekShortToStringLow(dayOfWeek), 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()) {
//bleState.Get : in displayapp/widgets/StatusIcons.cpp: bleState = bleController.IsConnected();
//dynamic icons have their definitions in displayApp/screens/BleIcon.h / cpp
lv_label_set_text_static(bleIcon, BleIcon::GetIcon(bleState.Get()));
lv_obj_align(bleIcon, dateContainer, LV_ALIGN_OUT_BOTTOM_MID, 0, 3);
}
// Add alarm state and time
// AlarmState is an enum type in class AlarmController that is in namespace controllers
if (settingsController.GetInfineatShowAlarmStatus()) {
alarmState = alarmController.State()==Pinetime::Controllers::AlarmController::AlarmState::Set;
timerRunning = Pinetime::Controllers::Timer::timerController.IsRunning()
if(!timerRunning)
// sets the icon as bird or bed
const char* alarmSymbol = Symbols::zzz;
if(alarmState) {
alarmSymbol = Symbols::bird;
}
lv_label_set_text_static(alarmIcon, alarmSymbol);
//displays the time of the alarm or nothing if the alarm is not set
if (alarmState) {
uint8_t alarmHours = alarmController.Hours();
uint8_t alarmMinutes = alarmController.Minutes();
//handles the am pm format.
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
char ampmChar[3] = "AM";
if (alarmHours == 0) {
alarmHours = 12;
} else if (alarmHours == 12) {
ampmChar[0]='P';
} else if (alarmHours > 12) {
alarmHours = alarmHours - 12;
ampmChar[0]='P';
}
lv_label_set_text(labelTimeAmPmAlarm, ampmChar);
lv_obj_set_style_local_text_font(labelTimeAmPmAlarm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_teko);
lv_obj_align(labelTimeAmPmAlarm, labelAlarm, LV_ALIGN_OUT_TOP_RIGHT, 0, 0);
}
lv_label_set_text_fmt(labelAlarm, "%02d:%02d", alarmHours, alarmMinutes);
lv_obj_align(alarmIcon, labelAlarm, LV_ALIGN_OUT_LEFT_MID, -3, 0);
lv_obj_align(labelAlarm, dateContainer, LV_ALIGN_OUT_BOTTOM_MID, -10, 0);
lv_obj_align(labelAlarm, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -3, 0);
else{ //timer is running, display timer instead of alarm
const char* timerSymbol = Symbols::hourGlass;
lv_label_set_text_static(timerIcon, timerSymbol);
auto secondsRemaining = std::chrono::duration_cast<std::chrono::seconds>(timer.GetTimeRemaining())/1000;
timerMinutes = secondsRemaining.count() / 60;
timerSeconds = secondsRemaining.count() % 60;
lv_label_set_text_fmt(labelTimer, "%02d:%02d", timerMinutes, timerSeconds);
lv_obj_align(timerIcon, labelTimer, LV_ALIGN_OUT_LEFT_MID, -3, 0);
lv_obj_align(labelTimer, dateContainer, LV_ALIGN_OUT_BOTTOM_MID, -10, 0);
lv_obj_align(labelTimer, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -3, 0);
}
}
else {
lv_label_set_text_static(labelAlarm, Symbols::none);
lv_obj_align(alarmIcon, dateContainer, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
lv_obj_align(alarmIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -3, 0);
}
}
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(pawIcon, 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 WatchFaceMeow::SetBatteryLevel(uint8_t batteryPercent) {
// starting point (y) + Pine64 logo height * (100 - batteryPercent) / 100^
//the ligne grows, it covers the icon starting from the top
lineBatteryPoints[1] = {27, static_cast<lv_coord_t>(107 + 31 * (100 - batteryPercent) / 100)};
lv_line_set_points(lineBattery, lineBatteryPoints, 2);
}
void WatchFaceMeow::ToggleBatteryIndicatorColor(bool showSideCover) {
if (!showSideCover) { // make indicator and notification icon color white
lv_obj_set_style_local_image_recolor_opa(logoCat, LV_IMG_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_100);
lv_obj_set_style_local_image_recolor(logoCat, 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(logoCat, 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 WatchFaceMeow::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/cat_small.bin", LFS_O_RDONLY) < 0) {
return false;
}
filesystem.FileClose(&file);
return true;
}

View file

@ -0,0 +1,141 @@
#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 "displayapp/screens/Timer.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 WatchFaceMeow : public Screen {
public:
static constexpr int nLines = 9;
WatchFaceMeow(Controllers::DateTime& dateTimeController,
const Controllers::Battery& batteryController,
const Controllers::Ble& bleController,
Controllers::AlarmController& alarmController,
Controllers::Timer& timerController,
Controllers::NotificationManager& notificationManager,
Controllers::Settings& settingsController,
Controllers::MotionController& motionController,
Controllers::FS& fs);
~WatchFaceMeow() 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 {};
bool alarmState {};
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::minutes>> currentDateTime {};
bool timerRunning {};
Utility::DirtyValue<uint32_t> stepCount {};
Utility::DirtyValue<bool> notificationState {};
Utility::DirtyValue<std::chrono::time_point<std::chrono::system_clock, std::chrono::days>> currentDate;
// Lines making up the side cover
lv_obj_t* lineBattery;
lv_point_t lineBatteryPoints[2];
lv_obj_t* logoCat;
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* labelAlarm;
lv_obj_t* labelTimeAmPmAlarm;
lv_obj_t* alarmIcon;
lv_obj_t* labelTimer;
lv_obj_t* timerIcon;
lv_obj_t* pawIcon;
lv_obj_t* stepValue;
lv_obj_t* notificationIcon;
lv_obj_t* btnClose;
lv_obj_t* btnNextColor;
lv_obj_t* btnToggleCover;
lv_obj_t* btnToggleAlarm;
lv_obj_t* btnPrevColor;
lv_obj_t* btnSettings;
lv_obj_t* labelBtnSettings;
lv_obj_t* lblToggle;
lv_obj_t* lblAlarm;
lv_obj_t* lines[nLines];
Controllers::DateTime& dateTimeController;
const Controllers::Battery& batteryController;
const Controllers::Ble& bleController;
Controllers::AlarmController& alarmController;
Controllers::Timer& timerController;
Controllers::NotificationManager& notificationManager;
Controllers::Settings& settingsController;
Controllers::MotionController& motionController;
void SetBatteryLevel(uint8_t batteryPercent);
void ToggleBatteryIndicatorColor(bool showSideCover);
void ToggleShowAlarmStatus(bool showAlarmStatus);
lv_task_t* taskRefresh;
lv_font_t* font_teko = nullptr;
lv_font_t* font_bebas = nullptr;
};
}
template <>
struct WatchFaceTraits<WatchFace::Meow> {
static constexpr WatchFace watchFace = WatchFace::Meow;
static constexpr const char* name = "Meow face";
static Screens::Screen* Create(AppControllers& controllers) {
return new Screens::WatchFaceMeow(controllers.dateTimeController,
controllers.batteryController,
controllers.bleController,
controllers.alarmController,
controllers.timer,
controllers.notificationManager,
controllers.settingsController,
controllers.motionController,
controllers.filesystem);
};
static bool IsAvailable(Pinetime::Controllers::FS& filesystem) {
return Screens::WatchFaceMeow::IsAvailable(filesystem);
}
};
}
}

View file

@ -0,0 +1,11 @@
# Add a new watchface :
## Modify the following files with the names of your source files :
- /src/displayapp/apps/Apps.h.in
- /src/components/settings/Settings.h
- /src/displayapp/screens/settings/SettingWatchFace.h
- /src/displayapp/UserApps.h
- /src/displayapp/apps/CMakeLists.txt
- CMakelists.txt

View file

@ -10,8 +10,11 @@
#include "displayapp/screens/Symbols.h"
#include "displayapp/screens/CheckboxList.h"
#include "displayapp/screens/WatchFaceInfineat.h"
#include "displayapp/screens/WatchFaceMeow.h"
#include "displayapp/screens/WatchFaceCasioStyleG7710.h"
namespace Pinetime {
namespace Applications {

View file

@ -0,0 +1,4 @@
compare infineat and meow .h files to make declaration correct
faire en sorte to keep bell and not bell for inifneat wf
check the orig files and the files in lib if they need to be in git

View file

@ -126,13 +126,6 @@ Bma421::Values Bma421::Process() {
uint32_t steps = 0;
bma423_step_counter_output(&steps, &bma);
int32_t temperature;
bma4_get_temperature(&temperature, BMA4_DEG, &bma);
temperature = temperature / 1000;
uint8_t activity = 0;
bma423_activity_output(&activity, &bma);
// X and Y axis are swapped because of the way the sensor is mounted in the PineTime
return {steps, data.y, data.x, data.z};
}

View file

@ -1,3 +1,4 @@
#include <cstring>
#include "drivers/St7789.h"
#include <hal/nrf_gpio.h>
#include <nrfx_log.h>
@ -16,10 +17,9 @@ void St7789::Init() {
HardwareReset();
SoftwareReset();
SleepOut();
ColMod();
PixelFormat();
MemoryDataAccessControl();
ColumnAddressSet();
RowAddressSet();
SetAddrWindow(0, 0, Width, Height);
// P8B Mirrored version does not need display inversion.
#ifndef DRIVER_DISPLAY_MIRROR
DisplayInversionOn();
@ -97,8 +97,9 @@ void St7789::SleepIn() {
sleepIn = true;
}
void St7789::ColMod() {
WriteCommand(static_cast<uint8_t>(Commands::ColMod));
void St7789::PixelFormat() {
WriteCommand(static_cast<uint8_t>(Commands::PixelFormat));
// 65K colours, 16-bit per pixel
WriteData(0x55);
}
@ -118,22 +119,6 @@ void St7789::MemoryDataAccessControl() {
#endif
}
void St7789::ColumnAddressSet() {
WriteCommand(static_cast<uint8_t>(Commands::ColumnAddressSet));
WriteData(0x00);
WriteData(0x00);
WriteData(Width >> 8u);
WriteData(Width & 0xffu);
}
void St7789::RowAddressSet() {
WriteCommand(static_cast<uint8_t>(Commands::RowAddressSet));
WriteData(0x00);
WriteData(0x00);
WriteData(320u >> 8u);
WriteData(320u & 0xffu);
}
void St7789::DisplayInversionOn() {
WriteCommand(static_cast<uint8_t>(Commands::DisplayInversionOn));
}
@ -148,16 +133,23 @@ void St7789::DisplayOn() {
void St7789::SetAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
WriteCommand(static_cast<uint8_t>(Commands::ColumnAddressSet));
WriteData(x0 >> 8);
WriteData(x0 & 0xff);
WriteData(x1 >> 8);
WriteData(x1 & 0xff);
uint8_t colArgs[] = {
static_cast<uint8_t>(x0 >> 8), // x start MSB
static_cast<uint8_t>(x0), // x start LSB
static_cast<uint8_t>(x1 >> 8), // x end MSB
static_cast<uint8_t>(x1) // x end LSB
};
WriteData(colArgs, sizeof(colArgs));
WriteCommand(static_cast<uint8_t>(Commands::RowAddressSet));
WriteData(y0 >> 8);
WriteData(y0 & 0xff);
WriteData(y1 >> 8);
WriteData(y1 & 0xff);
uint8_t rowArgs[] = {
static_cast<uint8_t>(y0 >> 8), // y start MSB
static_cast<uint8_t>(y0), // y start LSB
static_cast<uint8_t>(y1 >> 8), // y end MSB
static_cast<uint8_t>(y1) // y end LSB
};
memcpy(addrWindowArgs, rowArgs, sizeof(rowArgs));
WriteData(addrWindowArgs, sizeof(addrWindowArgs));
}
void St7789::WriteToRam(const uint8_t* data, size_t size) {
@ -179,8 +171,12 @@ void St7789::DisplayOff() {
void St7789::VerticalScrollStartAddress(uint16_t line) {
verticalScrollingStartAddress = line;
WriteCommand(static_cast<uint8_t>(Commands::VerticalScrollStartAddress));
WriteData(line >> 8u);
WriteData(line & 0x00ffu);
uint8_t args[] = {
static_cast<uint8_t>(line >> 8), // Frame memory line pointer MSB
static_cast<uint8_t>(line) // Frame memory line pointer LSB
};
memcpy(verticalScrollArgs, args, sizeof(args));
WriteData(verticalScrollArgs, sizeof(verticalScrollArgs));
}
void St7789::Uninit() {

View file

@ -40,7 +40,7 @@ namespace Pinetime {
void SleepOut();
void EnsureSleepOutPostDelay();
void SleepIn();
void ColMod();
void PixelFormat();
void MemoryDataAccessControl();
void DisplayInversionOn();
void NormalModeOn();
@ -68,16 +68,17 @@ namespace Pinetime {
MemoryDataAccessControl = 0x36,
VerticalScrollDefinition = 0x33,
VerticalScrollStartAddress = 0x37,
ColMod = 0x3a,
PixelFormat = 0x3a,
VdvSet = 0xc4,
};
void WriteData(uint8_t data);
void WriteData(const uint8_t* data, size_t size);
void ColumnAddressSet();
static constexpr uint16_t Width = 240;
static constexpr uint16_t Height = 320;
void RowAddressSet();
uint8_t addrWindowArgs[4];
uint8_t verticalScrollArgs[2];
};
}
}

View file

@ -589,7 +589,7 @@ typedef void* lv_obj_user_data_t;
/*Calendar (dependencies: -)*/
#define LV_USE_CALENDAR 1
#if LV_USE_CALENDAR
#define LV_CALENDAR_WEEK_STARTS_MONDAY 0
#define LV_CALENDAR_WEEK_STARTS_MONDAY 1
#endif
/*Canvas (dependencies: lv_img)*/

View file

@ -1,11 +1,18 @@
{
"pine_small" : {
"pine_small" : {
"sources": "images/pine_logo.png",
"color_format": "CF_TRUE_COLOR_ALPHA",
"output_format": "bin",
"binary_format": "ARGB8565_RBSWAP",
"target_path": "/images/"
},
"cat_small" : {
"sources": "images/cat_clean.png",
"color_format": "CF_TRUE_COLOR_ALPHA",
"output_format": "bin",
"binary_format": "ARGB8565_RBSWAP",
"target_path": "/images/"
},
"navigation0" : {
"sources": "images/navigation0.png",
"color_format": "CF_INDEXED_1_BIT",

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -410,8 +410,6 @@ void SystemTask::Work() {
}
monitor.Process();
uint32_t systick_counter = nrf_rtc_counter_get(portNRF_RTC_REG);
dateTimeController.UpdateTime(systick_counter);
NoInit_BackUpTime = dateTimeController.CurrentDateTime();
if (nrf_gpio_pin_read(PinMap::Button) == 0) {
watchdog.Reload();

3
todo.log Normal file
View file

@ -0,0 +1,3 @@
replace alarm info by timer info when timer is ongoing
add a shortcut for a 1min timer on the right