|
| 1 | +# Apps |
| 2 | +This page will teach you: |
| 3 | +- what apps in InfiniTime are |
| 4 | +- how to implement your own app |
| 5 | + |
| 6 | +## Theory |
| 7 | +Apps are the things you can launch from the app selection you get by swiping up. |
| 8 | +At the moment, settings and even the app launcher itself or the clock are implemented very similarly, this might change in the future though. |
| 9 | +Every app in InfiniTime is it's own class. |
| 10 | +An instance of the class is created when the app is launched and destroyed when the user exits the app. |
| 11 | +They run inside the "displayapp" task (briefly discussed [here](./Intro.md)). |
| 12 | +Apps are responsible for everything drawn on the screen when they are running. |
| 13 | +By default, apps only do something (as in a function is executed) when they are created or when a touch event is detected. |
| 14 | + |
| 15 | +## Interface |
| 16 | +Every app class has to be inside the namespace `Pinetime::Applications::Screens` and inherit from `Screen`. |
| 17 | +The constructor should have at least one parameter `DisplayApp* app`, which it needs for the constructor of its parent class Screen. |
| 18 | +Other parameters should be references to controllers that the app needs. |
| 19 | +A destructor is needed to clean up LVGL and restore any changes (for example re-enable sleeping). |
| 20 | +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. |
| 21 | +If an app only needs to display some text and do something upon a touch screen button press, |
| 22 | +it does not need to override any of these functions, as LVGL can also handle touch events for you. |
| 23 | +If you have any doubts, you can always look at how the other apps are doing things. |
| 24 | + |
| 25 | +### Continuous updating |
| 26 | +If your app needs to be updated continuously, yo can do so by overriding the `Refresh()` function in your class |
| 27 | +and calling `lv_task_create` inside the constructor. |
| 28 | +An example call could look like this: <br> |
| 29 | +`taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);` <br> |
| 30 | +With `taskRefresh` being a member variable of your class and of type `lv_task_t*`. |
| 31 | +Remember to delete the task again using `lv_task_del`. |
| 32 | +The function `RefreshTaskCallback` is inherited from screen and just calls your `Refresh` function. |
| 33 | + |
| 34 | +### Apps with multiple screens |
| 35 | +InfiniTime provides a mini-library in [displayapp/screens/ScreenList.h](/src/displayapp/screens/ScreenList.h) |
| 36 | +which makes it relatively easy to add multiple screens to your app. |
| 37 | +To use it, #include it in the header file of your app and add a ScreenList member to your class. |
| 38 | +The template argument should be the number of screens you need. |
| 39 | +You will also need to add `CreateScreen` functions that return `std::unique_ptr<Screen>` |
| 40 | +to your class, one for every screen you have. |
| 41 | +There are still some things left to to that I won't cover here. |
| 42 | +To figure them out, have a look at the "apps" ApplicationList, Settings and SystemInfo. |
| 43 | + |
| 44 | + |
| 45 | +## Creating your own app |
| 46 | +A minimal app could look like this: <br> |
| 47 | +MyApp.h: |
| 48 | +```cpp |
| 49 | +#pragma once |
| 50 | + |
| 51 | +#include "displayapp/screens/Screen.h" |
| 52 | +#include <lvgl/lvgl.h> |
| 53 | + |
| 54 | +namespace PineTime { |
| 55 | + namespace Applications { |
| 56 | + namespace Screens { |
| 57 | + class MyApp : public Screen { |
| 58 | + public: |
| 59 | + MyApp(DisplayApp* app); |
| 60 | + ~MyApp() override; |
| 61 | + } |
| 62 | + } |
| 63 | + } |
| 64 | +} |
| 65 | +``` |
| 66 | +
|
| 67 | +MyApp.cpp: |
| 68 | +```cpp |
| 69 | +#include "MyApp.h" |
| 70 | +#include "displayapp/DisplayApp.h" |
| 71 | +
|
| 72 | +using namespace Pinetime::Applications::Screens; |
| 73 | +
|
| 74 | +MyApp::MyApp(DisplayApp* app) : Screen(app) { |
| 75 | + lv_obj_t* title = lv_label_create(lv_scr_act(), NULL); |
| 76 | + lv_label_set_text_static(title, "My test application"); |
| 77 | + lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); |
| 78 | + lv_obj_align(title, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); |
| 79 | +} |
| 80 | +
|
| 81 | +MyApp::~MyApp() { |
| 82 | + lv_obj_clean(lv_scr_act()); |
| 83 | +} |
| 84 | +``` |
| 85 | +Both of these files should be in [displayapp/screens/](/src/displayapp/screens/) |
| 86 | +or [displayapp/screens/settings/](/src/displayapp/screens/settings/) if it's a setting app. |
| 87 | + |
| 88 | +Now we have our very own app, but InfiniTime does not know about it yet. |
| 89 | +The first step is to include your MyApp.cpp (or any new cpp files for that matter) |
| 90 | +in the compilation by adding it to [CMakeLists.txt](/CMakeLists.txt). |
| 91 | +The next step to making it launchable is to give your app an id. |
| 92 | +To do this, add an entry in the enum class `Pinetime::Applications::Apps` ([displayapp/Apps.h](/src/displayapp/Apps.h)). |
| 93 | +Name this entry after your app. Add `#include "displayapp/screens/MyApp.h"` to the file [displayapp/DisplayApp.cpp](/src/displayapp/DisplayApp.cpp). |
| 94 | +Now, go to the function `DisplayApp::LoadApp` and add another case to the switch statement. |
| 95 | +The case will be the id you gave your app earlier. |
| 96 | +If your app needs any additional arguments, this is the place to pass them. |
| 97 | + |
| 98 | +If you want your app to be launched from the regular app launcher, go to [displayapp/screens/ApplicationList.cpp](/src/displayapp/screens/ApplicationList.cpp). |
| 99 | +Add your app to one of the `CreateScreen` functions, or add another `CreateScreen` function if there are no empty spaces for your app. <br> |
| 100 | +If your app is a setting, do the same procedure in [displayapp/screens/settings/Settings.cpp](/src/displayapp/screens/settings/Settings.cpp). |
| 101 | + |
| 102 | +You should now be able to [build](../buildAndProgram.md) the firmware |
| 103 | +and flash it to your PineTime. Yay! |
| 104 | + |
| 105 | +Please remember to pay attention to the [UI guidelines](../ui_guidelines.md) |
| 106 | +when designing an app that you want to include in mainstream InfiniTime. |
0 commit comments