Compare commits
1 Commits
rei/develo
...
notificati
Author | SHA1 | Date | |
---|---|---|---|
|
b93438302e |
3
.github/workflows/format.yml
vendored
3
.github/workflows/format.yml
vendored
@ -7,7 +7,6 @@ on:
|
|||||||
- '**.cpp'
|
- '**.cpp'
|
||||||
- '**.h'
|
- '**.h'
|
||||||
- '!src/libs/**'
|
- '!src/libs/**'
|
||||||
- '!src/FreeRTOS/**'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test-format:
|
test-format:
|
||||||
@ -19,6 +18,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Configure git
|
- name: Configure git
|
||||||
run: |
|
run: |
|
||||||
|
git config --global user.email "-"
|
||||||
|
git config --global user.name "Autoformatter"
|
||||||
git fetch origin "$GITHUB_BASE_REF":"$GITHUB_BASE_REF" --depth=1000
|
git fetch origin "$GITHUB_BASE_REF":"$GITHUB_BASE_REF" --depth=1000
|
||||||
|
|
||||||
- name: Install clang-format
|
- name: Install clang-format
|
||||||
|
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@ -52,7 +52,7 @@
|
|||||||
"servertype": "openocd",
|
"servertype": "openocd",
|
||||||
"runToMain": true,
|
"runToMain": true,
|
||||||
// Only use armToolchainPath if your arm-none-eabi-gdb is not in your path (some GCC packages does not contain arm-none-eabi-gdb)
|
// Only use armToolchainPath if your arm-none-eabi-gdb is not in your path (some GCC packages does not contain arm-none-eabi-gdb)
|
||||||
"armToolchainPath": "${workspaceRoot}/../gcc-arm-11.2-2022.02-x86_64-arm-none-eabi/bin",
|
"armToolchainPath": "${workspaceRoot}/../gcc-arm-none-eabi-9-2020-q2-update/bin",
|
||||||
"svdFile": "${workspaceRoot}/nrf52.svd",
|
"svdFile": "${workspaceRoot}/nrf52.svd",
|
||||||
"configFiles": [
|
"configFiles": [
|
||||||
"interface/stlink.cfg",
|
"interface/stlink.cfg",
|
||||||
|
@ -51,9 +51,9 @@ Puncover is really easy to install:
|
|||||||
- `python -m virtualenv venv`
|
- `python -m virtualenv venv`
|
||||||
- `source venv/bin/activate`
|
- `source venv/bin/activate`
|
||||||
- Install : `pip install .`
|
- Install : `pip install .`
|
||||||
- Run : `puncover --gcc_tools_base=/path/to/gcc-arm-11.2-2022.02-x86_64-arm-none-eabi/bin/arm-none-eabi- --elf_file /path/to/build/directory/src/pinetime-app-1.1.0.out --src_root /path/to/sources --build_dir /path/to/build/directory`
|
- Run : `puncover --gcc_tools_base=/path/to/gcc-arm-none-eabi-9-2020-q2-update/bin/arm-none-eabi- --elf_file /path/to/build/directory/src/pinetime-app-1.1.0.out --src_root /path/to/sources --build_dir /path/to/build/directory`
|
||||||
- Replace
|
- Replace
|
||||||
* `/path/to/gcc-arm-11.2-2022.02-x86_64-arm-none-eabi/bin` with the path to your gcc-arm-none-eabi toolchain
|
* `/path/to/gcc-arm-none-eabi-9-2020-q2-update/bin` with the path to your gcc-arm-none-eabi toolchain
|
||||||
* `/path/to/build/directory/src/pinetime-app-1.1.0.out` with the path to the binary generated by GCC (.out file)
|
* `/path/to/build/directory/src/pinetime-app-1.1.0.out` with the path to the binary generated by GCC (.out file)
|
||||||
* `/path/to/sources` with the path to the root folder of the sources (checkout directory)
|
* `/path/to/sources` with the path to the root folder of the sources (checkout directory)
|
||||||
* `/path/to/build/directory` with the path to the build directory
|
* `/path/to/build/directory` with the path to the build directory
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# Build
|
# Build
|
||||||
## Dependencies
|
## Dependencies
|
||||||
To build this project, you'll need:
|
To build this project, you'll need:
|
||||||
- A cross-compiler : [ARM-GCC (arm-none-eabi 11.2-2022.02)](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/downloads)
|
- A cross-compiler : [ARM-GCC (9-2020-q2-update)](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads/9-2020-q2-update)
|
||||||
- The NRF52 SDK 15.3.0 : [nRF-SDK v15.3.0](https://developer.nordicsemi.com/nRF5_SDK/nRF5_SDK_v15.x.x/nRF5_SDK_15.3.0_59ac345.zip)
|
- The NRF52 SDK 15.3.0 : [nRF-SDK v15.3.0](https://developer.nordicsemi.com/nRF5_SDK/nRF5_SDK_v15.x.x/nRF5_SDK_15.3.0_59ac345.zip)
|
||||||
- The Python 3 modules `cbor`, `intelhex`, `click` and `cryptography` modules for the `mcuboot` tool (see [requirements.txt](../tools/mcuboot/requirements.txt))
|
- The Python 3 modules `cbor`, `intelhex`, `click` and `cryptography` modules for the `mcuboot` tool (see [requirements.txt](../tools/mcuboot/requirements.txt))
|
||||||
- To keep the system clean, you can install python modules into a python virtual environment (`venv`)
|
- To keep the system clean, you can install python modules into a python virtual environment (`venv`)
|
||||||
@ -31,7 +31,7 @@ CMake configures the project according to variables you specify the command line
|
|||||||
|
|
||||||
Variable | Description | Example|
|
Variable | Description | Example|
|
||||||
----------|-------------|--------|
|
----------|-------------|--------|
|
||||||
**ARM_NONE_EABI_TOOLCHAIN_PATH**|path to the toolchain directory|`-DARM_NONE_EABI_TOOLCHAIN_PATH=/home/jf/nrf52/gcc-arm-11.2-2022.02-x86_64-arm-none-eabi/`|
|
**ARM_NONE_EABI_TOOLCHAIN_PATH**|path to the toolchain directory|`-DARM_NONE_EABI_TOOLCHAIN_PATH=/home/jf/nrf52/gcc-arm-none-eabi-9-2020-q2-update/`|
|
||||||
**NRF5_SDK_PATH**|path to the NRF52 SDK|`-DNRF5_SDK_PATH=/home/jf/nrf52/Pinetime/sdk`|
|
**NRF5_SDK_PATH**|path to the NRF52 SDK|`-DNRF5_SDK_PATH=/home/jf/nrf52/Pinetime/sdk`|
|
||||||
**USE_JLINK, USE_GDB_CLIENT and USE_OPENOCD**|Enable *JLink* mode, *GDB Client* (Black Magic Probe) mode or *OpenOCD* mode (set the one you want to use to `1`)|`-DUSE_JLINK=1`
|
**USE_JLINK, USE_GDB_CLIENT and USE_OPENOCD**|Enable *JLink* mode, *GDB Client* (Black Magic Probe) mode or *OpenOCD* mode (set the one you want to use to `1`)|`-DUSE_JLINK=1`
|
||||||
**CMAKE_BUILD_TYPE (\*)**| Build type (Release or Debug). Release is applied by default if this variable is not specified.|`-DCMAKE_BUILD_TYPE=Debug`
|
**CMAKE_BUILD_TYPE (\*)**| Build type (Release or Debug). Release is applied by default if this variable is not specified.|`-DCMAKE_BUILD_TYPE=Debug`
|
||||||
|
@ -8,7 +8,7 @@ To support as many setups as possible the VS Code configuration files expect the
|
|||||||
|
|
||||||
Variable | Description | Example
|
Variable | Description | Example
|
||||||
----------|-------------|--------
|
----------|-------------|--------
|
||||||
**ARM_NONE_EABI_TOOLCHAIN_PATH**|path to the toolchain directory|`export ARM_NONE_EABI_TOOLCHAIN_PATH=/opt/gcc-arm-11.2-2022.02-x86_64-arm-none-eabi`
|
**ARM_NONE_EABI_TOOLCHAIN_PATH**|path to the toolchain directory|`export ARM_NONE_EABI_TOOLCHAIN_PATH=/opt/gcc-arm-none-eabi-9-2020-q2-update`
|
||||||
**NRF5_SDK_PATH**|path to the NRF52 SDK|`export NRF5_SDK_PATH=/opt/nRF5_SDK_15.3.0_59ac345`
|
**NRF5_SDK_PATH**|path to the NRF52 SDK|`export NRF5_SDK_PATH=/opt/nRF5_SDK_15.3.0_59ac345`
|
||||||
|
|
||||||
## VS Code Extensions
|
## VS Code Extensions
|
||||||
|
@ -18,7 +18,7 @@ You can sync the time using companion apps.
|
|||||||
|
|
||||||
You can also set the time in the settings without a companion app. (version >1.7.0)
|
You can also set the time in the settings without a companion app. (version >1.7.0)
|
||||||
|
|
||||||
InfiniTime doesn't handle daylight savings automatically, so make sure to set the correct time or sync it with a companion app.
|
InfiniTime doesn't handle daylight savings automatically, so make sure to set the correct the time or sync it with a companion app.
|
||||||
|
|
||||||
### Digital watch face
|
### Digital watch face
|
||||||
|
|
||||||
|
@ -12,20 +12,18 @@ export BUILD_DIR="${BUILD_DIR:=$SOURCES_DIR/build}"
|
|||||||
export OUTPUT_DIR="${OUTPUT_DIR:=$SOURCES_DIR/build/output}"
|
export OUTPUT_DIR="${OUTPUT_DIR:=$SOURCES_DIR/build/output}"
|
||||||
|
|
||||||
export BUILD_TYPE=${BUILD_TYPE:=Release}
|
export BUILD_TYPE=${BUILD_TYPE:=Release}
|
||||||
export GCC_ARM_VER=${GCC_ARM_VER:="11.2-2022.02"}
|
export GCC_ARM_VER=${GCC_ARM_VER:="gcc-arm-none-eabi-9-2020-q2-update"}
|
||||||
export NRF_SDK_VER=${NRF_SDK_VER:="nRF5_SDK_15.3.0_59ac345"}
|
export NRF_SDK_VER=${NRF_SDK_VER:="nRF5_SDK_15.3.0_59ac345"}
|
||||||
|
|
||||||
MACHINE="$(uname -m)"
|
MACHINE="$(uname -m)"
|
||||||
[[ "$MACHINE" == "arm64" ]] && MACHINE="aarch64"
|
[[ "$MACHINE" == "arm64" ]] && MACHINE="aarch64"
|
||||||
|
|
||||||
export GCC_ARM_PATH="gcc-arm-$GCC_ARM_VER-$MACHINE-arm-none-eabi"
|
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
local target="$1"
|
local target="$1"
|
||||||
|
|
||||||
mkdir -p "$TOOLS_DIR"
|
mkdir -p "$TOOLS_DIR"
|
||||||
|
|
||||||
[[ ! -d "$TOOLS_DIR/$GCC_ARM_PATH" ]] && GetGcc
|
[[ ! -d "$TOOLS_DIR/$GCC_ARM_VER" ]] && GetGcc
|
||||||
[[ ! -d "$TOOLS_DIR/$NRF_SDK_VER" ]] && GetNrfSdk
|
[[ ! -d "$TOOLS_DIR/$NRF_SDK_VER" ]] && GetNrfSdk
|
||||||
[[ ! -d "$TOOLS_DIR/mcuboot" ]] && GetMcuBoot
|
[[ ! -d "$TOOLS_DIR/mcuboot" ]] && GetMcuBoot
|
||||||
|
|
||||||
@ -40,7 +38,8 @@ main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
GetGcc() {
|
GetGcc() {
|
||||||
wget -q https://developer.arm.com/-/media/Files/downloads/gnu/$GCC_ARM_VER/binrel/$GCC_ARM_PATH.tar.xz -O - | tar -xJ -C $TOOLS_DIR/
|
GCC_SRC="$GCC_ARM_VER-$MACHINE-linux.tar.bz"
|
||||||
|
wget -q https://developer.arm.com/-/media/Files/downloads/gnu-rm/9-2020q2/$GCC_SRC -O - | tar -xj -C $TOOLS_DIR/
|
||||||
}
|
}
|
||||||
|
|
||||||
GetMcuBoot() {
|
GetMcuBoot() {
|
||||||
@ -60,7 +59,7 @@ CmakeGenerate() {
|
|||||||
-B "$BUILD_DIR" \
|
-B "$BUILD_DIR" \
|
||||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||||
-DUSE_OPENOCD=1 \
|
-DUSE_OPENOCD=1 \
|
||||||
-DARM_NONE_EABI_TOOLCHAIN_PATH="$TOOLS_DIR/$GCC_ARM_PATH" \
|
-DARM_NONE_EABI_TOOLCHAIN_PATH="$TOOLS_DIR/$GCC_ARM_VER" \
|
||||||
-DNRF5_SDK_PATH="$TOOLS_DIR/$NRF_SDK_VER" \
|
-DNRF5_SDK_PATH="$TOOLS_DIR/$NRF_SDK_VER" \
|
||||||
-DBUILD_DFU=1
|
-DBUILD_DFU=1
|
||||||
}
|
}
|
||||||
@ -73,4 +72,4 @@ CmakeBuild() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
[[ $SOURCED == "false" ]] && main "$@" || echo "Sourced!"
|
[[ $SOURCED == "false" ]] && main "$@" || echo "Sourced!"
|
@ -403,7 +403,6 @@ list(APPEND SOURCE_FILES
|
|||||||
displayapp/screens/Error.cpp
|
displayapp/screens/Error.cpp
|
||||||
displayapp/screens/Alarm.cpp
|
displayapp/screens/Alarm.cpp
|
||||||
displayapp/screens/Styles.cpp
|
displayapp/screens/Styles.cpp
|
||||||
displayapp/screens/Agenda.cpp
|
|
||||||
displayapp/Colors.cpp
|
displayapp/Colors.cpp
|
||||||
displayapp/widgets/Counter.cpp
|
displayapp/widgets/Counter.cpp
|
||||||
|
|
||||||
@ -458,7 +457,6 @@ list(APPEND SOURCE_FILES
|
|||||||
components/ble/MusicService.cpp
|
components/ble/MusicService.cpp
|
||||||
components/ble/weather/WeatherService.cpp
|
components/ble/weather/WeatherService.cpp
|
||||||
components/ble/NavigationService.cpp
|
components/ble/NavigationService.cpp
|
||||||
components/ble/AgendaService.cpp
|
|
||||||
components/ble/BatteryInformationService.cpp
|
components/ble/BatteryInformationService.cpp
|
||||||
components/ble/FSService.cpp
|
components/ble/FSService.cpp
|
||||||
components/ble/ImmediateAlertService.cpp
|
components/ble/ImmediateAlertService.cpp
|
||||||
@ -530,7 +528,6 @@ list(APPEND RECOVERY_SOURCE_FILES
|
|||||||
components/ble/ImmediateAlertService.cpp
|
components/ble/ImmediateAlertService.cpp
|
||||||
components/ble/ServiceDiscovery.cpp
|
components/ble/ServiceDiscovery.cpp
|
||||||
components/ble/NavigationService.cpp
|
components/ble/NavigationService.cpp
|
||||||
components/ble/AgendaService.cpp
|
|
||||||
components/ble/HeartRateService.cpp
|
components/ble/HeartRateService.cpp
|
||||||
components/ble/MotionService.cpp
|
components/ble/MotionService.cpp
|
||||||
components/firmwarevalidator/FirmwareValidator.cpp
|
components/firmwarevalidator/FirmwareValidator.cpp
|
||||||
|
@ -1,109 +0,0 @@
|
|||||||
/* Copyright (C) 2021 Adam Pigg
|
|
||||||
|
|
||||||
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 "components/ble/AgendaService.h"
|
|
||||||
|
|
||||||
#include "systemtask/SystemTask.h"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
// 3fdaYYXX-e246-472e-b7e0-d2b0f3d9c17a
|
|
||||||
constexpr ble_uuid128_t CharUuid(uint8_t x, uint8_t y) {
|
|
||||||
return ble_uuid128_t {.u = {.type = BLE_UUID_TYPE_128},
|
|
||||||
.value = {0x7a, 0xc1, 0xd9, 0xf3, 0xb0, 0xd2, 0xe0, 0xb7, 0x2e, 0x47, 0x46, 0xe2, x, y, 0xda, 0x3f}};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 00010000-78fc-48fe-8e23-433b3a1942d0
|
|
||||||
constexpr ble_uuid128_t BaseUuid() {
|
|
||||||
return CharUuid(0x00, 0x00);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr ble_uuid128_t agendaUuid {BaseUuid()};
|
|
||||||
|
|
||||||
constexpr ble_uuid128_t agendaItemCharUuid {CharUuid(0x01, 0x00)};
|
|
||||||
/*constexpr ble_uuid128_t navNarrativeCharUuid {CharUuid(0x02, 0x00)};
|
|
||||||
constexpr ble_uuid128_t navManDistCharUuid {CharUuid(0x03, 0x00)};
|
|
||||||
constexpr ble_uuid128_t navProgressCharUuid {CharUuid(0x04, 0x00)};*/
|
|
||||||
|
|
||||||
int AgendaCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
|
||||||
auto agendaService = static_cast<Pinetime::Controllers::AgendaService*>(arg);
|
|
||||||
return agendaService->OnCommand(conn_handle, attr_handle, ctxt);
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
Pinetime::Controllers::AgendaService::AgendaService(Pinetime::System::SystemTask& system) : m_system(system) {
|
|
||||||
characteristicDefinition[0] = {.uuid = &agendaItemCharUuid.u,
|
|
||||||
.access_cb = AgendaCallback,
|
|
||||||
.arg = this,
|
|
||||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
|
||||||
|
|
||||||
characteristicDefinition[1] = {0};
|
|
||||||
|
|
||||||
serviceDefinition[0] = {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = &agendaUuid.u, .characteristics = characteristicDefinition};
|
|
||||||
serviceDefinition[1] = {0};
|
|
||||||
}
|
|
||||||
|
|
||||||
void Pinetime::Controllers::AgendaService::Init() {
|
|
||||||
int res = 0;
|
|
||||||
res = ble_gatts_count_cfg(serviceDefinition);
|
|
||||||
ASSERT(res == 0);
|
|
||||||
|
|
||||||
res = ble_gatts_add_svcs(serviceDefinition);
|
|
||||||
ASSERT(res == 0);
|
|
||||||
|
|
||||||
m_agenda_times[0] = 1655327841;
|
|
||||||
m_agenda_pieces[0] = "C++ Fumbling";
|
|
||||||
}
|
|
||||||
|
|
||||||
int Pinetime::Controllers::AgendaService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
|
|
||||||
|
|
||||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
|
||||||
size_t notifSize = OS_MBUF_PKTLEN(ctxt->om);
|
|
||||||
uint8_t data[notifSize + 1];
|
|
||||||
data[notifSize] = '\0';
|
|
||||||
os_mbuf_copydata(ctxt->om, 0, notifSize, data);
|
|
||||||
if (ble_uuid_cmp(ctxt->chr->uuid, &agendaItemCharUuid.u) == 0) {
|
|
||||||
if (notifSize >= 5) {
|
|
||||||
uint8_t itemIndex = (uint8_t) data[0];
|
|
||||||
uint32_t itemTime = ((uint32_t) data[1]) << 24 | ((uint32_t) data[2]) << 16 | ((uint32_t) data[3]) << 8 | ((uint32_t) data[4]);
|
|
||||||
char* sAgendaItem = (char*) &data[5];
|
|
||||||
if (itemIndex < AGENDA_CAPACITY) { // don't allow a buffer overflow
|
|
||||||
m_agenda_times[itemIndex] = itemTime;
|
|
||||||
// implicit std::string copy/conversion here:
|
|
||||||
m_agenda_pieces[itemIndex] = sAgendaItem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t Pinetime::Controllers::AgendaService::getAgendaTime(uint8_t index) {
|
|
||||||
if (index < AGENDA_CAPACITY) {
|
|
||||||
return m_agenda_times[index];
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Pinetime::Controllers::AgendaService::getAgendaPiece(uint8_t index) {
|
|
||||||
if (index < AGENDA_CAPACITY) {
|
|
||||||
return m_agenda_pieces[index];
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
/* Copyright (C) 2021 Adam Pigg
|
|
||||||
|
|
||||||
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 <cstdint>
|
|
||||||
#include <string>
|
|
||||||
#define min // workaround: nimble's min/max macros conflict with libstdc++
|
|
||||||
#define max
|
|
||||||
#include <host/ble_gap.h>
|
|
||||||
#include <host/ble_uuid.h>
|
|
||||||
#undef max
|
|
||||||
#undef min
|
|
||||||
|
|
||||||
namespace Pinetime {
|
|
||||||
namespace System {
|
|
||||||
class SystemTask;
|
|
||||||
}
|
|
||||||
namespace Controllers {
|
|
||||||
|
|
||||||
class AgendaService {
|
|
||||||
public:
|
|
||||||
static const uint8_t AGENDA_CAPACITY = 35;
|
|
||||||
|
|
||||||
explicit AgendaService(Pinetime::System::SystemTask& system);
|
|
||||||
|
|
||||||
void Init();
|
|
||||||
|
|
||||||
int OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
|
|
||||||
|
|
||||||
uint32_t getAgendaTime(uint8_t index);
|
|
||||||
|
|
||||||
std::string getAgendaPiece(uint8_t index);
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct ble_gatt_chr_def characteristicDefinition[2];
|
|
||||||
struct ble_gatt_svc_def serviceDefinition[2];
|
|
||||||
|
|
||||||
uint32_t m_agenda_times[AGENDA_CAPACITY];
|
|
||||||
std::string m_agenda_pieces[AGENDA_CAPACITY];
|
|
||||||
|
|
||||||
Pinetime::System::SystemTask& m_system;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -51,7 +51,6 @@ NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask,
|
|||||||
heartRateService {systemTask, heartRateController},
|
heartRateService {systemTask, heartRateController},
|
||||||
motionService {systemTask, motionController},
|
motionService {systemTask, motionController},
|
||||||
fsService {systemTask, fs},
|
fsService {systemTask, fs},
|
||||||
agendaService {systemTask},
|
|
||||||
serviceDiscovery({¤tTimeClient, &alertNotificationClient}) {
|
serviceDiscovery({¤tTimeClient, &alertNotificationClient}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,7 +93,6 @@ void NimbleController::Init() {
|
|||||||
musicService.Init();
|
musicService.Init();
|
||||||
weatherService.Init();
|
weatherService.Init();
|
||||||
navService.Init();
|
navService.Init();
|
||||||
agendaService.Init();
|
|
||||||
anService.Init();
|
anService.Init();
|
||||||
dfuService.Init();
|
dfuService.Init();
|
||||||
batteryInformationService.Init();
|
batteryInformationService.Init();
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
#include "components/ble/NavigationService.h"
|
#include "components/ble/NavigationService.h"
|
||||||
#include "components/ble/ServiceDiscovery.h"
|
#include "components/ble/ServiceDiscovery.h"
|
||||||
#include "components/ble/MotionService.h"
|
#include "components/ble/MotionService.h"
|
||||||
#include "components/ble/AgendaService.h"
|
|
||||||
#include "components/ble/weather/WeatherService.h"
|
#include "components/ble/weather/WeatherService.h"
|
||||||
#include "components/fs/FS.h"
|
#include "components/fs/FS.h"
|
||||||
|
|
||||||
@ -62,9 +61,6 @@ namespace Pinetime {
|
|||||||
Pinetime::Controllers::NavigationService& navigation() {
|
Pinetime::Controllers::NavigationService& navigation() {
|
||||||
return navService;
|
return navService;
|
||||||
};
|
};
|
||||||
Pinetime::Controllers::AgendaService& agenda() {
|
|
||||||
return agendaService;
|
|
||||||
};
|
|
||||||
Pinetime::Controllers::AlertNotificationService& alertService() {
|
Pinetime::Controllers::AlertNotificationService& alertService() {
|
||||||
return anService;
|
return anService;
|
||||||
};
|
};
|
||||||
@ -107,7 +103,6 @@ namespace Pinetime {
|
|||||||
HeartRateService heartRateService;
|
HeartRateService heartRateService;
|
||||||
MotionService motionService;
|
MotionService motionService;
|
||||||
FSService fsService;
|
FSService fsService;
|
||||||
AgendaService agendaService;
|
|
||||||
ServiceDiscovery serviceDiscovery;
|
ServiceDiscovery serviceDiscovery;
|
||||||
|
|
||||||
uint8_t addrType;
|
uint8_t addrType;
|
||||||
|
@ -1,81 +1,86 @@
|
|||||||
#include "components/ble/NotificationManager.h"
|
#include "components/ble/NotificationManager.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
using namespace Pinetime::Controllers;
|
using namespace Pinetime::Controllers;
|
||||||
|
|
||||||
constexpr uint8_t NotificationManager::MessageSize;
|
constexpr uint8_t NotificationManager::MessageSize;
|
||||||
|
|
||||||
void NotificationManager::Push(NotificationManager::Notification&& notif) {
|
void NotificationManager::Push(NotificationManager::Notification&& notif) {
|
||||||
notif.id = GetNextId();
|
|
||||||
notif.valid = true;
|
notif.valid = true;
|
||||||
notifications[writeIndex] = std::move(notif);
|
|
||||||
writeIndex = (writeIndex + 1 < TotalNbNotifications) ? writeIndex + 1 : 0;
|
|
||||||
if (!empty)
|
|
||||||
readIndex = (readIndex + 1 < TotalNbNotifications) ? readIndex + 1 : 0;
|
|
||||||
else
|
|
||||||
empty = false;
|
|
||||||
|
|
||||||
newNotification = true;
|
newNotification = true;
|
||||||
|
if (begin_idx > 0) {
|
||||||
|
--begin_idx;
|
||||||
|
} else {
|
||||||
|
begin_idx = notifications.size() - 1;
|
||||||
|
}
|
||||||
|
notifications[begin_idx] = std::move(notif);
|
||||||
|
if (size_ < notifications.size()) {
|
||||||
|
size_++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NotificationManager::Notification NotificationManager::GetLastNotification() {
|
NotificationManager::Notification NotificationManager::GetLastNotification() {
|
||||||
NotificationManager::Notification notification = notifications[readIndex];
|
if (this->IsEmpty()) {
|
||||||
notification.index = 1;
|
|
||||||
return notification;
|
|
||||||
}
|
|
||||||
|
|
||||||
NotificationManager::Notification::Id NotificationManager::GetNextId() {
|
|
||||||
return nextId++;
|
|
||||||
}
|
|
||||||
|
|
||||||
NotificationManager::Notification NotificationManager::GetNext(NotificationManager::Notification::Id id) {
|
|
||||||
auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n) {
|
|
||||||
return n.valid && n.id == id;
|
|
||||||
});
|
|
||||||
if (currentIterator == notifications.end() || currentIterator->id != id)
|
|
||||||
return Notification {};
|
|
||||||
|
|
||||||
auto& lastNotification = notifications[readIndex];
|
|
||||||
|
|
||||||
NotificationManager::Notification result;
|
|
||||||
|
|
||||||
if (currentIterator == (notifications.end() - 1))
|
|
||||||
result = *(notifications.begin());
|
|
||||||
else
|
|
||||||
result = *(currentIterator + 1);
|
|
||||||
|
|
||||||
if (result.id <= id)
|
|
||||||
return {};
|
return {};
|
||||||
|
}
|
||||||
result.index = (lastNotification.id - result.id) + 1;
|
return this->At(0);
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NotificationManager::Notification NotificationManager::GetPrevious(NotificationManager::Notification::Id id) {
|
const NotificationManager::Notification& NotificationManager::At(NotificationManager::Notification::Id idx) const {
|
||||||
auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n) {
|
if (idx >= notifications.size()) {
|
||||||
return n.valid && n.id == id;
|
assert(false);
|
||||||
});
|
return notifications.at(begin_idx); // this should not happen
|
||||||
if (currentIterator == notifications.end() || currentIterator->id != id)
|
}
|
||||||
return Notification {};
|
size_t read_idx = (begin_idx + idx) % notifications.size();
|
||||||
|
return notifications.at(read_idx);
|
||||||
|
}
|
||||||
|
|
||||||
auto& lastNotification = notifications[readIndex];
|
NotificationManager::Notification& NotificationManager::At(NotificationManager::Notification::Id idx) {
|
||||||
|
if (idx >= notifications.size()) {
|
||||||
|
assert(false);
|
||||||
|
return notifications.at(begin_idx); // this should not happen
|
||||||
|
}
|
||||||
|
size_t read_idx = (begin_idx + idx) % notifications.size();
|
||||||
|
return notifications.at(read_idx);
|
||||||
|
}
|
||||||
|
|
||||||
NotificationManager::Notification result;
|
NotificationManager::Notification NotificationManager::GetNext(NotificationManager::Notification::Id idx) const {
|
||||||
|
if (idx == 0 || idx > notifications.size()) {
|
||||||
if (currentIterator == notifications.begin())
|
|
||||||
result = *(notifications.end() - 1);
|
|
||||||
else
|
|
||||||
result = *(currentIterator - 1);
|
|
||||||
|
|
||||||
if (result.id >= id)
|
|
||||||
return {};
|
return {};
|
||||||
|
}
|
||||||
result.index = (lastNotification.id - result.id) + 1;
|
return this->At(idx - 1);
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NotificationManager::AreNewNotificationsAvailable() {
|
NotificationManager::Notification NotificationManager::GetPrevious(NotificationManager::Notification::Id idx) const {
|
||||||
|
if (static_cast<size_t>(idx + 1) >= notifications.size()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return this->At(idx + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NotificationManager::Dismiss(NotificationManager::Notification::Id idx) {
|
||||||
|
if (this->IsEmpty())
|
||||||
|
return;
|
||||||
|
if (idx >= size_) {
|
||||||
|
assert(false);
|
||||||
|
return; // this should not happen
|
||||||
|
}
|
||||||
|
if (idx == 0) { // just remove the first element, don't need to change the other elements
|
||||||
|
notifications.at(begin_idx).valid = false;
|
||||||
|
begin_idx = (begin_idx + 1) % notifications.size();
|
||||||
|
} else {
|
||||||
|
// overwrite the specified entry by moving all later messages one index to the front
|
||||||
|
for (size_t i = idx; i < size_ - 1; ++i) {
|
||||||
|
this->At(i) = this->At(i + 1);
|
||||||
|
}
|
||||||
|
this->At(size_ - 1).valid = false;
|
||||||
|
}
|
||||||
|
--size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NotificationManager::AreNewNotificationsAvailable() const {
|
||||||
return newNotification;
|
return newNotification;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,9 +89,7 @@ bool NotificationManager::ClearNewNotificationFlag() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t NotificationManager::NbNotifications() const {
|
size_t NotificationManager::NbNotifications() const {
|
||||||
return std::count_if(notifications.begin(), notifications.end(), [](const Notification& n) {
|
return size_;
|
||||||
return n.valid;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* NotificationManager::Notification::Message() const {
|
const char* NotificationManager::Notification::Message() const {
|
||||||
|
@ -26,9 +26,7 @@ namespace Pinetime {
|
|||||||
|
|
||||||
struct Notification {
|
struct Notification {
|
||||||
using Id = uint8_t;
|
using Id = uint8_t;
|
||||||
Id id;
|
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
uint8_t index;
|
|
||||||
uint8_t size;
|
uint8_t size;
|
||||||
std::array<char, MessageSize + 1> message;
|
std::array<char, MessageSize + 1> message;
|
||||||
Categories category = Categories::Unknown;
|
Categories category = Categories::Unknown;
|
||||||
@ -36,27 +34,31 @@ namespace Pinetime {
|
|||||||
const char* Message() const;
|
const char* Message() const;
|
||||||
const char* Title() const;
|
const char* Title() const;
|
||||||
};
|
};
|
||||||
Notification::Id nextId {0};
|
|
||||||
|
|
||||||
void Push(Notification&& notif);
|
void Push(Notification&& notif);
|
||||||
Notification GetLastNotification();
|
Notification GetLastNotification();
|
||||||
Notification GetNext(Notification::Id id);
|
const Notification& At(Notification::Id id) const;
|
||||||
Notification GetPrevious(Notification::Id id);
|
Notification& At(Notification::Id id);
|
||||||
|
Notification GetNext(Notification::Id id) const;
|
||||||
|
Notification GetPrevious(Notification::Id id) const;
|
||||||
bool ClearNewNotificationFlag();
|
bool ClearNewNotificationFlag();
|
||||||
bool AreNewNotificationsAvailable();
|
bool AreNewNotificationsAvailable() const;
|
||||||
|
void Dismiss(Notification::Id id);
|
||||||
|
|
||||||
static constexpr size_t MaximumMessageSize() {
|
static constexpr size_t MaximumMessageSize() {
|
||||||
return MessageSize;
|
return MessageSize;
|
||||||
};
|
};
|
||||||
|
bool IsEmpty() const {
|
||||||
|
return size_ == 0;
|
||||||
|
}
|
||||||
size_t NbNotifications() const;
|
size_t NbNotifications() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Notification::Id GetNextId();
|
|
||||||
static constexpr uint8_t TotalNbNotifications = 5;
|
static constexpr uint8_t TotalNbNotifications = 5;
|
||||||
std::array<Notification, TotalNbNotifications> notifications;
|
std::array<Notification, TotalNbNotifications> notifications;
|
||||||
uint8_t readIndex = 0;
|
size_t begin_idx = TotalNbNotifications - 1; // index of the newest notification
|
||||||
uint8_t writeIndex = 0;
|
size_t size_ = 0; // number of valid notifications in buffer
|
||||||
bool empty = true;
|
|
||||||
std::atomic<bool> newNotification {false};
|
std::atomic<bool> newNotification {false};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -39,9 +39,7 @@ namespace Pinetime {
|
|||||||
SettingChimes,
|
SettingChimes,
|
||||||
SettingShakeThreshold,
|
SettingShakeThreshold,
|
||||||
SettingBluetooth,
|
SettingBluetooth,
|
||||||
Error,
|
Error
|
||||||
// oli: custom
|
|
||||||
Agenda
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,6 @@
|
|||||||
#include "displayapp/screens/PassKey.h"
|
#include "displayapp/screens/PassKey.h"
|
||||||
#include "displayapp/screens/Error.h"
|
#include "displayapp/screens/Error.h"
|
||||||
|
|
||||||
#include "displayapp/screens/Agenda.h"
|
|
||||||
|
|
||||||
#include "drivers/Cst816s.h"
|
#include "drivers/Cst816s.h"
|
||||||
#include "drivers/St7789.h"
|
#include "drivers/St7789.h"
|
||||||
#include "drivers/Watchdog.h"
|
#include "drivers/Watchdog.h"
|
||||||
@ -325,8 +323,7 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
|
|||||||
notificationManager,
|
notificationManager,
|
||||||
settingsController,
|
settingsController,
|
||||||
heartRateController,
|
heartRateController,
|
||||||
motionController,
|
motionController);
|
||||||
systemTask->nimble().agenda());
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Apps::Error:
|
case Apps::Error:
|
||||||
@ -477,10 +474,6 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
|
|||||||
case Apps::Steps:
|
case Apps::Steps:
|
||||||
currentScreen = std::make_unique<Screens::Steps>(this, motionController, settingsController);
|
currentScreen = std::make_unique<Screens::Steps>(this, motionController, settingsController);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Apps::Agenda:
|
|
||||||
currentScreen = std::make_unique<Screens::Agenda>(this, systemTask->nimble().agenda(), dateTimeController);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
currentApp = app;
|
currentApp = app;
|
||||||
}
|
}
|
||||||
@ -518,9 +511,6 @@ void DisplayApp::SetFullRefresh(DisplayApp::FullRefreshDirections direction) {
|
|||||||
case DisplayApp::FullRefreshDirections::RightAnim:
|
case DisplayApp::FullRefreshDirections::RightAnim:
|
||||||
lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::RightAnim);
|
lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::RightAnim);
|
||||||
break;
|
break;
|
||||||
// case DisplayApp::FullRefreshDirections::None:
|
|
||||||
// lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::None);
|
|
||||||
// break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"file": "FontAwesome5-Solid+Brands+Regular.woff",
|
"file": "FontAwesome5-Solid+Brands+Regular.woff",
|
||||||
"range": "0xf294, 0xf242, 0xf54b, 0xf21e, 0xf1e6, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf201, 0xf06e, 0xf015"
|
"range": "0xf294, 0xf242, 0xf54b, 0xf21e, 0xf1e6, 0xf54b, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf201, 0xf06e, 0xf015"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"bpp": 1,
|
"bpp": 1,
|
||||||
|
@ -1,147 +0,0 @@
|
|||||||
#include "displayapp/screens/Agenda.h"
|
|
||||||
#include <date/date.h>
|
|
||||||
#include <nrf_log.h>
|
|
||||||
|
|
||||||
using Pinetime::Applications::TouchEvents;
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
|
||||||
|
|
||||||
using namespace Pinetime::Controllers;
|
|
||||||
|
|
||||||
Agenda::Agenda(DisplayApp* app, AgendaService& agenda, Controllers::DateTime& dateTimeController) : Screen(app), agendaSvc(agenda), dateTimeController(dateTimeController) {
|
|
||||||
lv_obj_t* alignNextTo = lv_scr_act();
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < AGENDA_ONSCREEN; ++i) {
|
|
||||||
lv_obj_t* agendaItem = lv_label_create(lv_scr_act(), nullptr);
|
|
||||||
lv_label_set_text_static(agendaItem, ".\n.");
|
|
||||||
//lv_label_set_align(agendaItem, LV_LABEL_ALIGN_CENTER);
|
|
||||||
if (i != 0) {
|
|
||||||
lv_obj_align(agendaItem, alignNextTo, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
agendaItems[i] = agendaItem;
|
|
||||||
alignNextTo = agendaItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
pagingOffset = 0;
|
|
||||||
|
|
||||||
using namespace date;
|
|
||||||
using namespace std::chrono;
|
|
||||||
|
|
||||||
std::chrono::system_clock::time_point nowTp = dateTimeController.CurrentDateTime();
|
|
||||||
//sys_seconds now = nowTp;
|
|
||||||
|
|
||||||
// Find first entry that is just after the current time (- 5 min)!
|
|
||||||
for (uint8_t i = 0; i < AgendaService::AGENDA_CAPACITY; ++i) {
|
|
||||||
uint32_t time = agendaSvc.getAgendaTime(i);
|
|
||||||
sys_seconds timestamp = sys_days{1970_y/1/1} + seconds{time};
|
|
||||||
|
|
||||||
if (timestamp > nowTp - minutes{5}) {
|
|
||||||
uint8_t positionInPage = i % AGENDA_ONSCREEN;
|
|
||||||
pagingOffset = i - positionInPage;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
|
|
||||||
Relabel();
|
|
||||||
//Refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Agenda::OnTouchEvent(TouchEvents event) {
|
|
||||||
// NRF_LOG_INFO("touch");
|
|
||||||
switch (event) {
|
|
||||||
case TouchEvents::SwipeDown:
|
|
||||||
if (pagingOffset >= AGENDA_ONSCREEN) {
|
|
||||||
// NRF_LOG_INFO("swdn");
|
|
||||||
pagingOffset -= AGENDA_ONSCREEN;
|
|
||||||
app->SetFullRefresh(DisplayApp::FullRefreshDirections::Down);
|
|
||||||
Relabel();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TouchEvents::SwipeUp:
|
|
||||||
if (pagingOffset + 2*AGENDA_ONSCREEN <= AgendaService::AGENDA_CAPACITY) {
|
|
||||||
// NRF_LOG_INFO("swup");
|
|
||||||
pagingOffset += AGENDA_ONSCREEN;
|
|
||||||
app->SetFullRefresh(DisplayApp::FullRefreshDirections::Up);
|
|
||||||
Relabel();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Agenda::~Agenda() {
|
|
||||||
lv_task_del(taskRefresh);
|
|
||||||
lv_obj_clean(lv_scr_act());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Agenda::Relabel() {
|
|
||||||
using namespace date;
|
|
||||||
using namespace std::chrono;
|
|
||||||
std::chrono::system_clock::time_point now = dateTimeController.CurrentDateTime();
|
|
||||||
auto todayDate = floor<date::days>(now);
|
|
||||||
//auto nowTimePart = make_time(now - todayDate);
|
|
||||||
|
|
||||||
//auto todayYmd = year_month_day(todayDate);
|
|
||||||
// NRF_LOG_INFO("date CURRENT %d-%u-%u %ldh%ldh%ld", (int) todayYmd.year(), (unsigned) todayYmd.month(), (unsigned) todayYmd.day(), nowTimePart.hours().count(), nowTimePart.minutes().count(), nowTimePart.seconds().count());
|
|
||||||
|
|
||||||
//std::cout << todayDate << ' ' << nowTimePart << '\n';
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < AGENDA_ONSCREEN; ++i) {
|
|
||||||
uint8_t itemIdx = i + pagingOffset;
|
|
||||||
uint32_t time = agendaSvc.getAgendaTime(itemIdx);
|
|
||||||
|
|
||||||
lv_obj_t* agendaItem = agendaItems[i];
|
|
||||||
|
|
||||||
if (time == 0) {
|
|
||||||
lv_label_set_text_static(agendaItem, "--h--\n .....");
|
|
||||||
lv_obj_set_style_local_text_color(agendaItem, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x332222));
|
|
||||||
} else {
|
|
||||||
sys_seconds timestamp = sys_days{1970_y/1/1} + seconds{time};
|
|
||||||
//auto timestamp = std::chrono::system_clock::time_point{time * 1s};
|
|
||||||
sys_days agendaDate = floor<days>(timestamp);
|
|
||||||
time_of_day<seconds> agendaTimePart = make_time(timestamp - agendaDate);
|
|
||||||
year_month_day ymd = year_month_day(agendaDate);
|
|
||||||
//std::cout << agendaDate << ' ' << agendaTimePart << '\n';
|
|
||||||
|
|
||||||
/*std::time_t result = std::time(nullptr);
|
|
||||||
std::time_t result = std::time(nullptr);
|
|
||||||
std::chrono::time_point = */;
|
|
||||||
|
|
||||||
// NRF_LOG_INFO("IDX %u", itemIdx);
|
|
||||||
// NRF_LOG_INFO("unix %u", time);
|
|
||||||
// NRF_LOG_INFO("date %d-%u-%u ", (int) ymd.year(), (unsigned) ymd.month(), (unsigned) ymd.day());
|
|
||||||
// NRF_LOG_INFO("time %ldh%ldm%ld", agendaTimePart.hours().count(), agendaTimePart.minutes().count(), agendaTimePart.seconds().count());
|
|
||||||
// NRF_LOG_INFO("item %s", agendaSvc.getAgendaPiece(itemIdx).data());
|
|
||||||
|
|
||||||
if (agendaDate == todayDate) {
|
|
||||||
lv_label_set_text_fmt(agendaItem, "%02lldh%02lld\n %s", agendaTimePart.hours().count(), agendaTimePart.minutes().count(), agendaSvc.getAgendaPiece(itemIdx).data());
|
|
||||||
} else {
|
|
||||||
lv_label_set_text_fmt(agendaItem, "%04d-%02u-%02u %02lldh%02lld\n %s", (int) ymd.year(), (unsigned) ymd.month(), (unsigned) ymd.day(), agendaTimePart.hours().count(), agendaTimePart.minutes().count(), agendaSvc.getAgendaPiece(itemIdx).data());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timestamp + 30min < now) {
|
|
||||||
lv_obj_set_style_local_text_color(agendaItem, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x334433));
|
|
||||||
} else if (timestamp + 5min < now) {
|
|
||||||
lv_obj_set_style_local_text_color(agendaItem, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7));
|
|
||||||
} else if (timestamp - 5min < now && now < timestamp + 5min) {
|
|
||||||
lv_obj_set_style_local_text_color(agendaItem, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFFA500));
|
|
||||||
} else if (now + 5min < timestamp) {
|
|
||||||
lv_obj_set_style_local_text_color(agendaItem, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFFFF00));
|
|
||||||
} else if (now + 30min < timestamp) {
|
|
||||||
lv_obj_set_style_local_text_color(agendaItem, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFFFFFF));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Refresh seems to refer to re-render, but changing any LVGL widgets triggers a refresh again! */
|
|
||||||
void Agenda::Refresh() {
|
|
||||||
//NRF_LOG_INFO("refr");
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "displayapp/screens/Screen.h"
|
|
||||||
#include "components/ble/AgendaService.h"
|
|
||||||
#include "displayapp/DisplayApp.h"
|
|
||||||
#include "components/datetime/DateTimeController.h"
|
|
||||||
#include <lvgl/lvgl.h>
|
|
||||||
|
|
||||||
namespace Pinetime {
|
|
||||||
namespace Controllers {
|
|
||||||
class DateTime;
|
|
||||||
}
|
|
||||||
namespace Applications {
|
|
||||||
namespace Screens {
|
|
||||||
class Agenda : public Screen {
|
|
||||||
public:
|
|
||||||
static const uint8_t AGENDA_ONSCREEN = 5;
|
|
||||||
|
|
||||||
Agenda(DisplayApp* app, Pinetime::Controllers::AgendaService& agendaSvc, Pinetime::Controllers::DateTime &dateTimeController);
|
|
||||||
~Agenda() override;
|
|
||||||
|
|
||||||
bool OnTouchEvent(TouchEvents event) override;
|
|
||||||
|
|
||||||
void Refresh() override;
|
|
||||||
|
|
||||||
void Relabel();
|
|
||||||
|
|
||||||
private:
|
|
||||||
Pinetime::Controllers::AgendaService& agendaSvc;
|
|
||||||
|
|
||||||
Controllers::DateTime& dateTimeController;
|
|
||||||
|
|
||||||
lv_obj_t* agendaItems[AGENDA_ONSCREEN];
|
|
||||||
uint8_t pagingOffset;
|
|
||||||
|
|
||||||
lv_task_t* taskRefresh;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -25,9 +25,6 @@ ApplicationList::ApplicationList(Pinetime::Applications::DisplayApp* app,
|
|||||||
[this]() -> std::unique_ptr<Screen> {
|
[this]() -> std::unique_ptr<Screen> {
|
||||||
return CreateScreen2();
|
return CreateScreen2();
|
||||||
},
|
},
|
||||||
[this]() -> std::unique_ptr<Screen> {
|
|
||||||
return CreateScreen3();
|
|
||||||
},
|
|
||||||
//[this]() -> std::unique_ptr<Screen> { return CreateScreen3(); }
|
//[this]() -> std::unique_ptr<Screen> { return CreateScreen3(); }
|
||||||
},
|
},
|
||||||
Screens::ScreenListModes::UpDown} {
|
Screens::ScreenListModes::UpDown} {
|
||||||
@ -51,7 +48,7 @@ std::unique_ptr<Screen> ApplicationList::CreateScreen1() {
|
|||||||
{Symbols::music, Apps::Music},
|
{Symbols::music, Apps::Music},
|
||||||
}};
|
}};
|
||||||
|
|
||||||
return std::make_unique<Screens::Tile>(0, 3, app, settingsController, batteryController, dateTimeController, applications);
|
return std::make_unique<Screens::Tile>(0, 2, app, settingsController, batteryController, dateTimeController, applications);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Screen> ApplicationList::CreateScreen2() {
|
std::unique_ptr<Screen> ApplicationList::CreateScreen2() {
|
||||||
@ -64,20 +61,7 @@ std::unique_ptr<Screen> ApplicationList::CreateScreen2() {
|
|||||||
{Symbols::map, Apps::Navigation},
|
{Symbols::map, Apps::Navigation},
|
||||||
}};
|
}};
|
||||||
|
|
||||||
return std::make_unique<Screens::Tile>(1, 3, app, settingsController, batteryController, dateTimeController, applications);
|
return std::make_unique<Screens::Tile>(1, 2, app, settingsController, batteryController, dateTimeController, applications);
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<Screen> ApplicationList::CreateScreen3() {
|
|
||||||
std::array<Screens::Tile::Applications, 6> applications {{
|
|
||||||
{"A", Apps::Agenda},
|
|
||||||
{".", Apps::Paddle},
|
|
||||||
{".", Apps::Twos},
|
|
||||||
{".", Apps::Motion},
|
|
||||||
{".", Apps::Metronome},
|
|
||||||
{".", Apps::Navigation},
|
|
||||||
}};
|
|
||||||
|
|
||||||
return std::make_unique<Screens::Tile>(2, 3, app, settingsController, batteryController, dateTimeController, applications);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*std::unique_ptr<Screen> ApplicationList::CreateScreen3() {
|
/*std::unique_ptr<Screen> ApplicationList::CreateScreen3() {
|
||||||
|
@ -25,10 +25,10 @@ namespace Pinetime {
|
|||||||
Pinetime::Controllers::Battery& batteryController;
|
Pinetime::Controllers::Battery& batteryController;
|
||||||
Controllers::DateTime& dateTimeController;
|
Controllers::DateTime& dateTimeController;
|
||||||
|
|
||||||
ScreenList<3> screens;
|
ScreenList<2> screens;
|
||||||
std::unique_ptr<Screen> CreateScreen1();
|
std::unique_ptr<Screen> CreateScreen1();
|
||||||
std::unique_ptr<Screen> CreateScreen2();
|
std::unique_ptr<Screen> CreateScreen2();
|
||||||
std::unique_ptr<Screen> CreateScreen3();
|
// std::unique_ptr<Screen> CreateScreen3();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,7 @@ Clock::Clock(DisplayApp* app,
|
|||||||
Controllers::NotificationManager& notificatioManager,
|
Controllers::NotificationManager& notificatioManager,
|
||||||
Controllers::Settings& settingsController,
|
Controllers::Settings& settingsController,
|
||||||
Controllers::HeartRateController& heartRateController,
|
Controllers::HeartRateController& heartRateController,
|
||||||
Controllers::MotionController& motionController,
|
Controllers::MotionController& motionController)
|
||||||
Controllers::AgendaService& agendaService)
|
|
||||||
: Screen(app),
|
: Screen(app),
|
||||||
dateTimeController {dateTimeController},
|
dateTimeController {dateTimeController},
|
||||||
batteryController {batteryController},
|
batteryController {batteryController},
|
||||||
@ -32,7 +31,6 @@ Clock::Clock(DisplayApp* app,
|
|||||||
settingsController {settingsController},
|
settingsController {settingsController},
|
||||||
heartRateController {heartRateController},
|
heartRateController {heartRateController},
|
||||||
motionController {motionController},
|
motionController {motionController},
|
||||||
agendaService {agendaService},
|
|
||||||
screen {[this, &settingsController]() {
|
screen {[this, &settingsController]() {
|
||||||
switch (settingsController.GetClockFace()) {
|
switch (settingsController.GetClockFace()) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -73,8 +71,7 @@ std::unique_ptr<Screen> Clock::WatchFaceDigitalScreen() {
|
|||||||
notificatioManager,
|
notificatioManager,
|
||||||
settingsController,
|
settingsController,
|
||||||
heartRateController,
|
heartRateController,
|
||||||
motionController,
|
motionController);
|
||||||
agendaService);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Screen> Clock::WatchFaceAnalogScreen() {
|
std::unique_ptr<Screen> Clock::WatchFaceAnalogScreen() {
|
||||||
|
@ -15,7 +15,6 @@ namespace Pinetime {
|
|||||||
class Ble;
|
class Ble;
|
||||||
class NotificationManager;
|
class NotificationManager;
|
||||||
class MotionController;
|
class MotionController;
|
||||||
class AgendaService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Applications {
|
namespace Applications {
|
||||||
@ -29,8 +28,7 @@ namespace Pinetime {
|
|||||||
Controllers::NotificationManager& notificatioManager,
|
Controllers::NotificationManager& notificatioManager,
|
||||||
Controllers::Settings& settingsController,
|
Controllers::Settings& settingsController,
|
||||||
Controllers::HeartRateController& heartRateController,
|
Controllers::HeartRateController& heartRateController,
|
||||||
Controllers::MotionController& motionController,
|
Controllers::MotionController& motionController);
|
||||||
Controllers::AgendaService& agendaService);
|
|
||||||
~Clock() override;
|
~Clock() override;
|
||||||
|
|
||||||
bool OnTouchEvent(TouchEvents event) override;
|
bool OnTouchEvent(TouchEvents event) override;
|
||||||
@ -44,7 +42,6 @@ namespace Pinetime {
|
|||||||
Controllers::Settings& settingsController;
|
Controllers::Settings& settingsController;
|
||||||
Controllers::HeartRateController& heartRateController;
|
Controllers::HeartRateController& heartRateController;
|
||||||
Controllers::MotionController& motionController;
|
Controllers::MotionController& motionController;
|
||||||
Controllers::AgendaService& agendaService;
|
|
||||||
|
|
||||||
std::unique_ptr<Screen> screen;
|
std::unique_ptr<Screen> screen;
|
||||||
std::unique_ptr<Screen> WatchFaceDigitalScreen();
|
std::unique_ptr<Screen> WatchFaceDigitalScreen();
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "components/ble/MusicService.h"
|
#include "components/ble/MusicService.h"
|
||||||
#include "components/ble/AlertNotificationService.h"
|
#include "components/ble/AlertNotificationService.h"
|
||||||
#include "displayapp/screens/Symbols.h"
|
#include "displayapp/screens/Symbols.h"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
using namespace Pinetime::Applications::Screens;
|
using namespace Pinetime::Applications::Screens;
|
||||||
extern lv_font_t jetbrains_mono_extrabold_compressed;
|
extern lv_font_t jetbrains_mono_extrabold_compressed;
|
||||||
@ -20,13 +21,14 @@ Notifications::Notifications(DisplayApp* app,
|
|||||||
motorController {motorController},
|
motorController {motorController},
|
||||||
systemTask {systemTask},
|
systemTask {systemTask},
|
||||||
mode {mode} {
|
mode {mode} {
|
||||||
|
|
||||||
notificationManager.ClearNewNotificationFlag();
|
notificationManager.ClearNewNotificationFlag();
|
||||||
auto notification = notificationManager.GetLastNotification();
|
auto notification = notificationManager.GetLastNotification();
|
||||||
|
currentId = 0;
|
||||||
if (notification.valid) {
|
if (notification.valid) {
|
||||||
currentId = notification.id;
|
|
||||||
currentItem = std::make_unique<NotificationItem>(notification.Title(),
|
currentItem = std::make_unique<NotificationItem>(notification.Title(),
|
||||||
notification.Message(),
|
notification.Message(),
|
||||||
notification.index,
|
1,
|
||||||
notification.category,
|
notification.category,
|
||||||
notificationManager.NbNotifications(),
|
notificationManager.NbNotifications(),
|
||||||
mode,
|
mode,
|
||||||
@ -34,14 +36,7 @@ Notifications::Notifications(DisplayApp* app,
|
|||||||
motorController);
|
motorController);
|
||||||
validDisplay = true;
|
validDisplay = true;
|
||||||
} else {
|
} else {
|
||||||
currentItem = std::make_unique<NotificationItem>("Notification",
|
currentItem = std::make_unique<NotificationItem>(notification.category, alertNotificationService, motorController);
|
||||||
"No notification to display",
|
|
||||||
0,
|
|
||||||
notification.category,
|
|
||||||
notificationManager.NbNotifications(),
|
|
||||||
Modes::Preview,
|
|
||||||
alertNotificationService,
|
|
||||||
motorController);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode == Modes::Preview) {
|
if (mode == Modes::Preview) {
|
||||||
@ -77,7 +72,7 @@ Notifications::~Notifications() {
|
|||||||
void Notifications::Refresh() {
|
void Notifications::Refresh() {
|
||||||
if (mode == Modes::Preview && timeoutLine != nullptr) {
|
if (mode == Modes::Preview && timeoutLine != nullptr) {
|
||||||
TickType_t tick = xTaskGetTickCount();
|
TickType_t tick = xTaskGetTickCount();
|
||||||
int32_t pos = 240 - ((tick - timeoutTickCountStart) / (timeoutLength / 240));
|
int32_t pos = LV_HOR_RES - ((tick - timeoutTickCountStart) / (timeoutLength / LV_HOR_RES));
|
||||||
if (pos <= 0) {
|
if (pos <= 0) {
|
||||||
running = false;
|
running = false;
|
||||||
} else {
|
} else {
|
||||||
@ -85,6 +80,36 @@ void Notifications::Refresh() {
|
|||||||
lv_line_set_points(timeoutLine, timeoutLinePoints, 2);
|
lv_line_set_points(timeoutLine, timeoutLinePoints, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currentItem != nullptr && currentItem->AnimationElapsed()) {
|
||||||
|
auto notification = notificationManager.At(currentId);
|
||||||
|
if (!notification.valid) {
|
||||||
|
notification = notificationManager.GetLastNotification();
|
||||||
|
currentId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!notification.valid) {
|
||||||
|
validDisplay = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentItem.reset(nullptr);
|
||||||
|
app->SetFullRefresh(DisplayApp::FullRefreshDirections::Up);
|
||||||
|
|
||||||
|
if (validDisplay) {
|
||||||
|
currentItem = std::make_unique<NotificationItem>(notification.Title(),
|
||||||
|
notification.Message(),
|
||||||
|
currentId + 1,
|
||||||
|
notification.category,
|
||||||
|
notificationManager.NbNotifications(),
|
||||||
|
mode,
|
||||||
|
alertNotificationService,
|
||||||
|
motorController);
|
||||||
|
} else {
|
||||||
|
currentItem = std::make_unique<NotificationItem>(notification.category, alertNotificationService, motorController);
|
||||||
|
currentId = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
running = currentItem->IsRunning() && running;
|
running = currentItem->IsRunning() && running;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,23 +133,39 @@ bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
|
case Pinetime::Applications::TouchEvents::SwipeRight:
|
||||||
|
if (validDisplay) {
|
||||||
|
notificationManager.Dismiss(currentId);
|
||||||
|
if (currentId > 0 && currentId == notificationManager.NbNotifications()) {
|
||||||
|
// dismissed last message (like 5/5), need to go one message down (like 4/4)
|
||||||
|
--currentId;
|
||||||
|
}
|
||||||
|
currentItem->AnimateDismiss();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
case Pinetime::Applications::TouchEvents::SwipeDown: {
|
case Pinetime::Applications::TouchEvents::SwipeDown: {
|
||||||
Controllers::NotificationManager::Notification previousNotification;
|
Controllers::NotificationManager::Notification previousNotification;
|
||||||
if (validDisplay)
|
if (validDisplay) {
|
||||||
previousNotification = notificationManager.GetPrevious(currentId);
|
previousNotification = notificationManager.GetPrevious(currentId);
|
||||||
else
|
if (previousNotification.valid) {
|
||||||
|
currentId = std::min(static_cast<uint8_t>(currentId + 1), static_cast<uint8_t>(notificationManager.NbNotifications() - 1));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
previousNotification = notificationManager.GetLastNotification();
|
previousNotification = notificationManager.GetLastNotification();
|
||||||
|
currentId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!previousNotification.valid)
|
if (!previousNotification.valid) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
validDisplay = true;
|
validDisplay = true;
|
||||||
currentId = previousNotification.id;
|
|
||||||
currentItem.reset(nullptr);
|
currentItem.reset(nullptr);
|
||||||
app->SetFullRefresh(DisplayApp::FullRefreshDirections::Down);
|
app->SetFullRefresh(DisplayApp::FullRefreshDirections::Down);
|
||||||
currentItem = std::make_unique<NotificationItem>(previousNotification.Title(),
|
currentItem = std::make_unique<NotificationItem>(previousNotification.Title(),
|
||||||
previousNotification.Message(),
|
previousNotification.Message(),
|
||||||
previousNotification.index,
|
currentId + 1,
|
||||||
previousNotification.category,
|
previousNotification.category,
|
||||||
notificationManager.NbNotifications(),
|
notificationManager.NbNotifications(),
|
||||||
mode,
|
mode,
|
||||||
@ -145,12 +186,13 @@ bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
validDisplay = true;
|
validDisplay = true;
|
||||||
currentId = nextNotification.id;
|
if (currentId > 0)
|
||||||
|
--currentId;
|
||||||
currentItem.reset(nullptr);
|
currentItem.reset(nullptr);
|
||||||
app->SetFullRefresh(DisplayApp::FullRefreshDirections::Up);
|
app->SetFullRefresh(DisplayApp::FullRefreshDirections::Up);
|
||||||
currentItem = std::make_unique<NotificationItem>(nextNotification.Title(),
|
currentItem = std::make_unique<NotificationItem>(nextNotification.Title(),
|
||||||
nextNotification.Message(),
|
nextNotification.Message(),
|
||||||
nextNotification.index,
|
currentId + 1,
|
||||||
nextNotification.category,
|
nextNotification.category,
|
||||||
notificationManager.NbNotifications(),
|
notificationManager.NbNotifications(),
|
||||||
mode,
|
mode,
|
||||||
@ -170,6 +212,19 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Notifications::NotificationItem::NotificationItem(Controllers::NotificationManager::Categories category,
|
||||||
|
Pinetime::Controllers::AlertNotificationService& alertNotificationService,
|
||||||
|
Pinetime::Controllers::MotorController& motorController)
|
||||||
|
: NotificationItem("Notification",
|
||||||
|
"No notification to display",
|
||||||
|
0,
|
||||||
|
category,
|
||||||
|
0,
|
||||||
|
Modes::Preview,
|
||||||
|
alertNotificationService,
|
||||||
|
motorController) {
|
||||||
|
}
|
||||||
|
|
||||||
Notifications::NotificationItem::NotificationItem(const char* title,
|
Notifications::NotificationItem::NotificationItem(const char* title,
|
||||||
const char* msg,
|
const char* msg,
|
||||||
uint8_t notifNr,
|
uint8_t notifNr,
|
||||||
@ -179,24 +234,36 @@ Notifications::NotificationItem::NotificationItem(const char* title,
|
|||||||
Pinetime::Controllers::AlertNotificationService& alertNotificationService,
|
Pinetime::Controllers::AlertNotificationService& alertNotificationService,
|
||||||
Pinetime::Controllers::MotorController& motorController)
|
Pinetime::Controllers::MotorController& motorController)
|
||||||
: mode {mode}, alertNotificationService {alertNotificationService}, motorController {motorController} {
|
: mode {mode}, alertNotificationService {alertNotificationService}, motorController {motorController} {
|
||||||
lv_obj_t* container1 = lv_cont_create(lv_scr_act(), NULL);
|
|
||||||
|
|
||||||
lv_obj_set_style_local_bg_color(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x38, 0x38, 0x38));
|
container = lv_cont_create(lv_scr_act(), nullptr);
|
||||||
lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10);
|
lv_obj_set_size(container, LV_HOR_RES, LV_VER_RES);
|
||||||
lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5);
|
lv_obj_set_style_local_bg_color(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
|
||||||
lv_obj_set_style_local_border_width(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0);
|
lv_obj_set_style_local_pad_all(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0);
|
||||||
|
lv_obj_set_style_local_pad_inner(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0);
|
||||||
|
lv_obj_set_style_local_border_width(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0);
|
||||||
|
|
||||||
lv_obj_set_pos(container1, 0, 50);
|
subject_container = lv_cont_create(container, nullptr);
|
||||||
lv_obj_set_size(container1, LV_HOR_RES, 190);
|
lv_obj_set_style_local_bg_color(subject_container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x38, 0x38, 0x38));
|
||||||
|
lv_obj_set_style_local_pad_all(subject_container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10);
|
||||||
|
lv_obj_set_style_local_pad_inner(subject_container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5);
|
||||||
|
lv_obj_set_style_local_border_width(subject_container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0);
|
||||||
|
|
||||||
lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT);
|
lv_obj_set_pos(subject_container, 0, 50);
|
||||||
lv_cont_set_fit(container1, LV_FIT_NONE);
|
lv_obj_set_size(subject_container, LV_HOR_RES, LV_VER_RES - 50);
|
||||||
|
lv_cont_set_layout(subject_container, LV_LAYOUT_COLUMN_LEFT);
|
||||||
|
lv_cont_set_fit(subject_container, LV_FIT_NONE);
|
||||||
|
|
||||||
lv_obj_t* alert_count = lv_label_create(lv_scr_act(), nullptr);
|
lv_anim_init(&dismissAnim);
|
||||||
|
lv_anim_set_exec_cb(&dismissAnim, (lv_anim_exec_xcb_t) lv_obj_set_x);
|
||||||
|
lv_anim_set_var(&dismissAnim, container);
|
||||||
|
lv_anim_set_time(&dismissAnim, dismissAnimLength);
|
||||||
|
lv_anim_set_values(&dismissAnim, 0, LV_HOR_RES);
|
||||||
|
|
||||||
|
lv_obj_t* alert_count = lv_label_create(container, nullptr);
|
||||||
lv_label_set_text_fmt(alert_count, "%i/%i", notifNr, notifNb);
|
lv_label_set_text_fmt(alert_count, "%i/%i", notifNr, notifNb);
|
||||||
lv_obj_align(alert_count, NULL, LV_ALIGN_IN_TOP_RIGHT, 0, 16);
|
lv_obj_align(alert_count, NULL, LV_ALIGN_IN_TOP_RIGHT, 0, 16);
|
||||||
|
|
||||||
lv_obj_t* alert_type = lv_label_create(lv_scr_act(), nullptr);
|
lv_obj_t* alert_type = lv_label_create(container, nullptr);
|
||||||
lv_obj_set_style_local_text_color(alert_type, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0));
|
lv_obj_set_style_local_text_color(alert_type, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0));
|
||||||
if (title == nullptr) {
|
if (title == nullptr) {
|
||||||
lv_label_set_text_static(alert_type, "Notification");
|
lv_label_set_text_static(alert_type, "Notification");
|
||||||
@ -217,27 +284,27 @@ Notifications::NotificationItem::NotificationItem(const char* title,
|
|||||||
/////////
|
/////////
|
||||||
switch (category) {
|
switch (category) {
|
||||||
default: {
|
default: {
|
||||||
lv_obj_t* alert_subject = lv_label_create(container1, nullptr);
|
lv_obj_t* alert_subject = lv_label_create(subject_container, nullptr);
|
||||||
lv_obj_set_style_local_text_color(alert_subject, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xff, 0xb0, 0x0));
|
lv_obj_set_style_local_text_color(alert_subject, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xff, 0xb0, 0x0));
|
||||||
lv_label_set_long_mode(alert_subject, LV_LABEL_LONG_BREAK);
|
lv_label_set_long_mode(alert_subject, LV_LABEL_LONG_BREAK);
|
||||||
lv_obj_set_width(alert_subject, LV_HOR_RES - 20);
|
lv_obj_set_width(alert_subject, LV_HOR_RES - 20);
|
||||||
lv_label_set_text(alert_subject, msg);
|
lv_label_set_text(alert_subject, msg);
|
||||||
} break;
|
} break;
|
||||||
case Controllers::NotificationManager::Categories::IncomingCall: {
|
case Controllers::NotificationManager::Categories::IncomingCall: {
|
||||||
lv_obj_set_height(container1, 108);
|
lv_obj_set_height(subject_container, 108);
|
||||||
lv_obj_t* alert_subject = lv_label_create(container1, nullptr);
|
lv_obj_t* alert_subject = lv_label_create(subject_container, nullptr);
|
||||||
lv_obj_set_style_local_text_color(alert_subject, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xff, 0xb0, 0x0));
|
lv_obj_set_style_local_text_color(alert_subject, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xff, 0xb0, 0x0));
|
||||||
lv_label_set_long_mode(alert_subject, LV_LABEL_LONG_BREAK);
|
lv_label_set_long_mode(alert_subject, LV_LABEL_LONG_BREAK);
|
||||||
lv_obj_set_width(alert_subject, LV_HOR_RES - 20);
|
lv_obj_set_width(alert_subject, LV_HOR_RES - 20);
|
||||||
lv_label_set_text_static(alert_subject, "Incoming call from");
|
lv_label_set_text_static(alert_subject, "Incoming call from");
|
||||||
|
|
||||||
lv_obj_t* alert_caller = lv_label_create(container1, nullptr);
|
lv_obj_t* alert_caller = lv_label_create(subject_container, nullptr);
|
||||||
lv_obj_align(alert_caller, alert_subject, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0);
|
lv_obj_align(alert_caller, alert_subject, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0);
|
||||||
lv_label_set_long_mode(alert_caller, LV_LABEL_LONG_BREAK);
|
lv_label_set_long_mode(alert_caller, LV_LABEL_LONG_BREAK);
|
||||||
lv_obj_set_width(alert_caller, LV_HOR_RES - 20);
|
lv_obj_set_width(alert_caller, LV_HOR_RES - 20);
|
||||||
lv_label_set_text(alert_caller, msg);
|
lv_label_set_text(alert_caller, msg);
|
||||||
|
|
||||||
bt_accept = lv_btn_create(lv_scr_act(), nullptr);
|
bt_accept = lv_btn_create(container, nullptr);
|
||||||
bt_accept->user_data = this;
|
bt_accept->user_data = this;
|
||||||
lv_obj_set_event_cb(bt_accept, CallEventHandler);
|
lv_obj_set_event_cb(bt_accept, CallEventHandler);
|
||||||
lv_obj_set_size(bt_accept, 76, 76);
|
lv_obj_set_size(bt_accept, 76, 76);
|
||||||
@ -246,7 +313,7 @@ Notifications::NotificationItem::NotificationItem(const char* title,
|
|||||||
lv_label_set_text_static(label_accept, Symbols::phone);
|
lv_label_set_text_static(label_accept, Symbols::phone);
|
||||||
lv_obj_set_style_local_bg_color(bt_accept, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x0, 0xb0, 0x0));
|
lv_obj_set_style_local_bg_color(bt_accept, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x0, 0xb0, 0x0));
|
||||||
|
|
||||||
bt_reject = lv_btn_create(lv_scr_act(), nullptr);
|
bt_reject = lv_btn_create(container, nullptr);
|
||||||
bt_reject->user_data = this;
|
bt_reject->user_data = this;
|
||||||
lv_obj_set_event_cb(bt_reject, CallEventHandler);
|
lv_obj_set_event_cb(bt_reject, CallEventHandler);
|
||||||
lv_obj_set_size(bt_reject, 76, 76);
|
lv_obj_set_size(bt_reject, 76, 76);
|
||||||
@ -255,7 +322,7 @@ Notifications::NotificationItem::NotificationItem(const char* title,
|
|||||||
lv_label_set_text_static(label_reject, Symbols::phoneSlash);
|
lv_label_set_text_static(label_reject, Symbols::phoneSlash);
|
||||||
lv_obj_set_style_local_bg_color(bt_reject, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED);
|
lv_obj_set_style_local_bg_color(bt_reject, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED);
|
||||||
|
|
||||||
bt_mute = lv_btn_create(lv_scr_act(), nullptr);
|
bt_mute = lv_btn_create(container, nullptr);
|
||||||
bt_mute->user_data = this;
|
bt_mute->user_data = this;
|
||||||
lv_obj_set_event_cb(bt_mute, CallEventHandler);
|
lv_obj_set_event_cb(bt_mute, CallEventHandler);
|
||||||
lv_obj_set_size(bt_mute, 76, 76);
|
lv_obj_set_size(bt_mute, 76, 76);
|
||||||
@ -285,6 +352,20 @@ void Notifications::NotificationItem::OnCallButtonEvent(lv_obj_t* obj, lv_event_
|
|||||||
running = false;
|
running = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Notifications::NotificationItem::AnimateDismiss() {
|
||||||
|
dismissAnimTickCount = xTaskGetTickCount();
|
||||||
|
lv_anim_start(&dismissAnim);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Notifications::NotificationItem::AnimationElapsed() {
|
||||||
|
bool elapsed = dismissAnimTickCount != 0 && xTaskGetTickCount() > dismissAnimTickCount + dismissAnimLength;
|
||||||
|
|
||||||
|
if (elapsed)
|
||||||
|
dismissAnimTickCount = 0;
|
||||||
|
|
||||||
|
return elapsed;
|
||||||
|
}
|
||||||
|
|
||||||
Notifications::NotificationItem::~NotificationItem() {
|
Notifications::NotificationItem::~NotificationItem() {
|
||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,9 @@ namespace Pinetime {
|
|||||||
|
|
||||||
class NotificationItem {
|
class NotificationItem {
|
||||||
public:
|
public:
|
||||||
|
NotificationItem(Controllers::NotificationManager::Categories,
|
||||||
|
Pinetime::Controllers::AlertNotificationService& alertNotificationService,
|
||||||
|
Pinetime::Controllers::MotorController& motorController);
|
||||||
NotificationItem(const char* title,
|
NotificationItem(const char* title,
|
||||||
const char* msg,
|
const char* msg,
|
||||||
uint8_t notifNr,
|
uint8_t notifNr,
|
||||||
@ -46,9 +49,12 @@ namespace Pinetime {
|
|||||||
return running;
|
return running;
|
||||||
}
|
}
|
||||||
void OnCallButtonEvent(lv_obj_t*, lv_event_t event);
|
void OnCallButtonEvent(lv_obj_t*, lv_event_t event);
|
||||||
|
void AnimateDismiss();
|
||||||
|
bool AnimationElapsed();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
lv_obj_t* container1;
|
lv_obj_t* container;
|
||||||
|
lv_obj_t* subject_container;
|
||||||
lv_obj_t* bt_accept;
|
lv_obj_t* bt_accept;
|
||||||
lv_obj_t* bt_mute;
|
lv_obj_t* bt_mute;
|
||||||
lv_obj_t* bt_reject;
|
lv_obj_t* bt_reject;
|
||||||
@ -58,6 +64,11 @@ namespace Pinetime {
|
|||||||
Modes mode;
|
Modes mode;
|
||||||
Pinetime::Controllers::AlertNotificationService& alertNotificationService;
|
Pinetime::Controllers::AlertNotificationService& alertNotificationService;
|
||||||
Pinetime::Controllers::MotorController& motorController;
|
Pinetime::Controllers::MotorController& motorController;
|
||||||
|
|
||||||
|
lv_anim_t dismissAnim;
|
||||||
|
TickType_t dismissAnimTickCount;
|
||||||
|
static const TickType_t dismissAnimLength = pdMS_TO_TICKS(300);
|
||||||
|
|
||||||
bool running = true;
|
bool running = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -74,6 +85,7 @@ namespace Pinetime {
|
|||||||
lv_point_t timeoutLinePoints[2] {{0, 1}, {239, 1}};
|
lv_point_t timeoutLinePoints[2] {{0, 1}, {239, 1}};
|
||||||
lv_obj_t* timeoutLine = nullptr;
|
lv_obj_t* timeoutLine = nullptr;
|
||||||
TickType_t timeoutTickCountStart;
|
TickType_t timeoutTickCountStart;
|
||||||
|
|
||||||
static const TickType_t timeoutLength = pdMS_TO_TICKS(7000);
|
static const TickType_t timeoutLength = pdMS_TO_TICKS(7000);
|
||||||
bool interacted = true;
|
bool interacted = true;
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#include "displayapp/screens/WatchFaceDigital.h"
|
#include "displayapp/screens/WatchFaceDigital.h"
|
||||||
|
|
||||||
#include <nrf_log.h>
|
|
||||||
#include <date/date.h>
|
#include <date/date.h>
|
||||||
#include <lvgl/lvgl.h>
|
#include <lvgl/lvgl.h>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
@ -23,8 +22,7 @@ WatchFaceDigital::WatchFaceDigital(DisplayApp* app,
|
|||||||
Controllers::NotificationManager& notificatioManager,
|
Controllers::NotificationManager& notificatioManager,
|
||||||
Controllers::Settings& settingsController,
|
Controllers::Settings& settingsController,
|
||||||
Controllers::HeartRateController& heartRateController,
|
Controllers::HeartRateController& heartRateController,
|
||||||
Controllers::MotionController& motionController,
|
Controllers::MotionController& motionController)
|
||||||
Controllers::AgendaService& agendaService)
|
|
||||||
: Screen(app),
|
: Screen(app),
|
||||||
currentDateTime {{}},
|
currentDateTime {{}},
|
||||||
dateTimeController {dateTimeController},
|
dateTimeController {dateTimeController},
|
||||||
@ -33,8 +31,7 @@ WatchFaceDigital::WatchFaceDigital(DisplayApp* app,
|
|||||||
notificatioManager {notificatioManager},
|
notificatioManager {notificatioManager},
|
||||||
settingsController {settingsController},
|
settingsController {settingsController},
|
||||||
heartRateController {heartRateController},
|
heartRateController {heartRateController},
|
||||||
motionController {motionController},
|
motionController {motionController} {
|
||||||
agendaService {agendaService} {
|
|
||||||
|
|
||||||
batteryIcon.Create(lv_scr_act());
|
batteryIcon.Create(lv_scr_act());
|
||||||
lv_obj_align(batteryIcon.GetObject(), lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, 0, 0);
|
lv_obj_align(batteryIcon.GetObject(), lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, 0, 0);
|
||||||
@ -87,19 +84,6 @@ WatchFaceDigital::WatchFaceDigital(DisplayApp* app,
|
|||||||
lv_label_set_text_static(stepIcon, Symbols::shoe);
|
lv_label_set_text_static(stepIcon, Symbols::shoe);
|
||||||
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
|
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
|
||||||
|
|
||||||
|
|
||||||
agendaEntries[0] = lv_label_create(lv_scr_act(), nullptr);
|
|
||||||
lv_obj_align(agendaEntries[0], lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 0, 0);
|
|
||||||
lv_obj_set_style_local_text_color(agendaEntries[0], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x332222));
|
|
||||||
lv_label_set_text_static(agendaEntries[0], ".\n.");
|
|
||||||
|
|
||||||
|
|
||||||
agendaEntries[1] = lv_label_create(lv_scr_act(), nullptr);
|
|
||||||
lv_obj_align(agendaEntries[1], agendaEntries[0], LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0);
|
|
||||||
lv_obj_set_style_local_text_color(agendaEntries[1], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x332222));
|
|
||||||
lv_label_set_text_static(agendaEntries[1], ".\n.");
|
|
||||||
|
|
||||||
|
|
||||||
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
|
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
|
||||||
Refresh();
|
Refresh();
|
||||||
}
|
}
|
||||||
@ -109,89 +93,6 @@ WatchFaceDigital::~WatchFaceDigital() {
|
|||||||
lv_obj_clean(lv_scr_act());
|
lv_obj_clean(lv_scr_act());
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatchFaceDigital::RefreshMiniAgenda() {
|
|
||||||
using namespace date;
|
|
||||||
using namespace std::chrono;
|
|
||||||
|
|
||||||
// Set our offset to just before the newest event
|
|
||||||
// We only show events destined for today.
|
|
||||||
|
|
||||||
bool found = false;
|
|
||||||
uint8_t firstFutureEvent = 0;
|
|
||||||
|
|
||||||
std::chrono::system_clock::time_point now = dateTimeController.CurrentDateTime();
|
|
||||||
auto today = floor<days>(now);
|
|
||||||
|
|
||||||
// Find first entry that is just after the current time (- 5 min)!
|
|
||||||
for (uint8_t i = 0; i < Pinetime::Controllers::AgendaService::AGENDA_CAPACITY; ++i) {
|
|
||||||
uint32_t time = agendaService.getAgendaTime(i);
|
|
||||||
firstFutureEvent = i;
|
|
||||||
if (time == 0) break;
|
|
||||||
sys_seconds timestamp = sys_days{1970_y/1/1} + seconds{time};
|
|
||||||
sys_days dayOfEvent = floor<days>(timestamp);
|
|
||||||
|
|
||||||
if (dayOfEvent > today) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timestamp > now) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool suitable[2] = {false, found};
|
|
||||||
|
|
||||||
if (firstFutureEvent != 0) {
|
|
||||||
uint32_t time = agendaService.getAgendaTime(firstFutureEvent - 1);
|
|
||||||
if (time != 0) {
|
|
||||||
sys_seconds timestamp = sys_days{1970_y/1/1} + seconds{time};
|
|
||||||
|
|
||||||
sys_days dayOfEvent = floor<days>(timestamp);
|
|
||||||
|
|
||||||
if (dayOfEvent == today) {
|
|
||||||
suitable[0] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
// No earlier events in the day.
|
|
||||||
lv_label_set_text_static(agendaEntries[0], "--h--\n .....");
|
|
||||||
lv_obj_set_style_local_text_color(agendaEntries[0], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x332222));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < 2; ++i) {
|
|
||||||
if (! suitable[i]) {
|
|
||||||
lv_label_set_text_static(agendaEntries[i], "--h--\n .....");
|
|
||||||
lv_obj_set_style_local_text_color(agendaEntries[i], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x332222));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t itemIdx = firstFutureEvent - (1 - i);
|
|
||||||
|
|
||||||
uint32_t time = agendaService.getAgendaTime(itemIdx);
|
|
||||||
|
|
||||||
sys_seconds timestamp = sys_days{1970_y/1/1} + seconds{time};
|
|
||||||
//auto timestamp = std::chrono::system_clock::time_point{time * 1s};
|
|
||||||
sys_days agendaDate = floor<days>(timestamp);
|
|
||||||
time_of_day<seconds> agendaTimePart = make_time(timestamp - agendaDate);
|
|
||||||
|
|
||||||
lv_label_set_text_fmt(agendaEntries[i], "%02lldh%02lld\n %s", agendaTimePart.hours().count(), agendaTimePart.minutes().count(), agendaService.getAgendaPiece(itemIdx).data());
|
|
||||||
|
|
||||||
if (timestamp + 30min < now) {
|
|
||||||
lv_obj_set_style_local_text_color(agendaEntries[i], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x334433));
|
|
||||||
} else if (timestamp + 5min < now) {
|
|
||||||
lv_obj_set_style_local_text_color(agendaEntries[i], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7));
|
|
||||||
} else if (timestamp - 5min < now && now < timestamp + 5min) {
|
|
||||||
lv_obj_set_style_local_text_color(agendaEntries[i], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFFA500));
|
|
||||||
} else if (now + 5min < timestamp) {
|
|
||||||
lv_obj_set_style_local_text_color(agendaEntries[i], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFFFF00));
|
|
||||||
} else if (now + 30min < timestamp) {
|
|
||||||
lv_obj_set_style_local_text_color(agendaEntries[i], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFFFFFF));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void WatchFaceDigital::Refresh() {
|
void WatchFaceDigital::Refresh() {
|
||||||
powerPresent = batteryController.IsPowerPresent();
|
powerPresent = batteryController.IsPowerPresent();
|
||||||
if (powerPresent.IsUpdated()) {
|
if (powerPresent.IsUpdated()) {
|
||||||
@ -235,8 +136,6 @@ void WatchFaceDigital::Refresh() {
|
|||||||
uint8_t minute = time.minutes().count();
|
uint8_t minute = time.minutes().count();
|
||||||
|
|
||||||
if (displayedHour != hour || displayedMinute != minute) {
|
if (displayedHour != hour || displayedMinute != minute) {
|
||||||
RefreshMiniAgenda();
|
|
||||||
|
|
||||||
displayedHour = hour;
|
displayedHour = hour;
|
||||||
displayedMinute = minute;
|
displayedMinute = minute;
|
||||||
|
|
||||||
|
@ -17,7 +17,6 @@ namespace Pinetime {
|
|||||||
class NotificationManager;
|
class NotificationManager;
|
||||||
class HeartRateController;
|
class HeartRateController;
|
||||||
class MotionController;
|
class MotionController;
|
||||||
class AgendaService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Applications {
|
namespace Applications {
|
||||||
@ -32,14 +31,11 @@ namespace Pinetime {
|
|||||||
Controllers::NotificationManager& notificatioManager,
|
Controllers::NotificationManager& notificatioManager,
|
||||||
Controllers::Settings& settingsController,
|
Controllers::Settings& settingsController,
|
||||||
Controllers::HeartRateController& heartRateController,
|
Controllers::HeartRateController& heartRateController,
|
||||||
Controllers::MotionController& motionController,
|
Controllers::MotionController& motionController);
|
||||||
Controllers::AgendaService& agendaService);
|
|
||||||
~WatchFaceDigital() override;
|
~WatchFaceDigital() override;
|
||||||
|
|
||||||
void Refresh() override;
|
void Refresh() override;
|
||||||
|
|
||||||
void RefreshMiniAgenda();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t displayedHour = -1;
|
uint8_t displayedHour = -1;
|
||||||
uint8_t displayedMinute = -1;
|
uint8_t displayedMinute = -1;
|
||||||
@ -71,8 +67,6 @@ namespace Pinetime {
|
|||||||
lv_obj_t* stepValue;
|
lv_obj_t* stepValue;
|
||||||
lv_obj_t* notificationIcon;
|
lv_obj_t* notificationIcon;
|
||||||
|
|
||||||
lv_obj_t* agendaEntries[2];
|
|
||||||
|
|
||||||
BatteryIcon batteryIcon;
|
BatteryIcon batteryIcon;
|
||||||
|
|
||||||
Controllers::DateTime& dateTimeController;
|
Controllers::DateTime& dateTimeController;
|
||||||
@ -82,7 +76,6 @@ namespace Pinetime {
|
|||||||
Controllers::Settings& settingsController;
|
Controllers::Settings& settingsController;
|
||||||
Controllers::HeartRateController& heartRateController;
|
Controllers::HeartRateController& heartRateController;
|
||||||
Controllers::MotionController& motionController;
|
Controllers::MotionController& motionController;
|
||||||
Controllers::AgendaService& agendaService;
|
|
||||||
|
|
||||||
lv_task_t* taskRefresh;
|
lv_task_t* taskRefresh;
|
||||||
};
|
};
|
||||||
|
@ -14,8 +14,6 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr std::array<SettingChimes::Option, 3> SettingChimes::options;
|
|
||||||
|
|
||||||
SettingChimes::SettingChimes(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController)
|
SettingChimes::SettingChimes(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController)
|
||||||
: Screen(app), settingsController {settingsController} {
|
: Screen(app), settingsController {settingsController} {
|
||||||
|
|
||||||
@ -42,16 +40,37 @@ SettingChimes::SettingChimes(Pinetime::Applications::DisplayApp* app, Pinetime::
|
|||||||
lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER);
|
lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER);
|
||||||
lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0);
|
lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < options.size(); i++) {
|
optionsTotal = 0;
|
||||||
cbOption[i] = lv_checkbox_create(container1, nullptr);
|
cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr);
|
||||||
lv_checkbox_set_text(cbOption[i], options[i].name);
|
lv_checkbox_set_text_static(cbOption[optionsTotal], " Off");
|
||||||
if (settingsController.GetChimeOption() == options[i].chimesOption) {
|
cbOption[optionsTotal]->user_data = this;
|
||||||
lv_checkbox_set_checked(cbOption[i], true);
|
lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
|
||||||
}
|
SetRadioButtonStyle(cbOption[optionsTotal]);
|
||||||
cbOption[i]->user_data = this;
|
if (settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::None) {
|
||||||
lv_obj_set_event_cb(cbOption[i], event_handler);
|
lv_checkbox_set_checked(cbOption[optionsTotal], true);
|
||||||
SetRadioButtonStyle(cbOption[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
optionsTotal++;
|
||||||
|
cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr);
|
||||||
|
lv_checkbox_set_text_static(cbOption[optionsTotal], " Every hour");
|
||||||
|
cbOption[optionsTotal]->user_data = this;
|
||||||
|
lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
|
||||||
|
SetRadioButtonStyle(cbOption[optionsTotal]);
|
||||||
|
if (settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::Hours) {
|
||||||
|
lv_checkbox_set_checked(cbOption[optionsTotal], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
optionsTotal++;
|
||||||
|
cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr);
|
||||||
|
lv_checkbox_set_text_static(cbOption[optionsTotal], " Every 30 mins");
|
||||||
|
cbOption[optionsTotal]->user_data = this;
|
||||||
|
lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
|
||||||
|
SetRadioButtonStyle(cbOption[optionsTotal]);
|
||||||
|
if (settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::HalfHours) {
|
||||||
|
lv_checkbox_set_checked(cbOption[optionsTotal], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
optionsTotal++;
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingChimes::~SettingChimes() {
|
SettingChimes::~SettingChimes() {
|
||||||
@ -61,10 +80,18 @@ SettingChimes::~SettingChimes() {
|
|||||||
|
|
||||||
void SettingChimes::UpdateSelected(lv_obj_t* object, lv_event_t event) {
|
void SettingChimes::UpdateSelected(lv_obj_t* object, lv_event_t event) {
|
||||||
if (event == LV_EVENT_VALUE_CHANGED) {
|
if (event == LV_EVENT_VALUE_CHANGED) {
|
||||||
for (uint8_t i = 0; i < options.size(); i++) {
|
for (uint8_t i = 0; i < optionsTotal; i++) {
|
||||||
if (object == cbOption[i]) {
|
if (object == cbOption[i]) {
|
||||||
lv_checkbox_set_checked(cbOption[i], true);
|
lv_checkbox_set_checked(cbOption[i], true);
|
||||||
settingsController.SetChimeOption(options[i].chimesOption);
|
if (i == 0) {
|
||||||
|
settingsController.SetChimeOption(Controllers::Settings::ChimesOption::None);
|
||||||
|
}
|
||||||
|
if (i == 1) {
|
||||||
|
settingsController.SetChimeOption(Controllers::Settings::ChimesOption::Hours);
|
||||||
|
}
|
||||||
|
if (i == 2) {
|
||||||
|
settingsController.SetChimeOption(Controllers::Settings::ChimesOption::HalfHours);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
lv_checkbox_set_checked(cbOption[i], false);
|
lv_checkbox_set_checked(cbOption[i], false);
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#include <lvgl/lvgl.h>
|
#include <lvgl/lvgl.h>
|
||||||
#include "components/settings/Settings.h"
|
#include "components/settings/Settings.h"
|
||||||
#include "displayapp/screens/Screen.h"
|
#include "displayapp/screens/Screen.h"
|
||||||
#include <array>
|
|
||||||
|
|
||||||
namespace Pinetime {
|
namespace Pinetime {
|
||||||
|
|
||||||
@ -19,19 +18,9 @@ namespace Pinetime {
|
|||||||
void UpdateSelected(lv_obj_t* object, lv_event_t event);
|
void UpdateSelected(lv_obj_t* object, lv_event_t event);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Option {
|
|
||||||
Controllers::Settings::ChimesOption chimesOption;
|
|
||||||
const char* name;
|
|
||||||
};
|
|
||||||
static constexpr std::array<Option, 3> options = {{
|
|
||||||
{Controllers::Settings::ChimesOption::None, " Off"},
|
|
||||||
{Controllers::Settings::ChimesOption::Hours, " Every hour"},
|
|
||||||
{Controllers::Settings::ChimesOption::HalfHours, " Every 30 mins"}
|
|
||||||
}};
|
|
||||||
|
|
||||||
std::array<lv_obj_t*, options.size()> cbOption;
|
|
||||||
|
|
||||||
Controllers::Settings& settingsController;
|
Controllers::Settings& settingsController;
|
||||||
|
uint8_t optionsTotal;
|
||||||
|
lv_obj_t* cbOption[3];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,17 +16,18 @@ for file in $CHANGED_FILES
|
|||||||
do
|
do
|
||||||
[ -e "$file" ] || continue
|
[ -e "$file" ] || continue
|
||||||
case "$file" in
|
case "$file" in
|
||||||
src/libs/*|src/FreeRTOS/*) continue ;;
|
src/libs/*) continue ;;
|
||||||
*.cpp|*.h)
|
*.cpp|*.h)
|
||||||
echo Checking "$file"
|
echo Checking "$file"
|
||||||
PATCH="$(basename "$file").patch"
|
clang-format -i "$file"
|
||||||
git clang-format-12 -q --style file --diff "$GITHUB_BASE_REF" "$file" > "$PATCH"
|
if ! git diff --quiet
|
||||||
if [ -s "$PATCH" ]
|
|
||||||
then
|
then
|
||||||
printf "\033[31mError:\033[0m Formatting error in %s\n" "$file"
|
printf "\033[31mError:\033[0m Formatting error in %s\n" "$file"
|
||||||
CHANGED=1
|
CHANGED=1
|
||||||
else
|
git add "$file"
|
||||||
rm "$PATCH"
|
git commit -q -m "Apply clang-format to $(basename "$file")"
|
||||||
|
printf "Creating patch "
|
||||||
|
git format-patch HEAD~
|
||||||
fi
|
fi
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
Loading…
Reference in New Issue
Block a user