Skip to content

Commit 49455f4

Browse files
Merge pull request #2 from AzureOrange404/dev
merge changes from development branch
2 parents ea44d8f + f0de88b commit 49455f4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+982
-674
lines changed

CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose Debug or Release")
55
project(pinetime VERSION 1.13.0 LANGUAGES C CXX ASM)
66

77
set(CMAKE_C_STANDARD 99)
8-
set(CMAKE_CXX_STANDARD 14)
8+
set(CMAKE_CXX_STANDARD 20)
99

1010
# set(CMAKE_GENERATOR "Unix Makefiles")
1111
set(CMAKE_C_EXTENSIONS OFF)

doc/code/Apps.md

+90-32
Original file line numberDiff line numberDiff line change
@@ -9,59 +9,114 @@ This page will teach you:
99

1010
The user interface of InfiniTime is made up of **screens**.
1111
Screens that are opened from the app launcher are considered **apps**.
12-
Every app in InfiniTime is it's own class.
12+
Every app in InfiniTime is its own class.
1313
An instance of the class is created when the app is launched, and destroyed when the user exits the app.
14-
Apps run inside the "displayapp" task (briefly discussed [here](./Intro.md)).
14+
Apps run inside the `DisplayApp` task (briefly discussed [here](./Intro.md)).
1515
Apps are responsible for everything drawn on the screen when they are running.
16-
By default, apps only do something (as in a function is executed) when they are created or when a touch event is detected.
16+
Apps can be refreshed periodically and reacts to external events (touch or button).
1717

1818
## Interface
1919

