2021-10-05 15:19:44 +02:00
# Apps
2022-08-21 13:50:09 +02:00
2021-10-05 15:19:44 +02:00
This page will teach you:
2022-08-21 13:50:09 +02:00
2021-11-08 17:11:29 +01:00
- what screens and apps are in InfiniTime
2021-10-05 15:19:44 +02:00
- how to implement your own app
## Theory
2021-11-08 17:11:29 +01:00
2021-11-08 17:13:27 +01:00
The user interface of InfiniTime is made up of **screens** .
Screens that are opened from the app launcher are considered **apps** .
2021-10-08 14:59:45 +02:00
Every app in InfiniTime is it's own class.
2021-12-05 17:41:01 +01:00
An instance of the class is created when the app is launched, and destroyed when the user exits the app.
Apps run inside the "displayapp" task (briefly discussed [here ](./Intro.md )).
2021-10-08 14:59:45 +02:00
Apps are responsible for everything drawn on the screen when they are running.
By default, apps only do something (as in a function is executed) when they are created or when a touch event is detected.
2021-10-05 15:19:44 +02:00
## Interface
2022-08-21 13:50:09 +02:00
2021-10-08 14:59:45 +02:00
Every app class has to be inside the namespace `Pinetime::Applications::Screens` and inherit from `Screen` .
The constructor should have at least one parameter `DisplayApp* app` , which it needs for the constructor of its parent class Screen.
Other parameters should be references to controllers that the app needs.
A destructor is needed to clean up LVGL and restore any changes (for example re-enable sleeping).
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.
If an app only needs to display some text and do something upon a touch screen button press,
it does not need to override any of these functions, as LVGL can also handle touch events for you.
2021-12-05 21:04:35 +01:00
If you have any doubts, you can always look at how the other apps function for reference.
2021-10-06 14:30:16 +02:00
### Continuous updating
2022-08-21 13:50:09 +02:00
2021-11-08 17:11:29 +01:00
If your app needs to be updated continuously, you can do so by overriding the `Refresh()` function in your class
2021-10-08 14:59:45 +02:00
and calling `lv_task_create` inside the constructor.
2021-10-06 14:30:16 +02:00
2021-11-08 17:11:29 +01:00
An example call could look like this:
2022-08-21 13:50:09 +02:00
2021-11-08 17:11:29 +01:00
```cpp
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
```
2021-10-06 14:30:16 +02:00
2021-11-08 17:11:29 +01:00
With `taskRefresh` being a member variable of your class and of type `lv_task_t*` .
Remember to delete the task again using `lv_task_del` .
The function `RefreshTaskCallback` is inherited from `Screen` and just calls your `Refresh` function.
2021-10-05 15:19:44 +02:00
## Creating your own app
2022-08-21 13:50:09 +02:00
2021-11-08 17:11:29 +01:00
A minimal app could look like this:
2021-10-05 15:19:44 +02:00
MyApp.h:
2022-08-21 13:50:09 +02:00
2021-10-05 15:19:44 +02:00
```cpp
#pragma once
#include "displayapp/screens/Screen.h"
2021-10-06 14:30:16 +02:00
#include <lvgl/lvgl.h>
2021-10-05 15:19:44 +02:00
2021-10-18 06:35:47 +02:00
namespace Pinetime {
2021-10-06 14:30:16 +02:00
namespace Applications {
namespace Screens {
class MyApp : public Screen {
public:
MyApp(DisplayApp* app);
~MyApp() override;
2021-10-18 18:18:35 +02:00
};
2021-10-05 15:19:44 +02:00
}
2021-10-06 14:30:16 +02:00
}
2021-10-05 15:19:44 +02:00
}
```
MyApp.cpp:
2022-08-21 13:50:09 +02:00
2021-10-05 15:19:44 +02:00
```cpp
2021-11-08 17:11:29 +01:00
#include "displayapp/screens/MyApp.h"
2021-10-05 15:19:44 +02:00
#include "displayapp/DisplayApp.h"
using namespace Pinetime::Applications::Screens;
MyApp::MyApp(DisplayApp* app) : Screen(app) {
2021-11-08 17:11:29 +01:00
lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr);
2021-10-06 18:29:52 +02:00
lv_label_set_text_static(title, "My test application");
2021-10-06 14:30:16 +02:00
lv_label_set_align(title, LV_LABEL_ALIGN_CENTER);
lv_obj_align(title, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
2021-10-05 15:19:44 +02:00
}
MyApp::~MyApp() {
2021-10-06 14:30:16 +02:00
lv_obj_clean(lv_scr_act());
2021-10-05 15:19:44 +02:00
}
```
2022-08-21 13:50:09 +02:00
2021-10-08 14:59:45 +02:00
Both of these files should be in [displayapp/screens/ ](/src/displayapp/screens/ )
or [displayapp/screens/settings/ ](/src/displayapp/screens/settings/ ) if it's a setting app.
Now we have our very own app, but InfiniTime does not know about it yet.
The first step is to include your MyApp.cpp (or any new cpp files for that matter)
in the compilation by adding it to [CMakeLists.txt ](/CMakeLists.txt ).
The next step to making it launchable is to give your app an id.
To do this, add an entry in the enum class `Pinetime::Applications::Apps` ([displayapp/Apps.h](/src/displayapp/Apps.h)).
Name this entry after your app. Add `#include "displayapp/screens/MyApp.h"` to the file [displayapp/DisplayApp.cpp ](/src/displayapp/DisplayApp.cpp ).
2023-01-18 17:04:27 +01:00
Now, go to the function `DisplayApp::LoadScreen` and add another case to the switch statement.
2021-10-08 14:59:45 +02:00
The case will be the id you gave your app earlier.
If your app needs any additional arguments, this is the place to pass them.
2022-09-01 01:21:56 +02:00
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 ).
2021-10-05 15:19:44 +02:00
2021-10-08 14:59:45 +02:00
You should now be able to [build ](../buildAndProgram.md ) the firmware
and flash it to your PineTime. Yay!
2021-10-06 18:29:52 +02:00
2021-10-08 14:59:45 +02:00
Please remember to pay attention to the [UI guidelines ](../ui_guidelines.md )
2021-11-08 17:11:29 +01:00
when designing an app that you want to be included in InfiniTime.