20-
Every app class has to be inside the namespace `Pinetime::Applications::Screens` and inherit from `Screen`.
21-
The constructor should have at least one parameter `DisplayApp* app`, which it needs for the constructor of its parent class Screen.
22-
Other parameters should be references to controllers that the app needs.
23-
A destructor is needed to clean up LVGL and restore any changes (for example re-enable sleeping).
24-
App classes can override `bool OnButtonPushed()`, `bool OnTouchEvent(TouchEvents event)` and `bool OnTouchEvent(uint16_t x, uint16_t y)` to implement their own functionality for those events.
25-
If an app only needs to display some text and do something upon a touch screen button press,
26-
it does not need to override any of these functions, as LVGL can also handle touch events for you.
27-
If you have any doubts, you can always look at how the other apps function for reference.
20+
Every app class is declared inside the namespace `Pinetime::Applications::Screens`
21+
and inherits
22+
from [`Pinetime::Applications::Screens::Screen`](https://github.com/InfiniTimeOrg/InfiniTime/blob/main/src/displayapp/screens/Screen.h).
2823

29-
### Continuous updating
24+
Each app defines its own constructor.
25+
The constructors mostly take references to InfiniTime `Controllers` (ex: Alarm, DateTime, BLE services, Settings,...)
26+
the app needs for its operations. The constructor is responsible for initializing the UI of the app.
3027

31-
If your app needs to be updated continuously, you can do so by overriding the `Refresh()` function in your class
32-
and calling `lv_task_create` inside the constructor.
28+
The **destructor** cleans up LVGL and restores any changes (for example re-enable sleeping).
3329

34-
An example call could look like this:
30+
App classes can override `bool OnButtonPushed()`, `bool OnTouchEvent(TouchEvents event)`
31+
and `bool OnTouchEvent(uint16_t x, uint16_t y)` to implement their own functionality for those events.
3532

36-
```cpp
37-
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
33+
Apps that need to be refreshed periodically create an `lv_task` (using `lv_task_create()`)
34+
that will call the method `Refresh()` periodically.
35+
36+
## App types
37+
38+
There are basically 2 types of applications : **system** apps and **user** apps.
39+
40+
**System** applications are always built into InfiniTime, and InfiniTime cannot work properly without those apps.
41+
The watchfaces, settings, notifications and the application launcher are examples of such system applications.
42+
43+
**User** applications are optionally built into the firmware. They extend the functionalities of the system.
44+
45+
The distinction between **system** and **user** applications allows for more flexibility and customization.
46+
This allows to easily select which user applications must be built into the firmware
47+
without overflowing the system memory.
48+
49+
## Apps initialization
50+
51+
Apps are created by `DisplayApp` in `DisplayApp::LoadScreen()`.
52+
This method simply call the creates an instance of the class that corresponds to the app specified in parameters.
53+
54+
The constructor of **system** apps is called directly. If the application is a **user** app,
55+
the corresponding `AppDescription` is first retrieved from `userApps`
56+
and then the function `create` is called to create an instance of the app.
57+
58+
## User application selection at build time
59+
60+
The list of user applications is generated at build time by the `consteval` function `CreateAppDescriptions()`
61+
in `UserApps.h`. This method takes the list of applications that must be built into the firmware image.
62+
This list of applications is defined as a list `Apps` enum values named `UserAppTypes` in `Apps.h`.
63+
For each application listed in `UserAppTypes`, an entry of type `AppDescription` is added to the array `userApps`.
64+
This entry is created by using the information provided by a template `AppTraits`
65+
that is customized for every user application.
66+
67+
Here is an example of an AppTraits customized for the Alarm application.
68+
It defines the type of application, its icon and a function that returns an instance of the application.
69+
70+
```c++
71+
template <>
72+
struct AppTraits<Apps::Alarm> {
73+
static constexpr Apps app = Apps::Alarm;
74+
static constexpr const char* icon = Screens::Symbols::clock;
75+
76+
static Screens::Screen* Create(AppControllers& controllers) {
77+
return new Screens::Alarm(controllers.alarmController,
78+
controllers.settingsController.GetClockType(),
79+
*controllers.systemTask,
80+
controllers.motorController);
81+
};
82+
};
3883
```
3984
40-
With `taskRefresh` being a member variable of your class and of type `lv_task_t*`.
41-
Remember to delete the task again using `lv_task_del`.
42-
The function `RefreshTaskCallback` is inherited from `Screen` and just calls your `Refresh` function.
85+
This array `userApps` is used by `DisplayApp` to create the applications and the `AppLauncher`
86+
to list all available applications.
4387
4488
## Creating your own app
4589
46-
A minimal app could look like this:
90+
A minimal user app could look like this:
4791
4892
MyApp.h:
4993
5094
```cpp
5195
#pragma once
5296
97+
#include "displayapp/Apps.h"
5398
#include "displayapp/screens/Screen.h"
54-
#include <lvgl/lvgl.h>
99+
#include "displayapp/Controllers.h"
100+
#include "Symbols.h"
55101
56102
namespace Pinetime {
57103
namespace Applications {
58104
namespace Screens {
59105
class MyApp : public Screen {
60106
public:
61-
MyApp(DisplayApp* app);
107+
MyApp();
62108
~MyApp() override;
63109
};
64110
}
111+
112+
template <>
113+
struct AppTraits<Apps:MyApp> {
114+
static constexpr Apps app = Apps::MyApp;
115+
static constexpr const char* icon = Screens::Symbol::myApp;
116+
static Screens::Screens* Create(AppController& controllers) {
117+
return new Screens::MyApp();
118+
}
119+
};
65120
}
66121
}
67122
```
@@ -70,11 +125,10 @@ MyApp.cpp:
70125

71126
```cpp
72127
#include "displayapp/screens/MyApp.h"
73-
#include "displayapp/DisplayApp.h"
74128

75129
using namespace Pinetime::Applications::Screens;
76130

77-
MyApp::MyApp(DisplayApp* app) : Screen(app) {
131+
MyApp::MyApp() {
78132
lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr);
79133
lv_label_set_text_static(title, "My test application");
80134
lv_label_set_align(title, LV_LABEL_ALIGN_CENTER);
@@ -86,20 +140,24 @@ MyApp::~MyApp() {
86140
}
87141
```
88142
89-
Both of these files should be in [displayapp/screens/](/src/displayapp/screens/)
90-
or [displayapp/screens/settings/](/src/displayapp/screens/settings/) if it's a setting app.
143+
Both of these files should be in [displayapp/screens/](/src/displayapp/screens/).
91144
92145
Now we have our very own app, but InfiniTime does not know about it yet.
93-
The first step is to include your MyApp.cpp (or any new cpp files for that matter)
146+
The first step is to include your `MyApp.cpp` (or any new cpp files for that matter)
94147
in the compilation by adding it to [CMakeLists.txt](/CMakeLists.txt).
95-
The next step to making it launchable is to give your app an id.
148+
The next step to making it launch-able is to give your app an id.
96149
To do this, add an entry in the enum class `Pinetime::Applications::Apps` ([displayapp/Apps.h](/src/displayapp/Apps.h)).
97-
Name this entry after your app. Add `#include "displayapp/screens/MyApp.h"` to the file [displayapp/DisplayApp.cpp](/src/displayapp/DisplayApp.cpp).
98-
Now, go to the function `DisplayApp::LoadScreen` and add another case to the switch statement.
150+
Name this entry after your app. Add `#include "displayapp/screens/MyApp.h"`
151+
to the file [displayapp/DisplayApp.cpp](/src/displayapp/DisplayApp.cpp).
152+
153+
If your application is a **system** application, go to the function `DisplayApp::LoadScreen`
154+
and add another case to the switch statement.
99155
The case will be the id you gave your app earlier.
100156
If your app needs any additional arguments, this is the place to pass them.
101157
102-
If you want to add your app in the app launcher, add your app in [displayapp/screens/ApplicationList.h](/src/displayapp/screens/ApplicationList.h) to the array containing the applications and their corresponding symbol. If your app is a setting, do the same procedure in [displayapp/screens/settings/Settings.h](/src/displayapp/screens/settings/Settings.h).
158+
If your application is a **user** application, you don't need to add anything in DisplayApp,
159+
everything will be automatically generated for you.
160+
The user application will also be automatically be added to the app launcher menu.
103161
104162
You should now be able to [build](../buildAndProgram.md) the firmware
105163
and flash it to your PineTime. Yay!

docker/Dockerfile

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,28 @@
11
FROM ubuntu:22.04
22

33
ARG DEBIAN_FRONTEND=noninteractive
4+
ARG NODE_MAJOR=20
45
RUN apt-get update -qq \
6+
&& apt-get install -y ca-certificates curl gnupg \
7+
&& mkdir -p /etc/apt/keyrings \
8+
&& curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \
9+
&& echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" > /etc/apt/sources.list.d/nodesource.list \
10+
&& apt-get update -qq \
511
&& apt-get install -y \
612
# x86_64 / generic packages
713
bash \
814
build-essential \
915
cmake \
1016
git \
1117
make \
18+
nodejs \
1219
python3 \
1320
python3-pip \
1421
python3-pil \
1522
python-is-python3 \
1623
tar \
1724
unzip \
1825
wget \
19-
curl \
2026
# aarch64 packages
2127
libffi-dev \
2228
libssl-dev \
@@ -29,8 +35,6 @@ RUN apt-get update -qq \
2935
libpango-1.0-0 \
3036
ibpango1.0-dev \
3137
libpangocairo-1.0-0 \
32-
&& curl -sL https://deb.nodesource.com/setup_18.x | bash - \
33-
&& apt-get install -y nodejs \
3438
&& rm -rf /var/cache/apt/* /var/lib/apt/lists/*;
3539

3640
# Git needed for PROJECT_GIT_COMMIT_HASH variable setting

src/CMakeLists.txt

-2
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,6 @@ list(APPEND SOURCE_FILES
394394
displayapp/screens/Notifications.cpp
395395
displayapp/screens/Twos.cpp
396396
displayapp/screens/HeartRate.cpp
397-
displayapp/screens/Motion.cpp
398397
displayapp/screens/FlashLight.cpp
399398
displayapp/screens/List.cpp
400399
displayapp/screens/CheckboxList.cpp
@@ -433,7 +432,6 @@ list(APPEND SOURCE_FILES
433432
displayapp/screens/WatchFaceTerminal.cpp
434433
displayapp/screens/WatchFacePineTimeStyle.cpp
435434
displayapp/screens/WatchFaceCasioStyleG7710.cpp
436-
displayapp/screens/WatchFaceSlowTime.cpp
437435

438436
##
439437

src/components/gfx/Gfx.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ void Gfx::SetBackgroundColor(uint16_t color) {
141141
bool Gfx::GetNextBuffer(uint8_t** data, size_t& size) {
142142
if (!state.busy)
143143
return false;
144-
state.remainingIterations--;
144+
state.remainingIterations = state.remainingIterations - 1;
145145
if (state.remainingIterations == 0) {
146146
state.busy = false;
147147
NotifyEndOfTransfer(state.taskToNotify);
@@ -170,7 +170,7 @@ bool Gfx::GetNextBuffer(uint8_t** data, size_t& size) {
170170
size = bytes_in_line * 8 * 2;
171171
}
172172

173-
state.currentIteration++;
173+
state.currentIteration = state.currentIteration + 1;
174174

175175
return true;
176176
}

src/components/settings/Settings.h

+28
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ namespace Pinetime {
3535
};
3636
enum class PTSGaugeStyle : uint8_t { Full, Half, Numeric };
3737
enum class PTSWeather : uint8_t { On, Off };
38+
enum class A24HourMode : uint8_t { On, Off };
39+
enum class ASecondHand : uint8_t { On, Off };
3840

3941
struct PineTimeStyle {
4042
Colors ColorTime = Colors::Teal;
@@ -44,6 +46,11 @@ namespace Pinetime {
4446
PTSWeather weatherEnable = PTSWeather::Off;
4547
};
4648

49+
struct Analog {
50+
A24HourMode tfHourEnable = A24HourMode::Off;
51+
ASecondHand secondHandEnable = ASecondHand::On;
52+
};
53+
4754
struct WatchFaceInfineat {
4855
bool showSideCover = true;
4956
int colorIndex = 0;
@@ -153,6 +160,26 @@ namespace Pinetime {
153160
return settings.PTS.weatherEnable;
154161
};
155162

163+
void SetA24HourMode(A24HourMode tfHourEnable) {
164+
if (tfHourEnable != settings.A.tfHourEnable)
165+
settingsChanged = true;
166+
settings.A.tfHourEnable = tfHourEnable;
167+
};
168+
169+
A24HourMode GetA24HourMode() const {
170+
return settings.A.tfHourEnable;
171+
};
172+
173+
void SetASecondHand(ASecondHand secondHandEnable) {
174+
if (secondHandEnable != settings.A.secondHandEnable)
175+
settingsChanged = true;
176+
settings.A.secondHandEnable = secondHandEnable;
177+
};
178+
179+
ASecondHand GetASecondHand() const {
180+
return settings.A.secondHandEnable;
181+
};
182+
156183
void SetAppMenu(uint8_t menu) {
157184
appMenu = menu;
158185
};
@@ -288,6 +315,7 @@ namespace Pinetime {
288315
ChimesOption chimesOption = ChimesOption::None;
289316

290317
PineTimeStyle PTS;
318+
Analog A;
291319

292320
WatchFaceInfineat watchFaceInfineat;
293321

src/displayapp/Apps.h

+28-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#pragma once
2-
2+
#include <cstddef>
33
namespace Pinetime {
44
namespace Applications {
55
enum class Apps {
@@ -37,7 +37,33 @@ namespace Pinetime {
3737
SettingChimes,
3838
SettingShakeThreshold,
3939
SettingBluetooth,
40-
Error
40+
Error,
41+
Weather
4142
};
43+
44+
template <Apps>
45+
struct AppTraits {};
46+
47+
template <Apps... As>
48+
struct TypeList {
49+
static constexpr size_t Count = sizeof...(As);
50+
};
51+
52+
using UserAppTypes = TypeList<Apps::Alarm,
53+
Apps::HeartRate,
54+
Apps::Paint,
55+
Apps::Metronome,
56+
Apps::Music,
57+
Apps::Navigation,
58+
Apps::Paddle,
59+
Apps::Steps,
60+
Apps::StopWatch,
61+
Apps::Timer,
62+
Apps::Twos
63+
/*
64+
Apps::Weather,
65+
Apps::Motion
66+
*/
67+
>;
4268
}
4369
}

0 commit comments

Comments
 (0)