Merge branch 'develop' into infineat-external-resources

# Conflicts:
#	src/displayapp/screens/Symbols.h
#	src/displayapp/screens/settings/SettingWatchFace.cpp
#	src/displayapp/screens/settings/SettingWatchFace.h
This commit is contained in:
Jean-François Milants
2022-09-11 14:59:49 +02:00
160 changed files with 3250 additions and 46018 deletions

View File

@@ -9,15 +9,15 @@ using namespace Pinetime;
uint32_t BootloaderVersion::version = 0;
char BootloaderVersion::versionString[BootloaderVersion::VERSION_STR_LEN] = "0.0.0";
const uint32_t BootloaderVersion::Major() {
uint32_t BootloaderVersion::Major() {
return (BootloaderVersion::version >> 16u) & 0xff;
}
const uint32_t BootloaderVersion::Minor() {
uint32_t BootloaderVersion::Minor() {
return (BootloaderVersion::version >> 8u) & 0xff;
}
const uint32_t BootloaderVersion::Patch() {
uint32_t BootloaderVersion::Patch() {
return BootloaderVersion::version & 0xff;
}
@@ -25,7 +25,7 @@ const char* BootloaderVersion::VersionString() {
return BootloaderVersion::versionString;
}
const bool BootloaderVersion::IsValid() {
bool BootloaderVersion::IsValid() {
return BootloaderVersion::version >= 0x00010000;
}

View File

@@ -6,11 +6,11 @@
namespace Pinetime {
class BootloaderVersion {
public:
static const uint32_t Major();
static const uint32_t Minor();
static const uint32_t Patch();
static uint32_t Major();
static uint32_t Minor();
static uint32_t Patch();
static const char* VersionString();
static const bool IsValid();
static bool IsValid();
static void SetVersion(uint32_t v);
private:

View File

@@ -9,21 +9,21 @@ set(NRF_BOARD pca10040)
# check if all the necessary tools paths have been provided.
if (NOT NRF5_SDK_PATH)
message(FATAL_ERROR "The path to the nRF5 SDK (NRF5_SDK_PATH) must be set.")
message(FATAL_ERROR "The path to the nRF5 SDK (NRF5_SDK_PATH) must be set.")
endif ()
if (DEFINED ARM_NONE_EABI_TOOLCHAIN_PATH)
set(ARM_NONE_EABI_TOOLCHAIN_BIN_PATH ${ARM_NONE_EABI_TOOLCHAIN_PATH}/bin)
set(ARM_NONE_EABI_TOOLCHAIN_BIN_PATH ${ARM_NONE_EABI_TOOLCHAIN_PATH}/bin)
endif ()
if (NOT NRF_TARGET MATCHES "nrf52")
message(FATAL_ERROR "Only rRF52 boards are supported right now")
message(FATAL_ERROR "Only rRF52 boards are supported right now")
endif ()
# Setup toolchain
include(${CMAKE_SOURCE_DIR}/cmake-nRF5x/arm-gcc-toolchain.cmake)
if (NOT DEFINED ARM_GCC_TOOLCHAIN)
message(FATAL_ERROR "The toolchain must be set up before calling this macro")
message(FATAL_ERROR "The toolchain must be set up before calling this macro")
endif ()
set(CMAKE_OSX_SYSROOT "/")
set(CMAKE_OSX_DEPLOYMENT_TARGET "")
@@ -406,6 +406,8 @@ list(APPEND SOURCE_FILES
displayapp/screens/Styles.cpp
displayapp/Colors.cpp
displayapp/widgets/Counter.cpp
displayapp/widgets/PageIndicator.cpp
displayapp/widgets/StatusIcons.cpp
## Settings
displayapp/screens/settings/QuickSettings.cpp
@@ -478,7 +480,7 @@ list(APPEND SOURCE_FILES
FreeRTOS/port_cmsis.c
displayapp/LittleVgl.cpp
displayapp/lv_pinetime_theme.c
displayapp/InfiniTimeTheme.cpp
systemtask/SystemTask.cpp
systemtask/SystemMonitor.cpp
@@ -613,6 +615,8 @@ set(INCLUDE_FILES
displayapp/screens/Alarm.h
displayapp/Colors.h
displayapp/widgets/Counter.h
displayapp/widgets/PageIndicator.h
displayapp/widgets/StatusIcons.h
drivers/St7789.h
drivers/SpiNorFlash.h
drivers/SpiMaster.h
@@ -654,16 +658,16 @@ set(INCLUDE_FILES
drivers/Cst816s.h
FreeRTOS/portmacro.h
FreeRTOS/portmacro_cmsis.h
libs/date/includes/date/tz.h
libs/date/includes/date/chrono_io.h
libs/date/includes/date/date.h
libs/date/includes/date/islamic.h
libs/date/includes/date/iso_week.h
libs/date/includes/date/julian.h
libs/date/includes/date/ptz.h
libs/date/includes/date/tz_private.h
libs/date/include/date/tz.h
libs/date/include/date/chrono_io.h
libs/date/include/date/date.h
libs/date/include/date/islamic.h
libs/date/include/date/iso_week.h
libs/date/include/date/julian.h
libs/date/include/date/ptz.h
libs/date/include/date/tz_private.h
displayapp/LittleVgl.h
displayapp/lv_pinetime_theme.h
displayapp/InfiniTimeTheme.h
systemtask/SystemTask.h
systemtask/SystemMonitor.h
displayapp/screens/Symbols.h
@@ -684,7 +688,7 @@ include_directories(
../
libs/
FreeRTOS/
libs/date/includes
libs/date/include
libs/mynewt-nimble/porting/npl/freertos/include
libs/mynewt-nimble/nimble/include
libs/mynewt-nimble/porting/nimble/include
@@ -782,14 +786,60 @@ add_definitions(-DNRF52 -DNRF52832 -DNRF52832_XXAA -DNRF52_PAN_74 -DNRF52_PAN_64
add_definitions(-DFREERTOS)
add_definitions(-D__STACK_SIZE=1024)
add_definitions(-D__HEAP_SIZE=4096)
add_definitions(-DMYNEWT_VAL_BLE_LL_RFMGMT_ENABLE_TIME=1500)
# NOTE : Add the following defines to enable debug mode of the NRF SDK:
#add_definitions(-DDEBUG)
#add_definitions(-DDEBUG_NRF_USER)
# Note: Only use this for debugging
# Derive the low frequency clock from the main clock (SYNT)
# add_definitions(-DCLOCK_CONFIG_LF_SRC=2)
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release")
endif ()
# Target hardware configuration options
add_definitions(-DTARGET_DEVICE_${TARGET_DEVICE})
add_definitions(-DTARGET_DEVICE_NAME="${TARGET_DEVICE}")
if(TARGET_DEVICE STREQUAL "PINETIME")
add_definitions(-DDRIVER_PINMAP_PINETIME)
add_definitions(-DCLOCK_CONFIG_LF_SRC=1) # XTAL
elseif(TARGET_DEVICE STREQUAL "MOY-TFK5") # P8a
add_definitions(-DDRIVER_PINMAP_P8)
add_definitions(-DCLOCK_CONFIG_LF_SRC=1) # XTAL
elseif(TARGET_DEVICE STREQUAL "MOY-TIN5") # P8a variant 2
add_definitions(-DDRIVER_PINMAP_P8)
add_definitions(-DCLOCK_CONFIG_LF_SRC=1) # XTAL
elseif(TARGET_DEVICE STREQUAL "MOY-TON5") # P8b
add_definitions(-DDRIVER_PINMAP_P8)
add_definitions(-DCLOCK_CONFIG_LF_SRC=0) # RC
add_definitions(-DMYNEWT_VAL_BLE_LL_SCA=500)
add_definitions(-DCLOCK_CONFIG_LF_CAL_ENABLED=1)
elseif(TARGET_DEVICE STREQUAL "MOY-UNK") # P8b mirrored
add_definitions(-DDRIVER_PINMAP_P8)
add_definitions(-DCLOCK_CONFIG_LF_SRC=0) # RC
add_definitions(-DMYNEWT_VAL_BLE_LL_SCA=500)
add_definitions(-DCLOCK_CONFIG_LF_CAL_ENABLED=1)
add_definitions(-DDRIVER_DISPLAY_MIRROR)
else()
message(FATAL_ERROR "Invalid TARGET_DEVICE")
endif()
# Debug configuration
if (${CMAKE_BUILD_TYPE} STREQUAL "Debug")
add_definitions(-DDEBUG)
add_definitions(-DDEBUG_NRF_USER)
# NRF SDK Logging
add_definitions(-DNRF_LOG_ENABLED=1)
# add_definitions(-DNRF_LOG_BACKEND_RTT_ENABLED=1)
# add_definitions(-DNRF_LOG_BACKEND_SERIAL_USES_RTT=1)
# NRF SDK individual modules logging
# add_definitions(-DCLOCK_CONFIG_LOG_ENABLED=1)
# add_definitions(-DCLOCK_CONFIG_LOG_LEVEL=4)
# add_definitions(-DRTC_CONFIG_LOG_ENABLED=1)
# add_definitions(-DRTC_CONFIG_LOG_LEVEL=4)
# Nimble Logging
add_definitions(-DMYNEWT_VAL_NEWT_FEATURE_LOGCFG=1)
# add_definitions(-DMYNEWT_VAL_LOG_LEVEL=0)
# add_definitions(-DMYNEWT_VAL_BLE_HS_LOG_LVL=0)
endif()
add_subdirectory(displayapp/fonts)
target_compile_options(infinitime_fonts PUBLIC
@@ -894,10 +944,15 @@ add_custom_command(TARGET ${EXECUTABLE_NAME}
COMMAND ${CMAKE_OBJCOPY} -O ihex ${EXECUTABLE_FILE_NAME}.out "${EXECUTABLE_FILE_NAME}.hex"
COMMENT "post build steps for ${EXECUTABLE_FILE_NAME}")
if(BUILD_RESOURCES)
add_dependencies(${EXECUTABLE_NAME} GenerateResources)
endif()
# Build binary intended to be used by bootloader
set(EXECUTABLE_MCUBOOT_NAME "pinetime-mcuboot-app")
set(EXECUTABLE_MCUBOOT_FILE_NAME ${EXECUTABLE_MCUBOOT_NAME}-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH})
set(IMAGE_MCUBOOT_FILE_NAME ${EXECUTABLE_MCUBOOT_NAME}-image-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.hex)
set(IMAGE_MCUBOOT_FILE_NAME_HEX ${EXECUTABLE_MCUBOOT_NAME}-image-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.hex)
set(IMAGE_MCUBOOT_FILE_NAME_BIN ${EXECUTABLE_MCUBOOT_NAME}-image-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.bin)
set(DFU_MCUBOOT_FILE_NAME ${EXECUTABLE_MCUBOOT_NAME}-dfu-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.zip)
set(NRF5_LINKER_SCRIPT_MCUBOOT "${CMAKE_SOURCE_DIR}/gcc_nrf52-mcuboot.ld")
add_executable(${EXECUTABLE_MCUBOOT_NAME} ${SOURCE_FILES})
@@ -921,16 +976,21 @@ add_custom_command(TARGET ${EXECUTABLE_MCUBOOT_NAME}
COMMAND ${CMAKE_SIZE_UTIL} ${EXECUTABLE_MCUBOOT_FILE_NAME}.out
COMMAND ${CMAKE_OBJCOPY} -O binary ${EXECUTABLE_MCUBOOT_FILE_NAME}.out "${EXECUTABLE_MCUBOOT_FILE_NAME}.bin"
COMMAND ${CMAKE_OBJCOPY} -O ihex ${EXECUTABLE_MCUBOOT_FILE_NAME}.out "${EXECUTABLE_MCUBOOT_FILE_NAME}.hex"
COMMAND ${CMAKE_SOURCE_DIR}/tools/mcuboot/imgtool.py create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header ${EXECUTABLE_MCUBOOT_FILE_NAME}.hex ${IMAGE_MCUBOOT_FILE_NAME}
COMMAND ${CMAKE_SOURCE_DIR}/tools/mcuboot/imgtool.py create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header ${EXECUTABLE_MCUBOOT_FILE_NAME}.hex ${IMAGE_MCUBOOT_FILE_NAME_HEX}
COMMAND ${CMAKE_SOURCE_DIR}/tools/mcuboot/imgtool.py create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header ${EXECUTABLE_MCUBOOT_FILE_NAME}.bin ${IMAGE_MCUBOOT_FILE_NAME_BIN}
COMMENT "post build steps for ${EXECUTABLE_MCUBOOT_FILE_NAME}"
)
if(BUILD_RESOURCES)
add_dependencies(${EXECUTABLE_MCUBOOT_NAME} GenerateResources)
endif()
if(BUILD_DFU)
add_custom_command(TARGET ${EXECUTABLE_MCUBOOT_NAME}
POST_BUILD
COMMAND adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application ${IMAGE_MCUBOOT_FILE_NAME} ${DFU_MCUBOOT_FILE_NAME}
COMMENT "post build (DFU) steps for ${EXECUTABLE_MCUBOOT_FILE_NAME}"
)
add_custom_command(TARGET ${EXECUTABLE_MCUBOOT_NAME}
POST_BUILD
COMMAND adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application ${IMAGE_MCUBOOT_FILE_NAME_HEX} ${DFU_MCUBOOT_FILE_NAME}
COMMENT "post build (DFU) steps for ${EXECUTABLE_MCUBOOT_FILE_NAME}"
)
endif()
# InfiniTime recovery firmware (autonomous)
@@ -964,7 +1024,8 @@ add_custom_command(TARGET ${EXECUTABLE_RECOVERY_NAME}
# InfiniTime recovery firmware (mcuboot)
set(EXECUTABLE_RECOVERY_MCUBOOT_NAME "pinetime-mcuboot-recovery")
set(EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME ${EXECUTABLE_RECOVERY_MCUBOOT_NAME}-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH})
set(IMAGE_RECOVERY_MCUBOOT_FILE_NAME ${EXECUTABLE_RECOVERY_MCUBOOT_NAME}-image-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.hex)
set(IMAGE_RECOVERY_MCUBOOT_FILE_NAME ${EXECUTABLE_RECOVERY_MCUBOOT_NAME}-image-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH})
set(IMAGE_RECOVERY_MCUBOOT_FILE_NAME_HEX ${IMAGE_RECOVERY_MCUBOOT_FILE_NAME}.hex)
set(DFU_RECOVERY_MCUBOOT_FILE_NAME ${EXECUTABLE_RECOVERY_MCUBOOT_NAME}-dfu-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.zip)
add_executable(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} ${RECOVERY_SOURCE_FILES})
target_link_libraries(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} nimble nrf-sdk littlefs QCBOR infinitime_fonts)
@@ -988,18 +1049,18 @@ add_custom_command(TARGET ${EXECUTABLE_RECOVERY_MCUBOOT_NAME}
COMMAND ${CMAKE_SIZE_UTIL} ${EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME}.out
COMMAND ${CMAKE_OBJCOPY} -O binary ${EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME}.out "${EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME}.bin"
COMMAND ${CMAKE_OBJCOPY} -O ihex ${EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME}.out "${EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME}.hex"
COMMAND ${CMAKE_SOURCE_DIR}/tools/mcuboot/imgtool.py create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header ${EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME}.hex ${IMAGE_RECOVERY_MCUBOOT_FILE_NAME}
COMMAND ${CMAKE_OBJCOPY} -I ihex -O binary ${IMAGE_RECOVERY_MCUBOOT_FILE_NAME} "${IMAGE_RECOVERY_MCUBOOT_FILE_NAME}.bin"
COMMAND ${CMAKE_SOURCE_DIR}/tools/mcuboot/imgtool.py create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header ${EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME}.hex ${IMAGE_RECOVERY_MCUBOOT_FILE_NAME_HEX}
COMMAND ${CMAKE_OBJCOPY} -I ihex -O binary ${IMAGE_RECOVERY_MCUBOOT_FILE_NAME_HEX} "${IMAGE_RECOVERY_MCUBOOT_FILE_NAME}.bin"
COMMAND python3 ${CMAKE_SOURCE_DIR}/tools/bin2c.py ${IMAGE_RECOVERY_MCUBOOT_FILE_NAME}.bin recoveryImage > recoveryImage.h
COMMENT "post build steps for ${EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME}"
)
if(BUILD_DFU)
add_custom_command(TARGET ${EXECUTABLE_RECOVERY_MCUBOOT_NAME}
POST_BUILD
COMMAND adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application ${IMAGE_RECOVERY_MCUBOOT_FILE_NAME} ${DFU_RECOVERY_MCUBOOT_FILE_NAME}
COMMENT "post build (DFU) steps for ${EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME}"
)
add_custom_command(TARGET ${EXECUTABLE_RECOVERY_MCUBOOT_NAME}
POST_BUILD
COMMAND adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application ${IMAGE_RECOVERY_MCUBOOT_FILE_NAME_HEX} ${DFU_RECOVERY_MCUBOOT_FILE_NAME}
COMMENT "post build (DFU) steps for ${EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME}"
)
endif()
# Build binary that writes the recovery image into the SPI flash memory
@@ -1036,7 +1097,8 @@ add_custom_command(TARGET ${EXECUTABLE_RECOVERYLOADER_NAME}
# Build binary that writes the recovery image (MCUBoot version)
set(EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME "pinetime-mcuboot-recovery-loader")
set(EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME}-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH})
set(IMAGE_MCUBOOT_RECOVERYLOADER_FILE_NAME ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME}-image-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.hex)
set(IMAGE_MCUBOOT_RECOVERYLOADER_FILE_NAME ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME}-image-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH})
set(IMAGE_MCUBOOT_RECOVERYLOADER_FILE_NAME_HEX ${IMAGE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.hex)
set(DFU_MCUBOOT_RECOVERYLOADER_FILE_NAME ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME}-dfu-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.zip)
add_executable(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} ${RECOVERYLOADER_SOURCE_FILES})
target_link_libraries(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} nrf-sdk QCBOR infinitime_fonts)
@@ -1063,82 +1125,86 @@ add_custom_command(TARGET ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME}
COMMAND ${CMAKE_SIZE_UTIL} ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.out
COMMAND ${CMAKE_OBJCOPY} -O binary ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.out "${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.bin"
COMMAND ${CMAKE_OBJCOPY} -O ihex ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.out "${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.hex"
COMMAND ${CMAKE_SOURCE_DIR}/tools/mcuboot/imgtool.py create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.hex ${IMAGE_MCUBOOT_RECOVERYLOADER_FILE_NAME}
COMMAND ${CMAKE_OBJCOPY} -I ihex -O binary ${IMAGE_MCUBOOT_RECOVERYLOADER_FILE_NAME} "${IMAGE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.bin"
COMMAND ${CMAKE_SOURCE_DIR}/tools/mcuboot/imgtool.py create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.hex ${IMAGE_MCUBOOT_RECOVERYLOADER_FILE_NAME_HEX}
COMMAND ${CMAKE_OBJCOPY} -I ihex -O binary ${IMAGE_MCUBOOT_RECOVERYLOADER_FILE_NAME_HEX} "${IMAGE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.bin"
COMMAND python3 ${CMAKE_SOURCE_DIR}/tools/bin2c.py ${IMAGE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.bin recoveryLoaderImage > recoveryLoaderImage.h
COMMENT "post build steps for ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}"
)
if(BUILD_DFU)
add_custom_command(TARGET ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME}
POST_BUILD
COMMAND adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application ${IMAGE_MCUBOOT_RECOVERYLOADER_FILE_NAME} ${DFU_MCUBOOT_RECOVERYLOADER_FILE_NAME}
COMMENT "post build (DFU) steps for ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}"
)
add_custom_command(TARGET ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME}
POST_BUILD
COMMAND adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application ${IMAGE_MCUBOOT_RECOVERYLOADER_FILE_NAME_HEX} ${DFU_MCUBOOT_RECOVERYLOADER_FILE_NAME}
COMMENT "post build (DFU) steps for ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}"
)
endif()
if(BUILD_RESOURCES)
add_subdirectory(resources)
endif()
# FLASH
if (USE_JLINK)
add_custom_target(FLASH_ERASE
COMMAND ${NRFJPROG} --eraseall -f ${NRF_TARGET}
COMMENT "erasing flashing"
)
add_custom_target("FLASH_${EXECUTABLE_NAME}"
DEPENDS ${EXECUTABLE_NAME}
COMMAND ${NRFJPROG} --program ${EXECUTABLE_FILE_NAME}.hex -f ${NRF_TARGET} --sectorerase
COMMAND sleep 0.5s
COMMAND ${NRFJPROG} --reset -f ${NRF_TARGET}
COMMENT "flashing ${EXECUTABLE_FILE_NAME}.hex"
)
add_custom_target(FLASH_ERASE
COMMAND ${NRFJPROG} --eraseall -f ${NRF_TARGET}
COMMENT "erasing flashing"
)
add_custom_target("FLASH_${EXECUTABLE_NAME}"
DEPENDS ${EXECUTABLE_NAME}
COMMAND ${NRFJPROG} --program ${EXECUTABLE_FILE_NAME}.hex -f ${NRF_TARGET} --sectorerase
COMMAND sleep 0.5s
COMMAND ${NRFJPROG} --reset -f ${NRF_TARGET}
COMMENT "flashing ${EXECUTABLE_FILE_NAME}.hex"
)
elseif (USE_GDB_CLIENT)
add_custom_target(FLASH_ERASE
COMMAND ${GDB_CLIENT_BIN_PATH} -nx --batch -ex 'target extended-remote ${GDB_CLIENT_TARGET_REMOTE}' -ex 'monitor swdp_scan' -ex 'attach 1' -ex 'mon erase_mass'
COMMENT "erasing flashing"
)
add_custom_target("FLASH_${EXECUTABLE_NAME}"
DEPENDS ${EXECUTABLE_NAME}
COMMAND ${GDB_CLIENT_BIN_PATH} -nx --batch -ex 'target extended-remote ${GDB_CLIENT_TARGET_REMOTE}' -ex 'monitor swdp_scan' -ex 'attach 1' -ex 'load' -ex 'kill' ${EXECUTABLE_FILE_NAME}.hex
COMMENT "flashing ${EXECUTABLE_FILE_NAME}.hex"
)
elseif (USE_OPENOCD)
if (USE_CMSIS_DAP)
add_custom_target(FLASH_ERASE
COMMAND ${GDB_CLIENT_BIN_PATH} -nx --batch -ex 'target extended-remote ${GDB_CLIENT_TARGET_REMOTE}' -ex 'monitor swdp_scan' -ex 'attach 1' -ex 'mon erase_mass'
COMMAND ${OPENOCD_BIN_PATH} -c 'source [find interface/cmsis-dap.cfg]' -c 'transport select swd'
-c 'source [find target/nrf52.cfg]'
-c 'init'
-c 'halt'
-c 'nrf5 mass_erase'
-c 'halt'
-c 'reset'
-c 'exit'
COMMENT "erasing flashing"
)
add_custom_target("FLASH_${EXECUTABLE_NAME}"
DEPENDS ${EXECUTABLE_NAME}
COMMAND ${GDB_CLIENT_BIN_PATH} -nx --batch -ex 'target extended-remote ${GDB_CLIENT_TARGET_REMOTE}' -ex 'monitor swdp_scan' -ex 'attach 1' -ex 'load' -ex 'kill' ${EXECUTABLE_FILE_NAME}.hex
COMMAND ${OPENOCD_BIN_PATH}
-c 'tcl_port disabled'
-c 'gdb_port 3333'
-c 'telnet_port 4444'
-c 'source [find interface/cmsis-dap.cfg]'
-c 'transport select swd'
-c 'source [find target/nrf52.cfg]'
-c 'halt'
-c "program \"${EXECUTABLE_FILE_NAME}.hex\""
-c 'reset'
-c 'shutdown'
COMMENT "flashing ${EXECUTABLE_BIN_NAME}.hex"
)
else ()
add_custom_target(FLASH_ERASE
COMMAND ${OPENOCD_BIN_PATH} -f interface/stlink.cfg -c 'transport select hla_swd' -f target/nrf52.cfg -c init -c halt -c 'nrf5 mass_erase' -c reset -c shutdown
COMMENT "erasing flashing"
)
add_custom_target("FLASH_${EXECUTABLE_NAME}"
DEPENDS ${EXECUTABLE_NAME}
COMMAND ${OPENOCD_BIN_PATH} -c "tcl_port disabled" -c "gdb_port 3333" -c "telnet_port 4444" -f interface/stlink.cfg -c 'transport select hla_swd' -f target/nrf52.cfg -c "program \"${EXECUTABLE_FILE_NAME}.hex\"" -c reset -c shutdown
COMMENT "flashing ${EXECUTABLE_FILE_NAME}.hex"
)
elseif (USE_OPENOCD)
if (USE_CMSIS_DAP)
add_custom_target(FLASH_ERASE
COMMAND ${OPENOCD_BIN_PATH} -c 'source [find interface/cmsis-dap.cfg]' -c 'transport select swd'
-c 'source [find target/nrf52.cfg]'
-c 'init'
-c 'halt'
-c 'nrf5 mass_erase'
-c 'halt'
-c 'reset'
-c 'exit'
COMMENT "erasing flashing"
)
add_custom_target("FLASH_${EXECUTABLE_NAME}"
DEPENDS ${EXECUTABLE_NAME}
COMMAND ${OPENOCD_BIN_PATH}
-c 'tcl_port disabled'
-c 'gdb_port 3333'
-c 'telnet_port 4444'
-c 'source [find interface/cmsis-dap.cfg]'
-c 'transport select swd'
-c 'source [find target/nrf52.cfg]'
-c 'halt'
-c "program \"${EXECUTABLE_FILE_NAME}.hex\""
-c 'reset'
-c 'shutdown'
COMMENT "flashing ${EXECUTABLE_BIN_NAME}.hex"
)
else ()
add_custom_target(FLASH_ERASE
COMMAND ${OPENOCD_BIN_PATH} -f interface/stlink.cfg -c 'transport select hla_swd' -f target/nrf52.cfg -c init -c halt -c 'nrf5 mass_erase' -c reset -c shutdown
COMMENT "erasing flashing"
)
add_custom_target("FLASH_${EXECUTABLE_NAME}"
DEPENDS ${EXECUTABLE_NAME}
COMMAND ${OPENOCD_BIN_PATH} -c "tcl_port disabled" -c "gdb_port 3333" -c "telnet_port 4444" -f interface/stlink.cfg -c 'transport select hla_swd' -f target/nrf52.cfg -c "program \"${EXECUTABLE_FILE_NAME}.hex\"" -c reset -c shutdown
COMMENT "flashing ${EXECUTABLE_FILE_NAME}.hex"
)
endif ()
endif ()
endif ()

View File

@@ -1,6 +1,7 @@
#include "components/ble/NotificationManager.h"
#include <cstring>
#include <algorithm>
#include <cassert>
using namespace Pinetime::Controllers;
@@ -9,73 +10,117 @@ constexpr uint8_t NotificationManager::MessageSize;
void NotificationManager::Push(NotificationManager::Notification&& notif) {
notif.id = GetNextId();
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;
}
NotificationManager::Notification NotificationManager::GetLastNotification() {
NotificationManager::Notification notification = notifications[readIndex];
notification.index = 1;
return notification;
if (beginIdx > 0) {
--beginIdx;
} else {
beginIdx = notifications.size() - 1;
}
notifications[beginIdx] = std::move(notif);
if (size < notifications.size()) {
size++;
}
}
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)
NotificationManager::Notification NotificationManager::GetLastNotification() const {
if (this->IsEmpty()) {
return {};
result.index = (lastNotification.id - result.id) + 1;
return result;
}
return this->At(0);
}
NotificationManager::Notification NotificationManager::GetPrevious(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.begin())
result = *(notifications.end() - 1);
else
result = *(currentIterator - 1);
if (result.id >= id)
return {};
result.index = (lastNotification.id - result.id) + 1;
return result;
const NotificationManager::Notification& NotificationManager::At(NotificationManager::Notification::Idx idx) const {
if (idx >= notifications.size()) {
assert(false);
return notifications.at(beginIdx); // this should not happen
}
size_t read_idx = (beginIdx + idx) % notifications.size();
return notifications.at(read_idx);
}
bool NotificationManager::AreNewNotificationsAvailable() {
NotificationManager::Notification& NotificationManager::At(NotificationManager::Notification::Idx idx) {
if (idx >= notifications.size()) {
assert(false);
return notifications.at(beginIdx); // this should not happen
}
size_t read_idx = (beginIdx + idx) % notifications.size();
return notifications.at(read_idx);
}
NotificationManager::Notification::Idx NotificationManager::IndexOf(NotificationManager::Notification::Id id) const {
for (NotificationManager::Notification::Idx idx = 0; idx < this->size; idx++) {
const NotificationManager::Notification& notification = this->At(idx);
if (notification.id == id) {
return idx;
}
}
return size;
}
NotificationManager::Notification NotificationManager::Get(NotificationManager::Notification::Id id) const {
NotificationManager::Notification::Idx idx = this->IndexOf(id);
if (idx == this->size) {
return {};
}
return this->At(idx);
}
NotificationManager::Notification NotificationManager::GetNext(NotificationManager::Notification::Id id) const {
NotificationManager::Notification::Idx idx = this->IndexOf(id);
if (idx == this->size) {
return {};
}
if (idx == 0 || idx > notifications.size()) {
return {};
}
return this->At(idx - 1);
}
NotificationManager::Notification NotificationManager::GetPrevious(NotificationManager::Notification::Id id) const {
NotificationManager::Notification::Idx idx = this->IndexOf(id);
if (idx == this->size) {
return {};
}
if (static_cast<size_t>(idx + 1) >= notifications.size()) {
return {};
}
return this->At(idx + 1);
}
void NotificationManager::DismissIdx(NotificationManager::Notification::Idx 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(beginIdx).valid = false;
beginIdx = (beginIdx + 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;
}
void NotificationManager::Dismiss(NotificationManager::Notification::Id id) {
NotificationManager::Notification::Idx idx = this->IndexOf(id);
if (idx == this->size) {
return;
}
this->DismissIdx(idx);
}
bool NotificationManager::AreNewNotificationsAvailable() const {
return newNotification;
}
@@ -84,9 +129,7 @@ bool NotificationManager::ClearNewNotificationFlag() {
}
size_t NotificationManager::NbNotifications() const {
return std::count_if(notifications.begin(), notifications.end(), [](const Notification& n) {
return n.valid;
});
return size;
}
const char* NotificationManager::Notification::Message() const {

View File

@@ -26,9 +26,9 @@ namespace Pinetime {
struct Notification {
using Id = uint8_t;
Id id;
using Idx = uint8_t;
Id id = 0;
bool valid = false;
uint8_t index;
uint8_t size;
std::array<char, MessageSize + 1> message;
Categories category = Categories::Unknown;
@@ -36,27 +36,38 @@ namespace Pinetime {
const char* Message() const;
const char* Title() const;
};
Notification::Id nextId {0};
void Push(Notification&& notif);
Notification GetLastNotification();
Notification GetNext(Notification::Id id);
Notification GetPrevious(Notification::Id id);
Notification GetLastNotification() const;
Notification Get(Notification::Id id) const;
Notification GetNext(Notification::Id id) const;
Notification GetPrevious(Notification::Id id) const;
// Return the index of the notification with the specified id, if not found return NbNotifications()
Notification::Idx IndexOf(Notification::Id id) const;
bool ClearNewNotificationFlag();
bool AreNewNotificationsAvailable();
bool AreNewNotificationsAvailable() const;
void Dismiss(Notification::Id id);
static constexpr size_t MaximumMessageSize() {
return MessageSize;
};
bool IsEmpty() const {
return size == 0;
}
size_t NbNotifications() const;
private:
Notification::Id nextId {0};
Notification::Id GetNextId();
const Notification& At(Notification::Idx idx) const;
Notification& At(Notification::Idx idx);
void DismissIdx(Notification::Idx idx);
static constexpr uint8_t TotalNbNotifications = 5;
std::array<Notification, TotalNbNotifications> notifications;
uint8_t readIndex = 0;
uint8_t writeIndex = 0;
bool empty = true;
size_t beginIdx = TotalNbNotifications - 1; // index of the newest notification
size_t size = 0; // number of valid notifications in buffer
std::atomic<bool> newNotification {false};
};
}

View File

@@ -74,14 +74,6 @@ BrightnessController::Levels BrightnessController::Level() const {
return level;
}
void BrightnessController::Backup() {
backupLevel = level;
}
void BrightnessController::Restore() {
Set(backupLevel);
}
void BrightnessController::Step() {
switch (level) {
case Levels::Low:
@@ -123,4 +115,4 @@ const char* BrightnessController::ToString() {
default:
return "???";
}
}
}

View File

@@ -15,15 +15,11 @@ namespace Pinetime {
void Higher();
void Step();
void Backup();
void Restore();
const char* GetIcon();
const char* ToString();
private:
Levels level = Levels::High;
Levels backupLevel = Levels::High;
};
}
}

View File

@@ -9,7 +9,7 @@ namespace Pinetime {
class Settings {
public:
enum class ClockType : uint8_t { H24, H12 };
enum class Notification : uint8_t { ON, OFF };
enum class Notification : uint8_t { On, Off, Sleep };
enum class ChimesOption : uint8_t { None, Hours, HalfHours };
enum class WakeUpMode : uint8_t {
SingleTap = 0,
@@ -251,7 +251,7 @@ namespace Pinetime {
uint32_t screenTimeOut = 15000;
ClockType clockType = ClockType::H24;
Notification notificationStatus = Notification::ON;
Notification notificationStatus = Notification::On;
uint8_t clockFace = 0;
ChimesOption chimesOption = ChimesOption::None;

View File

@@ -129,6 +129,10 @@ void DisplayApp::InitHw() {
}
void DisplayApp::Refresh() {
auto LoadPreviousScreen = [this]() {
LoadApp(returnToApp, returnDirection);
};
TickType_t queueTimeout;
switch (state) {
case States::Idle:
@@ -136,7 +140,7 @@ void DisplayApp::Refresh() {
break;
case States::Running:
if (!currentScreen->IsRunning()) {
LoadApp(returnToApp, returnDirection);
LoadPreviousScreen();
}
queueTimeout = lv_task_handler();
break;
@@ -149,12 +153,10 @@ void DisplayApp::Refresh() {
if (xQueueReceive(msgQueue, &msg, queueTimeout)) {
switch (msg) {
case Messages::DimScreen:
// Backup brightness is the brightness to return to after dimming or sleeping
brightnessController.Backup();
brightnessController.Set(Controllers::BrightnessController::Levels::Low);
break;
case Messages::RestoreBrightness:
brightnessController.Restore();
brightnessController.Set(settingsController.GetBrightness());
break;
case Messages::GoToSleep:
while (brightnessController.Level() != Controllers::BrightnessController::Levels::Off) {
@@ -165,7 +167,7 @@ void DisplayApp::Refresh() {
state = States::Idle;
break;
case Messages::GoToRunning:
brightnessController.Restore();
brightnessController.Set(settingsController.GetBrightness());
state = States::Running;
break;
case Messages::UpdateTimeOut:
@@ -181,7 +183,7 @@ void DisplayApp::Refresh() {
case Messages::TimerDone:
if (currentApp == Apps::Timer) {
auto* timer = static_cast<Screens::Timer*>(currentScreen.get());
timer->SetDone();
timer->Reset();
} else {
LoadApp(Apps::Timer, DisplayApp::FullRefreshDirections::Down);
}
@@ -224,9 +226,7 @@ void DisplayApp::Refresh() {
break;
}
} else if (returnTouchEvent == gesture) {
LoadApp(returnToApp, returnDirection);
brightnessController.Set(settingsController.GetBrightness());
brightnessController.Backup();
LoadPreviousScreen();
}
} else {
touchHandler.CancelTap();
@@ -237,9 +237,7 @@ void DisplayApp::Refresh() {
if (currentApp == Apps::Clock) {
PushMessageToSystemTask(System::Messages::GoToSleep);
} else {
LoadApp(returnToApp, returnDirection);
brightnessController.Set(settingsController.GetBrightness());
brightnessController.Backup();
LoadPreviousScreen();
}
}
break;
@@ -303,6 +301,8 @@ void DisplayApp::ReturnApp(Apps app, DisplayApp::FullRefreshDirections direction
void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) {
touchHandler.CancelTap();
brightnessController.Set(settingsController.GetBrightness());
currentScreen.reset(nullptr);
SetFullRefresh(direction);
@@ -311,7 +311,8 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
switch (app) {
case Apps::Launcher:
currentScreen = std::make_unique<Screens::ApplicationList>(this, settingsController, batteryController, dateTimeController);
currentScreen =
std::make_unique<Screens::ApplicationList>(this, settingsController, batteryController, bleController, dateTimeController);
ReturnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::SwipeDown);
break;
case Apps::None:
@@ -367,7 +368,7 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
currentScreen = std::make_unique<Screens::Timer>(this, timerController);
break;
case Apps::Alarm:
currentScreen = std::make_unique<Screens::Alarm>(this, alarmController, settingsController, *systemTask);
currentScreen = std::make_unique<Screens::Alarm>(this, alarmController, settingsController.GetClockType(), *systemTask);
break;
// Settings
@@ -377,7 +378,8 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
dateTimeController,
brightnessController,
motorController,
settingsController);
settingsController,
bleController);
ReturnApp(Apps::Clock, FullRefreshDirections::LeftAnim, TouchEvents::SwipeLeft);
break;
case Apps::Settings:

View File

@@ -1,41 +1,13 @@
/**
* @file lv_pinetime_theme.c
*
*/
#include "displayapp/InfiniTimeTheme.h"
/*********************
* INCLUDES
*********************/
#include "displayapp/lv_pinetime_theme.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void theme_apply(lv_obj_t* obj, lv_theme_style_t name);
/**********************
* STATIC VARIABLES
**********************/
static lv_theme_t theme;
static lv_style_t style_circle;
static lv_style_t style_bg;
static lv_style_t style_box;
static lv_style_t style_box_border;
static lv_style_t style_btn;
static lv_style_t style_btn_border;
static lv_style_t style_title;
static lv_style_t style_label_white;
static lv_style_t style_back;
static lv_style_t style_icon;
static lv_style_t style_bar_indic;
static lv_style_t style_slider_knob;
@@ -51,7 +23,6 @@ static lv_style_t style_arc_knob;
static lv_style_t style_arc_indic;
static lv_style_t style_table_cell;
static lv_style_t style_pad_small;
static lv_style_t style_bg_grad;
static lv_style_t style_lmeter;
static lv_style_t style_chart_serie;
static lv_style_t style_cb_bg;
@@ -59,26 +30,15 @@ static lv_style_t style_cb_bullet;
static bool inited;
/**********************
* MACROS
**********************/
/**********************
* STATIC FUNCTIONS
**********************/
static void style_init_reset(lv_style_t* style) {
if (inited)
if (inited) {
lv_style_reset(style);
else
} else {
lv_style_init(style);
}
}
static void basic_init(void) {
style_init_reset(&style_circle);
lv_style_set_radius(&style_circle, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
static void basic_init() {
style_init_reset(&style_bg);
lv_style_set_bg_opa(&style_bg, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_bg, LV_STATE_DEFAULT, LV_COLOR_BLACK);
@@ -87,41 +47,27 @@ static void basic_init(void) {
style_init_reset(&style_box);
lv_style_set_bg_opa(&style_box, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_radius(&style_box, LV_STATE_DEFAULT, 10);
lv_style_set_value_color(&style_box, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
lv_style_set_value_color(&style_box, LV_STATE_DEFAULT, Colors::bg);
lv_style_set_value_font(&style_box, LV_STATE_DEFAULT, theme.font_normal);
style_init_reset(&style_box_border);
lv_style_set_bg_opa(&style_box_border, LV_STATE_DEFAULT, LV_OPA_TRANSP);
lv_style_set_border_width(&style_box_border, LV_STATE_DEFAULT, 2);
lv_style_set_border_color(&style_box_border, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
lv_style_set_text_color(&style_box, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
style_init_reset(&style_title);
lv_style_set_text_color(&style_title, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
lv_style_set_text_font(&style_title, LV_STATE_DEFAULT, theme.font_subtitle);
style_init_reset(&style_label_white);
lv_style_set_text_color(&style_label_white, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
lv_style_set_text_color(&style_label_white, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_style_set_text_color(&style_label_white, LV_STATE_DISABLED, LV_COLOR_GRAY);
style_init_reset(&style_btn);
lv_style_set_radius(&style_btn, LV_STATE_DEFAULT, 10);
lv_style_set_bg_opa(&style_btn, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_btn, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
lv_style_set_bg_color(&style_btn, LV_STATE_CHECKED, LV_COLOR_MAKE(0x0, 0xb0, 0x0));
lv_style_set_bg_color(&style_btn, LV_STATE_DISABLED, LV_PINETIME_BLUE);
lv_style_set_bg_color(&style_btn, LV_STATE_DISABLED | LV_STATE_CHECKED, lv_color_hex3(0x888));
lv_style_set_border_color(&style_btn, LV_STATE_DEFAULT, theme.color_primary);
lv_style_set_bg_color(&style_btn, LV_STATE_DEFAULT, Colors::bg);
lv_style_set_bg_color(&style_btn, LV_STATE_CHECKED, Colors::highlight);
lv_style_set_bg_color(&style_btn, LV_STATE_DISABLED, Colors::bgDark);
lv_style_set_border_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_style_set_border_width(&style_btn, LV_STATE_DEFAULT, 0);
lv_style_set_text_color(&style_btn, LV_STATE_DEFAULT, lv_color_hex(0xffffff));
lv_style_set_text_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
lv_style_set_text_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
lv_style_set_text_color(&style_btn, LV_STATE_DISABLED, lv_color_hex(0x888888));
lv_style_set_text_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_style_set_text_color(&style_btn, LV_STATE_DISABLED, LV_COLOR_GRAY);
lv_style_set_value_color(&style_btn, LV_STATE_DEFAULT, lv_color_hex(0xffffff));
lv_style_set_value_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
lv_style_set_value_color(&style_btn, LV_STATE_CHECKED, lv_color_hex(0xffffff));
lv_style_set_value_color(&style_btn, LV_STATE_DISABLED, lv_color_hex(0x888888));
lv_style_set_value_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_style_set_value_color(&style_btn, LV_STATE_DISABLED, LV_COLOR_GRAY);
lv_style_set_pad_left(&style_btn, LV_STATE_DEFAULT, LV_DPX(20));
lv_style_set_pad_right(&style_btn, LV_STATE_DEFAULT, LV_DPX(20));
@@ -130,27 +76,12 @@ static void basic_init(void) {
lv_style_set_pad_inner(&style_btn, LV_STATE_DEFAULT, LV_DPX(15));
lv_style_set_outline_width(&style_btn, LV_STATE_DEFAULT, LV_DPX(2));
lv_style_set_outline_opa(&style_btn, LV_STATE_DEFAULT, LV_OPA_0);
lv_style_set_outline_color(&style_btn, LV_STATE_DEFAULT, theme.color_primary);
lv_style_set_outline_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_style_set_transition_time(&style_btn, LV_STATE_DEFAULT, 0);
lv_style_set_transition_delay(&style_btn, LV_STATE_DEFAULT, 0);
style_init_reset(&style_btn_border);
lv_style_set_radius(&style_btn_border, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
lv_style_set_border_color(&style_btn_border, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
lv_style_set_border_width(&style_btn_border, LV_STATE_DEFAULT, 2);
lv_style_set_bg_opa(&style_btn_border, LV_STATE_DEFAULT, LV_OPA_TRANSP);
lv_style_set_bg_color(&style_btn_border, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
lv_style_set_text_color(&style_btn_border, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
lv_style_set_value_color(&style_btn_border, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
lv_style_set_transition_prop_3(&style_btn_border, LV_STATE_DEFAULT, LV_STYLE_BG_OPA);
style_init_reset(&style_icon);
lv_style_set_text_color(&style_icon, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
style_init_reset(&style_back);
lv_style_set_value_color(&style_back, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
lv_style_set_value_str(&style_back, LV_STATE_DEFAULT, LV_SYMBOL_LEFT);
lv_style_set_value_font(&style_back, LV_STATE_DEFAULT, theme.font_subtitle);
lv_style_set_text_color(&style_icon, LV_STATE_DEFAULT, LV_COLOR_WHITE);
style_init_reset(&style_bar_indic);
lv_style_set_bg_opa(&style_bar_indic, LV_STATE_DEFAULT, LV_OPA_COVER);
@@ -165,15 +96,11 @@ static void basic_init(void) {
style_init_reset(&style_list_btn);
lv_style_set_bg_opa(&style_list_btn, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_list_btn, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
lv_style_set_bg_color(&style_list_btn, LV_STATE_CHECKED, LV_PINETIME_GRAY);
lv_style_set_bg_color(&style_list_btn, LV_STATE_CHECKED | LV_STATE_PRESSED, lv_color_darken(LV_PINETIME_GRAY, LV_OPA_20));
lv_style_set_text_color(&style_list_btn, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
lv_style_set_text_color(&style_list_btn, LV_STATE_CHECKED, LV_PINETIME_WHITE);
lv_style_set_text_color(&style_list_btn, LV_STATE_CHECKED | LV_STATE_PRESSED, LV_PINETIME_WHITE);
lv_style_set_image_recolor(&style_list_btn, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
lv_style_set_image_recolor(&style_list_btn, LV_STATE_CHECKED, LV_PINETIME_WHITE);
lv_style_set_image_recolor(&style_list_btn, LV_STATE_CHECKED | LV_STATE_PRESSED, LV_PINETIME_WHITE);
lv_style_set_bg_color(&style_list_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_style_set_text_color(&style_list_btn, LV_STATE_DEFAULT, Colors::bg);
lv_style_set_text_color(&style_list_btn, LV_STATE_CHECKED, LV_COLOR_WHITE);
lv_style_set_image_recolor(&style_list_btn, LV_STATE_DEFAULT, Colors::bg);
lv_style_set_image_recolor(&style_list_btn, LV_STATE_CHECKED, LV_COLOR_WHITE);
lv_style_set_pad_left(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 25);
lv_style_set_pad_right(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 25);
lv_style_set_pad_top(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 100);
@@ -182,25 +109,23 @@ static void basic_init(void) {
style_init_reset(&style_ddlist_list);
// Causes lag unfortunately, so we'll have to live with the selected item overflowing the corner
//lv_style_set_clip_corner(&style_ddlist_list, LV_STATE_DEFAULT, true);
// lv_style_set_clip_corner(&style_ddlist_list, LV_STATE_DEFAULT, true);
lv_style_set_text_line_space(&style_ddlist_list, LV_STATE_DEFAULT, LV_VER_RES / 25);
lv_style_set_shadow_width(&style_ddlist_list, LV_STATE_DEFAULT, LV_VER_RES / 20);
lv_style_set_shadow_color(&style_ddlist_list, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0));
lv_style_set_bg_color(&style_ddlist_list, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0));
lv_style_set_bg_color(&style_ddlist_list, LV_STATE_DEFAULT, Colors::lightGray);
lv_style_set_pad_all(&style_ddlist_list, LV_STATE_DEFAULT, 20);
style_init_reset(&style_ddlist_selected);
lv_style_set_bg_opa(&style_ddlist_selected, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_ddlist_selected, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
lv_style_set_bg_color(&style_ddlist_selected, LV_STATE_DEFAULT, Colors::bg);
style_init_reset(&style_sw_bg);
lv_style_set_bg_opa(&style_sw_bg, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_sw_bg, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
lv_style_set_bg_color(&style_sw_bg, LV_STATE_DEFAULT, Colors::bg);
lv_style_set_radius(&style_sw_bg, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
style_init_reset(&style_sw_indic);
lv_style_set_bg_opa(&style_sw_indic, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_sw_indic, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x0, 0xb0, 0x0));
lv_style_set_bg_color(&style_sw_indic, LV_STATE_DEFAULT, Colors::highlight);
style_init_reset(&style_sw_knob);
lv_style_set_bg_opa(&style_sw_knob, LV_STATE_DEFAULT, LV_OPA_COVER);
@@ -228,12 +153,12 @@ static void basic_init(void) {
lv_style_set_pad_right(&style_slider_knob, LV_STATE_PRESSED, 14);
style_init_reset(&style_arc_indic);
lv_style_set_line_color(&style_arc_indic, LV_STATE_DEFAULT, LV_PINETIME_BLUE);
lv_style_set_line_color(&style_arc_indic, LV_STATE_DEFAULT, Colors::lightGray);
lv_style_set_line_width(&style_arc_indic, LV_STATE_DEFAULT, LV_DPX(25));
lv_style_set_line_rounded(&style_arc_indic, LV_STATE_DEFAULT, true);
style_init_reset(&style_arc_bg);
lv_style_set_line_color(&style_arc_bg, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0));
lv_style_set_line_color(&style_arc_bg, LV_STATE_DEFAULT, Colors::bg);
lv_style_set_line_width(&style_arc_bg, LV_STATE_DEFAULT, LV_DPX(25));
lv_style_set_line_rounded(&style_arc_bg, LV_STATE_DEFAULT, true);
lv_style_set_pad_all(&style_arc_bg, LV_STATE_DEFAULT, LV_DPX(5));
@@ -245,7 +170,7 @@ static void basic_init(void) {
lv_style_set_pad_all(&style_arc_knob, LV_STATE_DEFAULT, LV_DPX(5));
style_init_reset(&style_table_cell);
lv_style_set_border_color(&style_table_cell, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
lv_style_set_border_color(&style_table_cell, LV_STATE_DEFAULT, LV_COLOR_GRAY);
lv_style_set_border_width(&style_table_cell, LV_STATE_DEFAULT, 1);
lv_style_set_border_side(&style_table_cell, LV_STATE_DEFAULT, LV_BORDER_SIDE_FULL);
lv_style_set_pad_left(&style_table_cell, LV_STATE_DEFAULT, 5);
@@ -261,11 +186,6 @@ static void basic_init(void) {
lv_style_set_pad_bottom(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
lv_style_set_pad_inner(&style_pad_small, LV_STATE_DEFAULT, pad_small_value);
style_init_reset(&style_bg_grad);
lv_style_set_bg_color(&style_bg_grad, LV_STATE_DEFAULT, lv_color_hsv_to_rgb(10, 10, 40));
lv_style_set_bg_grad_color(&style_bg_grad, LV_STATE_DEFAULT, lv_color_hsv_to_rgb(10, 10, 20));
lv_style_set_bg_grad_dir(&style_bg_grad, LV_STATE_DEFAULT, LV_GRAD_DIR_VER);
style_init_reset(&style_lmeter);
lv_style_set_radius(&style_lmeter, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
lv_style_set_pad_left(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(20));
@@ -274,30 +194,30 @@ static void basic_init(void) {
lv_style_set_pad_inner(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(30));
lv_style_set_scale_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(25));
lv_style_set_line_color(&style_lmeter, LV_STATE_DEFAULT, theme.color_primary);
lv_style_set_scale_grad_color(&style_lmeter, LV_STATE_DEFAULT, theme.color_primary);
lv_style_set_scale_end_color(&style_lmeter, LV_STATE_DEFAULT, lv_color_hex3(0x888));
lv_style_set_line_color(&style_lmeter, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_style_set_scale_grad_color(&style_lmeter, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_style_set_scale_end_color(&style_lmeter, LV_STATE_DEFAULT, LV_COLOR_GRAY);
lv_style_set_line_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(10));
lv_style_set_scale_end_line_width(&style_lmeter, LV_STATE_DEFAULT, LV_DPX(7));
style_init_reset(&style_chart_serie);
lv_style_set_line_color(&style_chart_serie, LV_STATE_DEFAULT, LV_PINETIME_WHITE);
lv_style_set_line_color(&style_chart_serie, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_style_set_line_width(&style_chart_serie, LV_STATE_DEFAULT, 4);
lv_style_set_size(&style_chart_serie, LV_STATE_DEFAULT, 4);
lv_style_set_bg_opa(&style_chart_serie, LV_STATE_DEFAULT, 0);
lv_style_reset(&style_cb_bg);
lv_style_set_radius(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(4));
lv_style_set_pad_inner(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(10));
lv_style_set_outline_color(&style_cb_bg, LV_STATE_DEFAULT, theme.color_primary);
lv_style_set_pad_inner(&style_cb_bg, LV_STATE_DEFAULT, 18);
lv_style_set_outline_color(&style_cb_bg, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_style_set_outline_width(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(2));
lv_style_set_outline_pad(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(20));
lv_style_set_transition_time(&style_cb_bg, LV_STATE_DEFAULT, 0);
lv_style_set_transition_prop_6(&style_cb_bg, LV_STATE_DEFAULT, LV_STYLE_OUTLINE_OPA);
lv_style_reset(&style_cb_bullet);
lv_style_set_outline_opa(&style_cb_bullet, LV_STATE_FOCUSED, LV_OPA_TRANSP);
lv_style_set_radius(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(4));
lv_style_set_pattern_image(&style_cb_bullet, LV_STATE_CHECKED, LV_SYMBOL_OK);
lv_style_set_pattern_recolor(&style_cb_bullet, LV_STATE_CHECKED, LV_COLOR_WHITE);
lv_style_set_pad_left(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8));
lv_style_set_pad_right(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8));
@@ -305,10 +225,6 @@ static void basic_init(void) {
lv_style_set_pad_bottom(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8));
}
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Initialize the default
* @param color_primary the primary color of the theme
@@ -347,9 +263,7 @@ lv_theme_t* lv_pinetime_theme_init(lv_color_t color_primary,
static void theme_apply(lv_obj_t* obj, lv_theme_style_t name) {
lv_style_list_t* list;
/*To avoid warnings*/
uint32_t name_int = (uint32_t) name;
switch (name_int) {
switch (name) {
case LV_THEME_NONE:
break;
@@ -376,7 +290,6 @@ static void theme_apply(lv_obj_t* obj, lv_theme_style_t name) {
lv_obj_clean_style_list(obj, LV_BTN_PART_MAIN);
list = lv_obj_get_style_list(obj, LV_BTN_PART_MAIN);
_lv_style_list_add_style(list, &style_btn);
//_lv_style_list_add_style(list, &style_bg_grad);
break;
case LV_THEME_BTNMATRIX:
@@ -386,8 +299,6 @@ static void theme_apply(lv_obj_t* obj, lv_theme_style_t name) {
list = lv_obj_get_style_list(obj, LV_BTNMATRIX_PART_BTN);
_lv_style_list_add_style(list, &style_btn);
//_lv_style_list_add_style(list, &style_bg_grad);
//_lv_style_list_add_style(list, &style_bg_click);
break;
case LV_THEME_BAR:
@@ -490,7 +401,7 @@ static void theme_apply(lv_obj_t* obj, lv_theme_style_t name) {
_lv_style_list_add_style(list, &style_scrollbar);
break;
case LV_THEME_TABLE:
case LV_THEME_TABLE: {
list = lv_obj_get_style_list(obj, LV_TABLE_PART_BG);
_lv_style_list_add_style(list, &style_bg);
@@ -503,7 +414,7 @@ static void theme_apply(lv_obj_t* obj, lv_theme_style_t name) {
_lv_style_list_add_style(list, &style_table_cell);
_lv_style_list_add_style(list, &style_label_white);
}
break;
} break;
case LV_THEME_LINEMETER:
list = lv_obj_get_style_list(obj, LV_LINEMETER_PART_MAIN);
@@ -533,7 +444,3 @@ static void theme_apply(lv_obj_t* obj, lv_theme_style_t name) {
lv_obj_refresh_style(obj, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL);
}
/**********************
* STATIC FUNCTIONS
**********************/

View File

@@ -1,39 +1,17 @@
/**
* @file lv_pinetime_theme.h
*
*/
#pragma once
#ifndef LV_PINETIME_THEME_H
#define LV_PINETIME_THEME_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include <lvgl/lvgl.h>
/*********************
* DEFINES
*********************/
/*Colors*/
#define LV_PINETIME_WHITE lv_color_hex(0xffffff)
#define LV_PINETIME_LIGHT lv_color_hex(0xf3f8fe)
#define LV_PINETIME_GRAY lv_color_hex(0x8a8a8a)
#define LV_PINETIME_LIGHT_GRAY lv_color_hex(0xc4c4c4)
#define LV_PINETIME_BLUE lv_color_hex(0x5d697e)
#define LV_PINETIME_GREEN lv_color_hex(0x4cb242)
#define LV_PINETIME_RED lv_color_hex(0xd51732)
namespace Colors {
static constexpr lv_color_t orange = LV_COLOR_MAKE(0xff, 0xb0, 0x0);
static constexpr lv_color_t green = LV_COLOR_MAKE(0x0, 0xb0, 0x0);
static constexpr lv_color_t lightGray = LV_COLOR_MAKE(0xb0, 0xb0, 0xb0);
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
static constexpr lv_color_t bg = LV_COLOR_MAKE(0x5d, 0x69, 0x7e);
static constexpr lv_color_t bgAlt = LV_COLOR_MAKE(0x38, 0x38, 0x38);
static constexpr lv_color_t bgDark = LV_COLOR_MAKE(0x18, 0x18, 0x18);
static constexpr lv_color_t highlight = green;
};
/**
* Initialize the default
@@ -53,12 +31,3 @@ lv_theme_t* lv_pinetime_theme_init(lv_color_t color_primary,
const lv_font_t* font_normal,
const lv_font_t* font_subtitle,
const lv_font_t* font_title);
/**********************
* MACROS
**********************/
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif

View File

@@ -1,5 +1,5 @@
#include "displayapp/LittleVgl.h"
#include "displayapp/lv_pinetime_theme.h"
#include "displayapp/InfiniTimeTheme.h"
#include <FreeRTOS.h>
#include <task.h>

View File

@@ -6,6 +6,8 @@ find_program(LV_FONT_CONV "lv_font_conv" NO_CACHE REQUIRED
message(STATUS "Using ${LV_FONT_CONV} to generate font files")
configure_file(${CMAKE_CURRENT_LIST_DIR}/jetbrains_mono_bold_20.c_zero.patch
${CMAKE_CURRENT_BINARY_DIR}/jetbrains_mono_bold_20.c_zero.patch COPYONLY)
configure_file(${CMAKE_CURRENT_LIST_DIR}/jetbrains_mono_bold_20.c_M.patch
${CMAKE_CURRENT_BINARY_DIR}/jetbrains_mono_bold_20.c_M.patch COPYONLY)
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12)
# FindPython3 module introduces with CMake 3.12
# https://cmake.org/cmake/help/latest/module/FindPython3.html

View File

@@ -1,16 +1,19 @@
# Fonts
* [Jetbrains Mono](https://www.jetbrains.com/fr-fr/lp/mono/)
* [Awesome font from LVGL](https://lvgl.io/assets/others/FontAwesome5-Solid+Brands+Regular.woff)
* [Open Sans Light from Google](https://fonts.google.com/specimen/Open+Sans)
- [Jetbrains Mono](https://www.jetbrains.com/lp/mono/)
- [Font Awesome](https://fontawesome.com/v5/cheatsheet/free/solid)
- [Open Sans Light](https://fonts.google.com/specimen/Open+Sans)
- [Material Symbols](https://fonts.google.com/icons)
### How to add new symbols:
* Browse [this cheatsheet](https://fontawesome.com/cheatsheet/free/solid) and pick symbols
* For each symbol, add its hex code (0xf641 for the 'Ad' icon, for example) to the *Range* list (or the symbol list when its simple enough) in the `fonts.json` file
* Convert this hex value into a UTF-8 code
- Browse the cheat sheets and pick symbols
- [Font Awesome](https://fontawesome.com/v5/cheatsheet/free/solid)
- [Material Symbols](https://fonts.google.com/icons)
- For each symbol, add its hex code (0xf641 for the 'Ad' icon, for example) to the *Range* list in the `fonts.json` file
- Convert this hex value into a UTF-8 code
using [this site](http://www.ltg.ed.ac.uk/~richard/utf-8.cgi?input=f185&mode=hex)
* Define the new symbols in `src/displayapp/screens/Symbols.h`:
- Define the new symbols in `src/displayapp/screens/Symbols.h`:
```
static constexpr const char* newSymbol = "\xEF\x86\x85";
@@ -20,11 +23,12 @@ static constexpr const char* newSymbol = "\xEF\x86\x85";
inside `fonts`, there is a dictionary of fonts,
and for each font there is:
* sources - list of file,range(,symbols) wanted (as a dictionary of those)
* bpp - bits per pixel.
* size - size.
* patches - list of extra "patches" to run: a path to a .patch file. (may be relative)
* compress - optional. default disabled. add `"compress": true` to enable
- sources - list of file,range(,symbols) wanted (as a dictionary of those)
- bpp - bits per pixel.
- size - size.
- patches - list of extra "patches" to run: a path to a .patch file. (may be relative)
- compress - optional. default disabled. add `"compress": true` to enable
### Navigation font

View File

@@ -7,12 +7,12 @@
},
{
"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, 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, 0xf00c"
}
],
"bpp": 1,
"size": 20,
"patches": ["jetbrains_mono_bold_20.c_zero.patch"]
"patches": ["jetbrains_mono_bold_20.c_zero.patch", "jetbrains_mono_bold_20.c_M.patch"]
},
"jetbrains_mono_42": {
"sources": [
@@ -57,8 +57,8 @@
"lv_font_sys_48": {
"sources": [
{
"file": "icons_sys_48.ttf",
"range": "0xe902, 0xe904-0xe907, 0xe90b-0xe90c"
"file": "material-design-icons/MaterialIcons-Regular.ttf",
"range": "0xf00b, 0xe3aa-0xe3ac, 0xe7f6-0xe7f7, 0xe8b8, 0xef44"
}
],
"bpp": 1,

View File

@@ -67,7 +67,7 @@ def main():
subprocess.check_call(line)
if patches:
for patch in patches:
subprocess.check_call(['/usr/bin/patch', name+'.c', patch])
subprocess.check_call(['/usr/bin/env', 'patch', name+'.c', patch])

View File

@@ -0,0 +1,8 @@
@@ -217,7 +217,7 @@
0xc0, 0xe0, 0x70, 0x38, 0x1c, 0xf, 0xff, 0xfc,
/* U+004D "M" */
- 0xf3, 0xfc, 0xfd, 0x3f, 0xcf, 0xff, 0xff, 0xfe,
+ 0xf3, 0xfc, 0xff, 0x3f, 0xcf, 0xff, 0xff, 0xfe,
0xdf, 0xb7, 0xe1, 0xf8, 0x7e, 0x1f, 0x87, 0xe1,
0xf8, 0x70,

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -18,10 +18,18 @@
#include "displayapp/screens/Alarm.h"
#include "displayapp/screens/Screen.h"
#include "displayapp/screens/Symbols.h"
#include "displayapp/InfiniTimeTheme.h"
using namespace Pinetime::Applications::Screens;
using Pinetime::Controllers::AlarmController;
namespace {
void ValueChangedHandler(void* userData) {
auto* screen = static_cast<Alarm*>(userData);
screen->OnValueChanged();
}
}
static void btnEventHandler(lv_obj_t* obj, lv_event_t event) {
auto* screen = static_cast<Alarm*>(obj->user_data);
screen->OnButtonEvent(obj, event);
@@ -34,58 +42,33 @@ static void StopAlarmTaskCallback(lv_task_t* task) {
Alarm::Alarm(DisplayApp* app,
Controllers::AlarmController& alarmController,
Pinetime::Controllers::Settings& settingsController,
Controllers::Settings::ClockType clockType,
System::SystemTask& systemTask)
: Screen(app), alarmController {alarmController}, settingsController {settingsController}, systemTask {systemTask} {
: Screen(app), alarmController {alarmController}, systemTask {systemTask} {
time = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0));
hourCounter.Create();
lv_obj_align(hourCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
if (clockType == Controllers::Settings::ClockType::H12) {
hourCounter.EnableTwelveHourMode();
alarmHours = alarmController.Hours();
alarmMinutes = alarmController.Minutes();
lv_label_set_text_fmt(time, "%02hhu:%02hhu", alarmHours, alarmMinutes);
lblampm = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(lblampm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20);
lv_label_set_text_static(lblampm, "AM");
lv_label_set_align(lblampm, LV_LABEL_ALIGN_CENTER);
lv_obj_align(lblampm, lv_scr_act(), LV_ALIGN_CENTER, 0, 30);
}
hourCounter.SetValue(alarmController.Hours());
hourCounter.SetValueChangedEventCallback(this, ValueChangedHandler);
lv_obj_align(time, lv_scr_act(), LV_ALIGN_CENTER, 0, -25);
minuteCounter.Create();
lv_obj_align(minuteCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0);
minuteCounter.SetValue(alarmController.Minutes());
minuteCounter.SetValueChangedEventCallback(this, ValueChangedHandler);
lblampm = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(lblampm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20);
lv_obj_set_style_local_text_color(lblampm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0));
lv_label_set_text_static(lblampm, " ");
lv_label_set_align(lblampm, LV_LABEL_ALIGN_CENTER);
lv_obj_align(lblampm, lv_scr_act(), LV_ALIGN_CENTER, 0, 30);
btnHoursUp = lv_btn_create(lv_scr_act(), nullptr);
btnHoursUp->user_data = this;
lv_obj_set_event_cb(btnHoursUp, btnEventHandler);
lv_obj_set_size(btnHoursUp, 60, 40);
lv_obj_align(btnHoursUp, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 20, -85);
txtHrUp = lv_label_create(btnHoursUp, nullptr);
lv_label_set_text_static(txtHrUp, "+");
btnHoursDown = lv_btn_create(lv_scr_act(), nullptr);
btnHoursDown->user_data = this;
lv_obj_set_event_cb(btnHoursDown, btnEventHandler);
lv_obj_set_size(btnHoursDown, 60, 40);
lv_obj_align(btnHoursDown, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 20, 35);
txtHrDown = lv_label_create(btnHoursDown, nullptr);
lv_label_set_text_static(txtHrDown, "-");
btnMinutesUp = lv_btn_create(lv_scr_act(), nullptr);
btnMinutesUp->user_data = this;
lv_obj_set_event_cb(btnMinutesUp, btnEventHandler);
lv_obj_set_size(btnMinutesUp, 60, 40);
lv_obj_align(btnMinutesUp, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -20, -85);
txtMinUp = lv_label_create(btnMinutesUp, nullptr);
lv_label_set_text_static(txtMinUp, "+");
btnMinutesDown = lv_btn_create(lv_scr_act(), nullptr);
btnMinutesDown->user_data = this;
lv_obj_set_event_cb(btnMinutesDown, btnEventHandler);
lv_obj_set_size(btnMinutesDown, 60, 40);
lv_obj_align(btnMinutesDown, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, -20, 35);
txtMinDown = lv_label_create(btnMinutesDown, nullptr);
lv_label_set_text_static(txtMinDown, "-");
lv_obj_t* colonLabel = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(colonLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
lv_label_set_text_static(colonLabel, ":");
lv_obj_align(colonLabel, lv_scr_act(), LV_ALIGN_CENTER, 0, -29);
btnStop = lv_btn_create(lv_scr_act(), nullptr);
btnStop->user_data = this;
@@ -97,6 +80,8 @@ Alarm::Alarm(DisplayApp* app,
lv_label_set_text_static(txtStop, Symbols::stop);
lv_obj_set_hidden(btnStop, true);
static constexpr lv_color_t bgColor = Colors::bgAlt;
btnRecur = lv_btn_create(lv_scr_act(), nullptr);
btnRecur->user_data = this;
lv_obj_set_event_cb(btnRecur, btnEventHandler);
@@ -104,13 +89,18 @@ Alarm::Alarm(DisplayApp* app,
lv_obj_align(btnRecur, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
txtRecur = lv_label_create(btnRecur, nullptr);
SetRecurButtonState();
lv_obj_set_style_local_bg_color(btnRecur, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, bgColor);
btnInfo = lv_btn_create(lv_scr_act(), nullptr);
btnInfo->user_data = this;
lv_obj_set_event_cb(btnInfo, btnEventHandler);
lv_obj_set_size(btnInfo, 50, 40);
lv_obj_align(btnInfo, lv_scr_act(), LV_ALIGN_CENTER, 0, -85);
txtInfo = lv_label_create(btnInfo, nullptr);
lv_obj_set_size(btnInfo, 50, 50);
lv_obj_align(btnInfo, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, -4);
lv_obj_set_style_local_bg_color(btnInfo, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, bgColor);
lv_obj_set_style_local_border_width(btnInfo, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 4);
lv_obj_set_style_local_border_color(btnInfo, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_obj_t* txtInfo = lv_label_create(btnInfo, nullptr);
lv_label_set_text_static(txtInfo, "i");
enableSwitch = lv_switch_create(lv_scr_act(), nullptr);
@@ -119,6 +109,7 @@ Alarm::Alarm(DisplayApp* app,
lv_obj_set_size(enableSwitch, 100, 50);
// Align to the center of 115px from edge
lv_obj_align(enableSwitch, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 7, 0);
lv_obj_set_style_local_bg_color(enableSwitch, LV_SWITCH_PART_BG, LV_STATE_DEFAULT, bgColor);
UpdateAlarmTime();
@@ -136,8 +127,14 @@ Alarm::~Alarm() {
lv_obj_clean(lv_scr_act());
}
void Alarm::DisableAlarm() {
if (alarmController.State() == AlarmController::AlarmState::Set) {
alarmController.DisableAlarm();
lv_switch_off(enableSwitch, LV_ANIM_ON);
}
}
void Alarm::OnButtonEvent(lv_obj_t* obj, lv_event_t event) {
using Pinetime::Controllers::AlarmController;
if (event == LV_EVENT_CLICKED) {
if (obj == btnStop) {
StopAlerting();
@@ -159,49 +156,8 @@ void Alarm::OnButtonEvent(lv_obj_t* obj, lv_event_t event) {
}
return;
}
// If any other button was pressed, disable the alarm
// this is to make it clear that the alarm won't be set until it is turned back on
if (alarmController.State() == AlarmController::AlarmState::Set) {
alarmController.DisableAlarm();
lv_switch_off(enableSwitch, LV_ANIM_ON);
}
if (obj == btnMinutesUp) {
if (alarmMinutes >= 59) {
alarmMinutes = 0;
} else {
alarmMinutes++;
}
UpdateAlarmTime();
return;
}
if (obj == btnMinutesDown) {
if (alarmMinutes == 0) {
alarmMinutes = 59;
} else {
alarmMinutes--;
}
UpdateAlarmTime();
return;
}
if (obj == btnHoursUp) {
if (alarmHours >= 23) {
alarmHours = 0;
} else {
alarmHours++;
}
UpdateAlarmTime();
return;
}
if (obj == btnHoursDown) {
if (alarmHours == 0) {
alarmHours = 23;
} else {
alarmHours--;
}
UpdateAlarmTime();
return;
}
if (obj == btnRecur) {
DisableAlarm();
ToggleRecurrence();
}
}
@@ -224,30 +180,20 @@ bool Alarm::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
return alarmController.State() == AlarmController::AlarmState::Alerting && event == TouchEvents::SwipeDown;
}
void Alarm::OnValueChanged() {
DisableAlarm();
UpdateAlarmTime();
}
void Alarm::UpdateAlarmTime() {
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
switch (alarmHours) {
case 0:
lv_label_set_text_static(lblampm, "AM");
lv_label_set_text_fmt(time, "%02d:%02d", 12, alarmMinutes);
break;
case 1 ... 11:
lv_label_set_text_static(lblampm, "AM");
lv_label_set_text_fmt(time, "%02d:%02d", alarmHours, alarmMinutes);
break;
case 12:
lv_label_set_text_static(lblampm, "PM");
lv_label_set_text_fmt(time, "%02d:%02d", 12, alarmMinutes);
break;
case 13 ... 23:
lv_label_set_text_static(lblampm, "PM");
lv_label_set_text_fmt(time, "%02d:%02d", alarmHours - 12, alarmMinutes);
break;
if (lblampm != nullptr) {
if (hourCounter.GetValue() >= 12) {
lv_label_set_text_static(lblampm, "PM");
} else {
lv_label_set_text_static(lblampm, "AM");
}
} else {
lv_label_set_text_fmt(time, "%02d:%02d", alarmHours, alarmMinutes);
}
alarmController.SetAlarmTime(alarmHours, alarmMinutes);
alarmController.SetAlarmTime(hourCounter.GetValue(), minuteCounter.GetValue());
}
void Alarm::SetAlerting() {
@@ -283,6 +229,9 @@ void Alarm::SetSwitchState(lv_anim_enable_t anim) {
}
void Alarm::ShowInfo() {
if (btnMessage != nullptr) {
return;
}
btnMessage = lv_btn_create(lv_scr_act(), nullptr);
btnMessage->user_data = this;
lv_obj_set_event_cb(btnMessage, btnEventHandler);

View File

@@ -21,6 +21,7 @@
#include "systemtask/SystemTask.h"
#include "displayapp/LittleVgl.h"
#include "components/alarm/AlarmController.h"
#include "displayapp/widgets/Counter.h"
namespace Pinetime {
namespace Applications {
@@ -29,29 +30,28 @@ namespace Pinetime {
public:
Alarm(DisplayApp* app,
Controllers::AlarmController& alarmController,
Pinetime::Controllers::Settings& settingsController,
Controllers::Settings::ClockType clockType,
System::SystemTask& systemTask);
~Alarm() override;
void SetAlerting();
void OnButtonEvent(lv_obj_t* obj, lv_event_t event);
bool OnButtonPushed() override;
bool OnTouchEvent(TouchEvents event) override;
void OnValueChanged();
void StopAlerting();
private:
uint8_t alarmHours;
uint8_t alarmMinutes;
Controllers::AlarmController& alarmController;
Controllers::Settings& settingsController;
System::SystemTask& systemTask;
lv_obj_t *time, *lblampm, *btnStop, *txtStop, *btnMinutesUp, *btnMinutesDown, *btnHoursUp, *btnHoursDown, *txtMinUp, *txtMinDown,
*txtHrUp, *txtHrDown, *btnRecur, *txtRecur, *btnInfo, *txtInfo, *enableSwitch;
lv_obj_t *btnStop, *txtStop, *btnRecur, *txtRecur, *btnInfo, *enableSwitch;
lv_obj_t* lblampm = nullptr;
lv_obj_t* txtMessage = nullptr;
lv_obj_t* btnMessage = nullptr;
lv_task_t* taskStopAlarm = nullptr;
enum class EnableButtonState { On, Off, Alerting };
void DisableAlarm();
void SetRecurButtonState();
void SetSwitchState(lv_anim_enable_t anim);
void SetAlarm();
@@ -59,6 +59,8 @@ namespace Pinetime {
void HideInfo();
void ToggleRecurrence();
void UpdateAlarmTime();
Widgets::Counter hourCounter = Widgets::Counter(0, 23, jetbrains_mono_76);
Widgets::Counter minuteCounter = Widgets::Counter(0, 59, jetbrains_mono_76);
};
};
};

View File

@@ -1,33 +1,34 @@
#include "displayapp/screens/ApplicationList.h"
#include <lvgl/lvgl.h>
#include <array>
#include "displayapp/screens/Symbols.h"
#include "displayapp/screens/Tile.h"
#include <functional>
#include "displayapp/Apps.h"
#include "displayapp/DisplayApp.h"
using namespace Pinetime::Applications::Screens;
constexpr std::array<Tile::Applications, ApplicationList::applications.size()> ApplicationList::applications;
auto ApplicationList::CreateScreenList() const {
std::array<std::function<std::unique_ptr<Screen>()>, nScreens> screens;
for (size_t i = 0; i < screens.size(); i++) {
screens[i] = [this, i]() -> std::unique_ptr<Screen> {
return CreateScreen(i);
};
}
return screens;
}
ApplicationList::ApplicationList(Pinetime::Applications::DisplayApp* app,
Pinetime::Controllers::Settings& settingsController,
Pinetime::Controllers::Battery& batteryController,
Pinetime::Controllers::Ble& bleController,
Controllers::DateTime& dateTimeController)
: Screen(app),
settingsController {settingsController},
batteryController {batteryController},
bleController {bleController},
dateTimeController {dateTimeController},
screens {app,
settingsController.GetAppMenu(),
{
[this]() -> std::unique_ptr<Screen> {
return CreateScreen1();
},
[this]() -> std::unique_ptr<Screen> {
return CreateScreen2();
},
//[this]() -> std::unique_ptr<Screen> { return CreateScreen3(); }
},
Screens::ScreenListModes::UpDown} {
screens {app, settingsController.GetAppMenu(), CreateScreenList(), Screens::ScreenListModes::UpDown} {
}
ApplicationList::~ApplicationList() {
@@ -38,42 +39,18 @@ bool ApplicationList::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
return screens.OnTouchEvent(event);
}
std::unique_ptr<Screen> ApplicationList::CreateScreen1() {
std::array<Screens::Tile::Applications, 6> applications {{
{Symbols::stopWatch, Apps::StopWatch},
{Symbols::clock, Apps::Alarm},
{Symbols::hourGlass, Apps::Timer},
{Symbols::shoe, Apps::Steps},
{Symbols::heartBeat, Apps::HeartRate},
{Symbols::music, Apps::Music},
}};
std::unique_ptr<Screen> ApplicationList::CreateScreen(unsigned int screenNum) const {
std::array<Tile::Applications, appsPerScreen> apps;
for (int i = 0; i < appsPerScreen; i++) {
apps[i] = applications[screenNum * appsPerScreen + i];
}
return std::make_unique<Screens::Tile>(0, 2, app, settingsController, batteryController, dateTimeController, applications);
return std::make_unique<Screens::Tile>(screenNum,
nScreens,
app,
settingsController,
batteryController,
bleController,
dateTimeController,
apps);
}
std::unique_ptr<Screen> ApplicationList::CreateScreen2() {
std::array<Screens::Tile::Applications, 6> applications {{
{Symbols::paintbrush, Apps::Paint},
{Symbols::paddle, Apps::Paddle},
{"2", Apps::Twos},
{Symbols::chartLine, Apps::Motion},
{Symbols::drum, Apps::Metronome},
{Symbols::map, Apps::Navigation},
}};
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::Meter},
{"B", Apps::Navigation},
{"C", Apps::Clock},
{"D", Apps::Music},
{"E", Apps::SysInfo},
{"F", Apps::Brightness}
}
};
return std::make_unique<Screens::Tile>(2, 3, app, settingsController, batteryController, dateTimeController, applications);
}*/

View File

@@ -1,5 +1,6 @@
#pragma once
#include <array>
#include <memory>
#include "displayapp/screens/Screen.h"
@@ -7,6 +8,8 @@
#include "components/datetime/DateTimeController.h"
#include "components/settings/Settings.h"
#include "components/battery/BatteryController.h"
#include "displayapp/screens/Symbols.h"
#include "displayapp/screens/Tile.h"
namespace Pinetime {
namespace Applications {
@@ -16,19 +19,41 @@ namespace Pinetime {
explicit ApplicationList(DisplayApp* app,
Pinetime::Controllers::Settings& settingsController,
Pinetime::Controllers::Battery& batteryController,
Pinetime::Controllers::Ble& bleController,
Controllers::DateTime& dateTimeController);
~ApplicationList() override;
bool OnTouchEvent(TouchEvents event) override;
private:
auto CreateScreenList() const;
std::unique_ptr<Screen> CreateScreen(unsigned int screenNum) const;
Controllers::Settings& settingsController;
Pinetime::Controllers::Battery& batteryController;
Pinetime::Controllers::Ble& bleController;
Controllers::DateTime& dateTimeController;
ScreenList<2> screens;
std::unique_ptr<Screen> CreateScreen1();
std::unique_ptr<Screen> CreateScreen2();
// std::unique_ptr<Screen> CreateScreen3();
static constexpr int appsPerScreen = 6;
// Increment this when more space is needed
static constexpr int nScreens = 2;
static constexpr std::array<Tile::Applications, appsPerScreen * nScreens> applications {{
{Symbols::stopWatch, Apps::StopWatch},
{Symbols::clock, Apps::Alarm},
{Symbols::hourGlass, Apps::Timer},
{Symbols::shoe, Apps::Steps},
{Symbols::heartBeat, Apps::HeartRate},
{Symbols::music, Apps::Music},
{Symbols::paintbrush, Apps::Paint},
{Symbols::paddle, Apps::Paddle},
{"2", Apps::Twos},
{Symbols::chartLine, Apps::Motion},
{Symbols::drum, Apps::Metronome},
{Symbols::map, Apps::Navigation},
}};
ScreenList<nScreens> screens;
};
}
}

View File

@@ -1,6 +1,7 @@
#include "displayapp/screens/BatteryInfo.h"
#include "displayapp/DisplayApp.h"
#include "components/battery/BatteryController.h"
#include "displayapp/InfiniTimeTheme.h"
using namespace Pinetime::Applications::Screens;
@@ -16,9 +17,9 @@ BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Cont
lv_obj_align(charging_bar, nullptr, LV_ALIGN_CENTER, 0, 10);
lv_bar_set_anim_time(charging_bar, 1000);
lv_obj_set_style_local_radius(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, lv_color_hex(0x222222));
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, Colors::bgAlt);
lv_obj_set_style_local_bg_opa(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_OPA_100);
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, lv_color_hex(0xFF0000));
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED);
lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_ON);
status = lv_label_create(lv_scr_act(), nullptr);
@@ -33,7 +34,7 @@ BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Cont
lv_obj_align(percent, nullptr, LV_ALIGN_CENTER, 0, -60);
voltage = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(voltage, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xff, 0xb0, 0x0));
lv_obj_set_style_local_text_color(voltage, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::orange);
lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltage / 1000, batteryVoltage % 1000 / 10);
lv_label_set_align(voltage, LV_LABEL_ALIGN_CENTER);
lv_obj_align(voltage, nullptr, LV_ALIGN_CENTER, 0, 95);
@@ -62,7 +63,7 @@ void BatteryInfo::Refresh() {
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
lv_label_set_text_static(status, "Battery low");
} else {
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x0, 0xb0, 0x0));
lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, Colors::highlight);
lv_label_set_text_static(status, "Discharging");
}

View File

@@ -3,6 +3,7 @@
#include "Version.h"
#include "components/firmwarevalidator/FirmwareValidator.h"
#include "displayapp/DisplayApp.h"
#include "displayapp/InfiniTimeTheme.h"
using namespace Pinetime::Applications::Screens;
@@ -42,7 +43,7 @@ FirmwareValidation::FirmwareValidation(Pinetime::Applications::DisplayApp* app,
lv_obj_set_size(buttonValidate, 115, 50);
lv_obj_align(buttonValidate, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
lv_obj_set_event_cb(buttonValidate, ButtonEventHandler);
lv_obj_set_style_local_bg_color(buttonValidate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x0, 0xb0, 0x0));
lv_obj_set_style_local_bg_color(buttonValidate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::highlight);
labelButtonValidate = lv_label_create(buttonValidate, nullptr);
lv_label_set_text_static(labelButtonValidate, "Validate");
@@ -51,7 +52,7 @@ FirmwareValidation::FirmwareValidation(Pinetime::Applications::DisplayApp* app,
buttonReset->user_data = this;
lv_obj_set_size(buttonReset, 115, 50);
lv_obj_align(buttonReset, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
lv_obj_set_style_local_bg_color(buttonReset, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0x0, 0x0));
lv_obj_set_style_local_bg_color(buttonReset, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED);
lv_obj_set_event_cb(buttonReset, ButtonEventHandler);
labelButtonReset = lv_label_create(buttonReset, nullptr);

View File

@@ -1,37 +1,35 @@
#include "displayapp/screens/FlashLight.h"
#include "displayapp/DisplayApp.h"
#include "displayapp/screens/Symbols.h"
#include "displayapp/InfiniTimeTheme.h"
using namespace Pinetime::Applications::Screens;
namespace {
void event_handler(lv_obj_t* obj, lv_event_t event) {
auto* screen = static_cast<FlashLight*>(obj->user_data);
screen->OnClickEvent(obj, event);
void EventHandler(lv_obj_t* obj, lv_event_t event) {
if (event == LV_EVENT_CLICKED) {
auto* screen = static_cast<FlashLight*>(obj->user_data);
screen->Toggle();
}
}
}
FlashLight::FlashLight(Pinetime::Applications::DisplayApp* app,
System::SystemTask& systemTask,
Controllers::BrightnessController& brightnessController)
: Screen(app),
systemTask {systemTask},
brightnessController {brightnessController}
: Screen(app), systemTask {systemTask}, brightnessController {brightnessController} {
{
brightnessController.Backup();
brightnessLevel = brightnessController.Level();
brightnessController.Set(Controllers::BrightnessController::Levels::Low);
flashLight = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &lv_font_sys_48);
lv_label_set_text_static(flashLight, Symbols::highlight);
lv_label_set_text_static(flashLight, Symbols::flashlight);
lv_obj_align(flashLight, nullptr, LV_ALIGN_CENTER, 0, 0);
for (auto& i : indicators) {
i = lv_obj_create(lv_scr_act(), nullptr);
lv_obj_set_size(i, 15, 10);
lv_obj_set_style_local_border_width(i, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, 2);
for (auto& indicator : indicators) {
indicator = lv_obj_create(lv_scr_act(), nullptr);
lv_obj_set_size(indicator, 15, 10);
lv_obj_set_style_local_border_width(indicator, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, 2);
}
lv_obj_align(indicators[1], flashLight, LV_ALIGN_OUT_BOTTOM_MID, 0, 5);
@@ -48,7 +46,7 @@ FlashLight::FlashLight(Pinetime::Applications::DisplayApp* app,
lv_label_set_text_static(backgroundAction, "");
lv_obj_set_click(backgroundAction, true);
backgroundAction->user_data = this;
lv_obj_set_event_cb(backgroundAction, event_handler);
lv_obj_set_event_cb(backgroundAction, EventHandler);
systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
}
@@ -56,27 +54,19 @@ FlashLight::FlashLight(Pinetime::Applications::DisplayApp* app,
FlashLight::~FlashLight() {
lv_obj_clean(lv_scr_act());
lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
brightnessController.Restore();
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
}
void FlashLight::SetColors() {
if (isOn) {
lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_obj_set_style_local_text_color(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0));
for (auto& i : indicators) {
lv_obj_set_style_local_bg_color(i, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0));
lv_obj_set_style_local_bg_color(i, LV_OBJ_PART_MAIN, LV_STATE_DISABLED, LV_COLOR_WHITE);
lv_obj_set_style_local_border_color(i, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0));
}
} else {
lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_obj_set_style_local_text_color(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
for (auto& i : indicators) {
lv_obj_set_style_local_bg_color(i, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_obj_set_style_local_bg_color(i, LV_OBJ_PART_MAIN, LV_STATE_DISABLED, LV_COLOR_BLACK);
lv_obj_set_style_local_border_color(i, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
}
lv_color_t bgColor = isOn ? LV_COLOR_WHITE : LV_COLOR_BLACK;
lv_color_t fgColor = isOn ? Colors::lightGray : LV_COLOR_WHITE;
lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, bgColor);
lv_obj_set_style_local_text_color(flashLight, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, fgColor);
for (auto& indicator : indicators) {
lv_obj_set_style_local_bg_color(indicator, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, fgColor);
lv_obj_set_style_local_bg_color(indicator, LV_OBJ_PART_MAIN, LV_STATE_DISABLED, bgColor);
lv_obj_set_style_local_border_color(indicator, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, fgColor);
}
}
@@ -95,37 +85,43 @@ void FlashLight::SetIndicators() {
}
}
void FlashLight::OnClickEvent(lv_obj_t* obj, lv_event_t event) {
if (obj == backgroundAction && event == LV_EVENT_CLICKED) {
isOn = !isOn;
SetColors();
void FlashLight::Toggle() {
isOn = !isOn;
SetColors();
if (isOn) {
brightnessController.Set(brightnessLevel);
} else {
brightnessController.Set(Controllers::BrightnessController::Levels::Low);
}
}
bool FlashLight::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
using namespace Pinetime::Controllers;
auto SetState = [this]() {
if (isOn) {
brightnessController.Set(brightnessLevel);
}
SetIndicators();
};
if (event == TouchEvents::SwipeLeft) {
if (brightnessLevel == BrightnessController::Levels::High) {
brightnessLevel = BrightnessController::Levels::Medium;
brightnessController.Set(brightnessLevel);
SetIndicators();
SetState();
} else if (brightnessLevel == BrightnessController::Levels::Medium) {
brightnessLevel = BrightnessController::Levels::Low;
brightnessController.Set(brightnessLevel);
SetIndicators();
SetState();
}
return true;
}
if (event == TouchEvents::SwipeRight) {
if (brightnessLevel == BrightnessController::Levels::Low) {
brightnessLevel = BrightnessController::Levels::Medium;
brightnessController.Set(brightnessLevel);
SetIndicators();
SetState();
} else if (brightnessLevel == BrightnessController::Levels::Medium) {
brightnessLevel = BrightnessController::Levels::High;
brightnessController.Set(brightnessLevel);
SetIndicators();
SetState();
}
return true;
}

View File

@@ -17,7 +17,7 @@ namespace Pinetime {
~FlashLight() override;
bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override;
void OnClickEvent(lv_obj_t* obj, lv_event_t event);
void Toggle();
private:
void SetIndicators();
@@ -26,7 +26,7 @@ namespace Pinetime {
Pinetime::System::SystemTask& systemTask;
Controllers::BrightnessController& brightnessController;
Controllers::BrightnessController::Levels brightnessLevel;
Controllers::BrightnessController::Levels brightnessLevel = Controllers::BrightnessController::Levels::High;
lv_obj_t* flashLight;
lv_obj_t* backgroundAction;

View File

@@ -3,6 +3,7 @@
#include <components/heartrate/HeartRateController.h>
#include "displayapp/DisplayApp.h"
#include "displayapp/InfiniTimeTheme.h"
using namespace Pinetime::Applications::Screens;
@@ -36,10 +37,11 @@ HeartRate::HeartRate(Pinetime::Applications::DisplayApp* app,
lv_obj_set_style_local_text_font(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
if (isHrRunning)
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x0, 0xb0, 0x0));
else
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0));
if (isHrRunning) {
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::highlight);
} else {
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray);
}
lv_label_set_text_static(label_hr, "000");
lv_obj_align(label_hr, nullptr, LV_ALIGN_CENTER, 0, -40);
@@ -97,12 +99,12 @@ void HeartRate::OnStartStopEvent(lv_event_t event) {
heartRateController.Start();
UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped);
systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x0, 0xb0, 0x0));
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::highlight);
} else {
heartRateController.Stop();
UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped);
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0));
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray);
}
}
}

View File

@@ -1,6 +1,7 @@
#include "displayapp/screens/InfiniPaint.h"
#include "displayapp/DisplayApp.h"
#include "displayapp/LittleVgl.h"
#include "displayapp/InfiniTimeTheme.h"
#include <algorithm> // std::fill
@@ -26,7 +27,7 @@ bool InfiniPaint::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
selectColor = LV_COLOR_MAGENTA;
break;
case 1:
selectColor = LV_COLOR_MAKE(0x0, 0xb0, 0x0);
selectColor = Colors::green;
break;
case 2:
selectColor = LV_COLOR_WHITE;

View File

@@ -3,34 +3,9 @@
using namespace Pinetime::Applications::Screens;
Label::Label(uint8_t screenID, uint8_t numScreens, Pinetime::Applications::DisplayApp* app, lv_obj_t* labelText)
: Screen(app), labelText {labelText} {
: Screen(app), labelText {labelText}, pageIndicator(screenID, numScreens) {
if (numScreens > 1) {
pageIndicatorBasePoints[0].x = LV_HOR_RES - 1;
pageIndicatorBasePoints[0].y = 0;
pageIndicatorBasePoints[1].x = LV_HOR_RES - 1;
pageIndicatorBasePoints[1].y = LV_VER_RES;
pageIndicatorBase = lv_line_create(lv_scr_act(), NULL);
lv_obj_set_style_local_line_width(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3);
lv_obj_set_style_local_line_color(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x111111));
lv_obj_set_style_local_line_rounded(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, true);
lv_line_set_points(pageIndicatorBase, pageIndicatorBasePoints, 2);
uint16_t indicatorSize = LV_VER_RES / numScreens;
uint16_t indicatorPos = indicatorSize * screenID;
pageIndicatorPoints[0].x = LV_HOR_RES - 1;
pageIndicatorPoints[0].y = indicatorPos;
pageIndicatorPoints[1].x = LV_HOR_RES - 1;
pageIndicatorPoints[1].y = indicatorPos + indicatorSize;
pageIndicator = lv_line_create(lv_scr_act(), NULL);
lv_obj_set_style_local_line_width(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3);
lv_obj_set_style_local_line_color(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0));
lv_obj_set_style_local_line_rounded(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, true);
lv_line_set_points(pageIndicator, pageIndicatorPoints, 2);
}
pageIndicator.Create();
}
Label::~Label() {

View File

@@ -1,6 +1,7 @@
#pragma once
#include "displayapp/screens/Screen.h"
#include "displayapp/widgets/PageIndicator.h"
#include <lvgl/lvgl.h>
namespace Pinetime {
@@ -14,10 +15,7 @@ namespace Pinetime {
private:
lv_obj_t* labelText = nullptr;
lv_point_t pageIndicatorBasePoints[2];
lv_point_t pageIndicatorPoints[2];
lv_obj_t* pageIndicatorBase;
lv_obj_t* pageIndicator;
Widgets::PageIndicator pageIndicator;
};
}
}

View File

@@ -16,37 +16,14 @@ List::List(uint8_t screenID,
DisplayApp* app,
Controllers::Settings& settingsController,
std::array<Applications, MAXLISTITEMS>& applications)
: Screen(app), settingsController {settingsController} {
: Screen(app), settingsController {settingsController}, pageIndicator(screenID, numScreens) {
// Set the background to Black
lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_make(0, 0, 0));
settingsController.SetSettingsMenu(screenID);
if (numScreens > 1) {
pageIndicatorBasePoints[0].x = LV_HOR_RES - 1;
pageIndicatorBasePoints[0].y = 0;
pageIndicatorBasePoints[1].x = LV_HOR_RES - 1;
pageIndicatorBasePoints[1].y = LV_VER_RES;
pageIndicatorBase = lv_line_create(lv_scr_act(), NULL);
lv_obj_set_style_local_line_width(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3);
lv_obj_set_style_local_line_color(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x111111));
lv_line_set_points(pageIndicatorBase, pageIndicatorBasePoints, 2);
const uint16_t indicatorSize = LV_VER_RES / numScreens;
const uint16_t indicatorPos = indicatorSize * screenID;
pageIndicatorPoints[0].x = LV_HOR_RES - 1;
pageIndicatorPoints[0].y = indicatorPos;
pageIndicatorPoints[1].x = LV_HOR_RES - 1;
pageIndicatorPoints[1].y = indicatorPos + indicatorSize;
pageIndicator = lv_line_create(lv_scr_act(), NULL);
lv_obj_set_style_local_line_width(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3);
lv_obj_set_style_local_line_color(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0));
lv_line_set_points(pageIndicator, pageIndicatorPoints, 2);
}
pageIndicator.Create();
lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr);

View File

@@ -4,6 +4,7 @@
#include <cstdint>
#include <array>
#include "displayapp/screens/Screen.h"
#include "displayapp/widgets/PageIndicator.h"
#include "displayapp/Apps.h"
#include "components/settings/Settings.h"
@@ -35,10 +36,7 @@ namespace Pinetime {
lv_obj_t* itemApps[MAXLISTITEMS];
lv_point_t pageIndicatorBasePoints[2];
lv_point_t pageIndicatorPoints[2];
lv_obj_t* pageIndicatorBase;
lv_obj_t* pageIndicator;
Widgets::PageIndicator pageIndicator;
};
}
}

View File

@@ -1,5 +1,6 @@
#include "displayapp/screens/Metronome.h"
#include "displayapp/screens/Symbols.h"
#include "displayapp/InfiniTimeTheme.h"
using namespace Pinetime::Applications::Screens;
@@ -12,7 +13,7 @@ namespace {
lv_obj_t* createLabel(const char* name, lv_obj_t* reference, lv_align_t align, lv_font_t* font, uint8_t x, uint8_t y) {
lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font);
lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0));
lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray);
lv_label_set_text(label, name);
lv_obj_align(label, reference, align, x, y);

View File

@@ -1,6 +1,7 @@
#include "displayapp/screens/Motion.h"
#include <lvgl/lvgl.h>
#include "displayapp/DisplayApp.h"
#include "displayapp/InfiniTimeTheme.h"
using namespace Pinetime::Applications::Screens;
@@ -19,7 +20,7 @@ Motion::Motion(Pinetime::Applications::DisplayApp* app, Controllers::MotionContr
/*Add 3 data series*/
ser1 = lv_chart_add_series(chart, LV_COLOR_RED);
ser2 = lv_chart_add_series(chart, LV_COLOR_MAKE(0x0, 0xb0, 0x0));
ser2 = lv_chart_add_series(chart, Colors::green);
ser3 = lv_chart_add_series(chart, LV_COLOR_YELLOW);
lv_chart_init_points(chart, ser1, 0);

View File

@@ -19,6 +19,7 @@
#include <cstdint>
#include "displayapp/DisplayApp.h"
#include "components/ble/NavigationService.h"
#include "displayapp/InfiniTimeTheme.h"
using namespace Pinetime::Applications::Screens;
@@ -192,7 +193,7 @@ void Navigation::Refresh() {
if (progress > 90) {
lv_obj_set_style_local_bg_color(barProgress, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED);
} else {
lv_obj_set_style_local_bg_color(barProgress, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xff, 0xb0, 0x0));
lv_obj_set_style_local_bg_color(barProgress, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, Colors::orange);
}
}
}

View File

@@ -3,6 +3,8 @@
#include "components/ble/MusicService.h"
#include "components/ble/AlertNotificationService.h"
#include "displayapp/screens/Symbols.h"
#include <algorithm>
#include "displayapp/InfiniTimeTheme.h"
using namespace Pinetime::Applications::Screens;
extern lv_font_t jetbrains_mono_extrabold_compressed;
@@ -20,30 +22,23 @@ Notifications::Notifications(DisplayApp* app,
motorController {motorController},
systemTask {systemTask},
mode {mode} {
notificationManager.ClearNewNotificationFlag();
auto notification = notificationManager.GetLastNotification();
if (notification.valid) {
currentId = notification.id;
currentItem = std::make_unique<NotificationItem>(notification.Title(),
notification.Message(),
notification.index,
1,
notification.category,
notificationManager.NbNotifications(),
mode,
alertNotificationService,
motorController);
validDisplay = true;
} else {
currentItem = std::make_unique<NotificationItem>("Notification",
"No notification to display",
0,
notification.category,
notificationManager.NbNotifications(),
Modes::Preview,
alertNotificationService,
motorController);
currentItem = std::make_unique<NotificationItem>(alertNotificationService, motorController);
validDisplay = false;
}
if (mode == Modes::Preview) {
systemTask.PushMessage(System::Messages::DisableSleeping);
if (notification.category == Controllers::NotificationManager::Categories::IncomingCall) {
@@ -77,7 +72,7 @@ Notifications::~Notifications() {
void Notifications::Refresh() {
if (mode == Modes::Preview && timeoutLine != nullptr) {
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) {
running = false;
} else {
@@ -85,6 +80,40 @@ void Notifications::Refresh() {
lv_line_set_points(timeoutLine, timeoutLinePoints, 2);
}
}
if (dismissingNotification) {
dismissingNotification = false;
auto notification = notificationManager.Get(currentId);
if (!notification.valid) {
notification = notificationManager.GetLastNotification();
}
currentId = notification.id;
if (!notification.valid) {
validDisplay = false;
}
currentItem.reset(nullptr);
if (afterDismissNextMessageFromAbove) {
app->SetFullRefresh(DisplayApp::FullRefreshDirections::Down);
} else {
app->SetFullRefresh(DisplayApp::FullRefreshDirections::Up);
}
if (validDisplay) {
Controllers::NotificationManager::Notification::Idx currentIdx = notificationManager.IndexOf(currentId);
currentItem = std::make_unique<NotificationItem>(notification.Title(),
notification.Message(),
currentIdx + 1,
notification.category,
notificationManager.NbNotifications(),
alertNotificationService,
motorController);
} else {
currentItem = std::make_unique<NotificationItem>(alertNotificationService, motorController);
}
}
running = currentItem->IsRunning() && running;
}
@@ -108,52 +137,84 @@ bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
}
switch (event) {
case Pinetime::Applications::TouchEvents::SwipeRight:
if (validDisplay) {
Controllers::NotificationManager::Notification previousNotification;
auto previousMessage = notificationManager.GetPrevious(currentId);
auto nextMessage = notificationManager.GetNext(currentId);
if (!previousMessage.valid) {
// dismissed last message (like 5/5), need to go one message down (like 4/4)
afterDismissNextMessageFromAbove = false; // show next message coming from below
} else {
afterDismissNextMessageFromAbove = true; // show next message coming from above
}
notificationManager.Dismiss(currentId);
if (previousMessage.valid) {
currentId = previousMessage.id;
} else if (nextMessage.valid) {
currentId = nextMessage.id;
} else {
// don't update id, won't be found be refresh and try to load latest message or no message box
}
currentItem.reset(nullptr);
app->SetFullRefresh(DisplayApp::FullRefreshDirections::RightAnim);
// create black transition screen to let the notification dismiss to blackness
lv_obj_t* blackBox = lv_obj_create(lv_scr_act(), nullptr);
lv_obj_set_size(blackBox, LV_HOR_RES, LV_VER_RES);
lv_obj_set_style_local_bg_color(blackBox, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
dismissingNotification = true;
return true;
}
return false;
case Pinetime::Applications::TouchEvents::SwipeDown: {
Controllers::NotificationManager::Notification previousNotification;
if (validDisplay)
if (validDisplay) {
previousNotification = notificationManager.GetPrevious(currentId);
else
} else {
previousNotification = notificationManager.GetLastNotification();
}
if (!previousNotification.valid)
if (!previousNotification.valid) {
return true;
}
validDisplay = true;
currentId = previousNotification.id;
Controllers::NotificationManager::Notification::Idx currentIdx = notificationManager.IndexOf(currentId);
validDisplay = true;
currentItem.reset(nullptr);
app->SetFullRefresh(DisplayApp::FullRefreshDirections::Down);
currentItem = std::make_unique<NotificationItem>(previousNotification.Title(),
previousNotification.Message(),
previousNotification.index,
currentIdx + 1,
previousNotification.category,
notificationManager.NbNotifications(),
mode,
alertNotificationService,
motorController);
}
return true;
case Pinetime::Applications::TouchEvents::SwipeUp: {
Controllers::NotificationManager::Notification nextNotification;
if (validDisplay)
if (validDisplay) {
nextNotification = notificationManager.GetNext(currentId);
else
} else {
nextNotification = notificationManager.GetLastNotification();
}
if (!nextNotification.valid) {
running = false;
return false;
}
validDisplay = true;
currentId = nextNotification.id;
Controllers::NotificationManager::Notification::Idx currentIdx = notificationManager.IndexOf(currentId);
validDisplay = true;
currentItem.reset(nullptr);
app->SetFullRefresh(DisplayApp::FullRefreshDirections::Up);
currentItem = std::make_unique<NotificationItem>(nextNotification.Title(),
nextNotification.Message(),
nextNotification.index,
currentIdx + 1,
nextNotification.category,
notificationManager.NbNotifications(),
mode,
alertNotificationService,
motorController);
}
@@ -170,34 +231,49 @@ namespace {
}
}
Notifications::NotificationItem::NotificationItem(Pinetime::Controllers::AlertNotificationService& alertNotificationService,
Pinetime::Controllers::MotorController& motorController)
: NotificationItem("Notification",
"No notification to display",
0,
Controllers::NotificationManager::Categories::Unknown,
0,
alertNotificationService,
motorController) {
}
Notifications::NotificationItem::NotificationItem(const char* title,
const char* msg,
uint8_t notifNr,
Controllers::NotificationManager::Categories category,
uint8_t notifNb,
Modes mode,
Pinetime::Controllers::AlertNotificationService& alertNotificationService,
Pinetime::Controllers::MotorController& motorController)
: mode {mode}, alertNotificationService {alertNotificationService}, motorController {motorController} {
lv_obj_t* container1 = lv_cont_create(lv_scr_act(), NULL);
: alertNotificationService {alertNotificationService}, motorController {motorController} {
container = lv_cont_create(lv_scr_act(), nullptr);
lv_obj_set_size(container, LV_HOR_RES, LV_VER_RES);
lv_obj_set_style_local_bg_color(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
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_style_local_bg_color(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x38, 0x38, 0x38));
lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10);
lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5);
lv_obj_set_style_local_border_width(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0);
subject_container = lv_cont_create(container, nullptr);
lv_obj_set_style_local_bg_color(subject_container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt);
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_obj_set_pos(container1, 0, 50);
lv_obj_set_size(container1, LV_HOR_RES, 190);
lv_obj_set_pos(subject_container, 0, 50);
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_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT);
lv_cont_set_fit(container1, LV_FIT_NONE);
lv_obj_t* alert_count = lv_label_create(lv_scr_act(), nullptr);
lv_obj_t* alert_count = lv_label_create(container, nullptr);
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_t* alert_type = lv_label_create(lv_scr_act(), 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_t* alert_type = lv_label_create(container, nullptr);
lv_obj_set_style_local_text_color(alert_type, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::orange);
if (title == nullptr) {
lv_label_set_text_static(alert_type, "Notification");
} else {
@@ -214,39 +290,34 @@ Notifications::NotificationItem::NotificationItem(const char* title,
lv_obj_set_width(alert_type, 180);
lv_obj_align(alert_type, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 16);
/////////
lv_obj_t* alert_subject = lv_label_create(subject_container, nullptr);
lv_label_set_long_mode(alert_subject, LV_LABEL_LONG_BREAK);
lv_obj_set_width(alert_subject, LV_HOR_RES - 20);
switch (category) {
default: {
lv_obj_t* alert_subject = lv_label_create(container1, nullptr);
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_obj_set_width(alert_subject, LV_HOR_RES - 20);
default:
lv_label_set_text(alert_subject, msg);
} break;
break;
case Controllers::NotificationManager::Categories::IncomingCall: {
lv_obj_set_height(container1, 108);
lv_obj_t* alert_subject = lv_label_create(container1, nullptr);
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_obj_set_width(alert_subject, LV_HOR_RES - 20);
lv_obj_set_height(subject_container, 108);
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_label_set_long_mode(alert_caller, LV_LABEL_LONG_BREAK);
lv_obj_set_width(alert_caller, LV_HOR_RES - 20);
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;
lv_obj_set_event_cb(bt_accept, CallEventHandler);
lv_obj_set_size(bt_accept, 76, 76);
lv_obj_align(bt_accept, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
label_accept = lv_label_create(bt_accept, nullptr);
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, Colors::highlight);
bt_reject = lv_btn_create(lv_scr_act(), nullptr);
bt_reject = lv_btn_create(container, nullptr);
bt_reject->user_data = this;
lv_obj_set_event_cb(bt_reject, CallEventHandler);
lv_obj_set_size(bt_reject, 76, 76);
@@ -255,14 +326,14 @@ Notifications::NotificationItem::NotificationItem(const char* title,
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);
bt_mute = lv_btn_create(lv_scr_act(), nullptr);
bt_mute = lv_btn_create(container, nullptr);
bt_mute->user_data = this;
lv_obj_set_event_cb(bt_mute, CallEventHandler);
lv_obj_set_size(bt_mute, 76, 76);
lv_obj_align(bt_mute, NULL, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
label_mute = lv_label_create(bt_mute, nullptr);
lv_label_set_text_static(label_mute, Symbols::volumMute);
lv_obj_set_style_local_bg_color(bt_mute, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0));
lv_obj_set_style_local_bg_color(bt_mute, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray);
} break;
}
}

View File

@@ -33,12 +33,13 @@ namespace Pinetime {
class NotificationItem {
public:
NotificationItem(Pinetime::Controllers::AlertNotificationService& alertNotificationService,
Pinetime::Controllers::MotorController& motorController);
NotificationItem(const char* title,
const char* msg,
uint8_t notifNr,
Controllers::NotificationManager::Categories,
uint8_t notifNb,
Modes mode,
Pinetime::Controllers::AlertNotificationService& alertNotificationService,
Pinetime::Controllers::MotorController& motorController);
~NotificationItem();
@@ -48,16 +49,17 @@ namespace Pinetime {
void OnCallButtonEvent(lv_obj_t*, lv_event_t event);
private:
lv_obj_t* container1;
lv_obj_t* container;
lv_obj_t* subject_container;
lv_obj_t* bt_accept;
lv_obj_t* bt_mute;
lv_obj_t* bt_reject;
lv_obj_t* label_accept;
lv_obj_t* label_mute;
lv_obj_t* label_reject;
Modes mode;
Pinetime::Controllers::AlertNotificationService& alertNotificationService;
Pinetime::Controllers::MotorController& motorController;
bool running = true;
};
@@ -68,15 +70,19 @@ namespace Pinetime {
System::SystemTask& systemTask;
Modes mode = Modes::Normal;
std::unique_ptr<NotificationItem> currentItem;
Controllers::NotificationManager::Notification::Id currentId;
Pinetime::Controllers::NotificationManager::Notification::Id currentId;
bool validDisplay = false;
bool afterDismissNextMessageFromAbove = false;
lv_point_t timeoutLinePoints[2] {{0, 1}, {239, 1}};
lv_obj_t* timeoutLine = nullptr;
TickType_t timeoutTickCountStart;
static const TickType_t timeoutLength = pdMS_TO_TICKS(7000);
bool interacted = true;
bool dismissingNotification = false;
lv_task_t* taskRefresh;
};
}

View File

@@ -5,7 +5,7 @@ using namespace Pinetime::Applications::Screens;
PassKey::PassKey(Pinetime::Applications::DisplayApp* app, uint32_t key) : Screen(app) {
passkeyLabel = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(passkeyLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFFFF00));
lv_obj_set_style_local_text_color(passkeyLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
lv_obj_set_style_local_text_font(passkeyLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
lv_label_set_text_fmt(passkeyLabel, "%06u", key);
lv_obj_align(passkeyLabel, nullptr, LV_ALIGN_CENTER, 0, -20);

View File

@@ -20,7 +20,7 @@ Steps::Steps(Pinetime::Applications::DisplayApp* app,
lv_obj_set_style_local_bg_opa(stepsArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, LV_OPA_0);
lv_obj_set_style_local_border_width(stepsArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, 2);
lv_obj_set_style_local_radius(stepsArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, 0);
lv_obj_set_style_local_line_color(stepsArc, LV_ARC_PART_INDIC, LV_STATE_DEFAULT, lv_color_hex(0x0000FF));
lv_obj_set_style_local_line_color(stepsArc, LV_ARC_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_BLUE);
lv_arc_set_end_angle(stepsArc, 200);
lv_obj_set_size(stepsArc, 240, 240);
lv_arc_set_range(stepsArc, 0, 500);
@@ -32,7 +32,7 @@ Steps::Steps(Pinetime::Applications::DisplayApp* app,
lv_arc_set_value(stepsArc, int16_t(500 * stepsCount / settingsController.GetStepsGoal()));
lSteps = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(lSteps, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FF00));
lv_obj_set_style_local_text_color(lSteps, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_LIME);
lv_obj_set_style_local_text_font(lSteps, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
lv_label_set_text_fmt(lSteps, "%li", stepsCount);
lv_obj_align(lSteps, nullptr, LV_ALIGN_CENTER, 0, -40);

View File

@@ -1,10 +1,7 @@
#include "displayapp/screens/StopWatch.h"
#include "displayapp/screens/Screen.h"
#include "displayapp/screens/Symbols.h"
#include <lvgl/lvgl.h>
#include <FreeRTOS.h>
#include <task.h>
#include "displayapp/InfiniTimeTheme.h"
using namespace Pinetime::Applications::Screens;
@@ -30,25 +27,17 @@ namespace {
}
}
StopWatch::StopWatch(DisplayApp* app, System::SystemTask& systemTask)
: Screen(app),
systemTask {systemTask},
currentState {States::Init},
startTime {},
oldTimeElapsed {},
currentTimeSeparated {},
lapBuffer {},
lapNr {} {
StopWatch::StopWatch(DisplayApp* app, System::SystemTask& systemTask) : Screen(app), systemTask {systemTask} {
time = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0));
lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray);
lv_label_set_text_static(time, "00:00");
lv_obj_align(time, lv_scr_act(), LV_ALIGN_CENTER, 0, -45);
msecTime = lv_label_create(lv_scr_act(), nullptr);
// lv_obj_set_style_local_text_font(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20);
lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0));
lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray);
lv_label_set_text_static(msecTime, "00");
lv_obj_align(msecTime, lv_scr_act(), LV_ALIGN_CENTER, 0, 3);
@@ -65,24 +54,15 @@ StopWatch::StopWatch(DisplayApp* app, System::SystemTask& systemTask)
lv_obj_set_event_cb(btnStopLap, stop_lap_event_handler);
lv_obj_set_size(btnStopLap, 115, 50);
lv_obj_align(btnStopLap, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
lv_obj_set_style_local_bg_color(btnStopLap, LV_BTN_PART_MAIN, LV_STATE_DISABLED, LV_COLOR_MAKE(0x18, 0x18, 0x18));
txtStopLap = lv_label_create(btnStopLap, nullptr);
lv_obj_set_style_local_text_color(txtStopLap, LV_BTN_PART_MAIN, LV_STATE_DISABLED, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0));
lv_label_set_text_static(txtStopLap, Symbols::stop);
lv_obj_set_state(btnStopLap, LV_STATE_DISABLED);
lv_obj_set_state(txtStopLap, LV_STATE_DISABLED);
lapOneText = lv_label_create(lv_scr_act(), nullptr);
// lv_obj_set_style_local_text_font(lapOneText, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20);
lv_obj_set_style_local_text_color(lapOneText, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
lv_obj_align(lapOneText, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 50, 30);
lv_label_set_text_static(lapOneText, "");
lapTwoText = lv_label_create(lv_scr_act(), nullptr);
// lv_obj_set_style_local_text_font(lapTwoText, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20);
lv_obj_set_style_local_text_color(lapTwoText, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
lv_obj_align(lapTwoText, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 50, 55);
lv_label_set_text_static(lapTwoText, "");
lapText = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(lapText, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
lv_obj_align(lapText, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 50, 30);
lv_label_set_text_static(lapText, "");
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
}
@@ -96,16 +76,14 @@ StopWatch::~StopWatch() {
void StopWatch::Reset() {
currentState = States::Init;
oldTimeElapsed = 0;
lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0));
lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0));
lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray);
lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray);
lv_label_set_text_static(time, "00:00");
lv_label_set_text_static(msecTime, "00");
lv_label_set_text_static(lapOneText, "");
lv_label_set_text_static(lapTwoText, "");
lapBuffer.clearBuffer();
lapNr = 0;
lv_label_set_text_static(lapText, "");
lapsDone = 0;
lv_obj_set_state(btnStopLap, LV_STATE_DISABLED);
lv_obj_set_state(txtStopLap, LV_STATE_DISABLED);
}
@@ -113,8 +91,8 @@ void StopWatch::Reset() {
void StopWatch::Start() {
lv_obj_set_state(btnStopLap, LV_STATE_DEFAULT);
lv_obj_set_state(txtStopLap, LV_STATE_DEFAULT);
lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x0, 0xb0, 0x0));
lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x0, 0xb0, 0x0));
lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::highlight);
lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::highlight);
lv_label_set_text_static(txtPlayPause, Symbols::pause);
lv_label_set_text_static(txtStopLap, Symbols::lapsFlag);
startTime = xTaskGetTickCount();
@@ -125,7 +103,7 @@ void StopWatch::Start() {
void StopWatch::Pause() {
startTime = 0;
// Store the current time elapsed in cache
oldTimeElapsed += timeElapsed;
oldTimeElapsed = laps[lapsDone];
currentState = States::Halted;
lv_label_set_text_static(txtPlayPause, Symbols::play);
lv_label_set_text_static(txtStopLap, Symbols::stop);
@@ -136,9 +114,9 @@ void StopWatch::Pause() {
void StopWatch::Refresh() {
if (currentState == States::Running) {
timeElapsed = xTaskGetTickCount() - startTime;
currentTimeSeparated = convertTicksToTimeSegments((oldTimeElapsed + timeElapsed));
laps[lapsDone] = oldTimeElapsed + xTaskGetTickCount() - startTime;
TimeSeparated_t currentTimeSeparated = convertTicksToTimeSegments(laps[lapsDone]);
lv_label_set_text_fmt(time, "%02d:%02d", currentTimeSeparated.mins, currentTimeSeparated.secs);
lv_label_set_text_fmt(msecTime, "%02d", currentTimeSeparated.hundredths);
}
@@ -163,18 +141,17 @@ void StopWatch::stopLapBtnEventHandler(lv_event_t event) {
}
// If running, then this button is used to save laps
if (currentState == States::Running) {
lapBuffer.addLaps(currentTimeSeparated);
lapNr++;
if (lapBuffer[1]) {
lv_label_set_text_fmt(lapOneText,
"#%2d %2d:%02d.%02d",
(lapNr - 1),
lapBuffer[1]->mins,
lapBuffer[1]->secs,
lapBuffer[1]->hundredths);
}
if (lapBuffer[0]) {
lv_label_set_text_fmt(lapTwoText, "#%2d %2d:%02d.%02d", lapNr, lapBuffer[0]->mins, lapBuffer[0]->secs, lapBuffer[0]->hundredths);
lv_label_set_text(lapText, "");
lapsDone = std::min(lapsDone + 1, maxLapCount);
for (int i = lapsDone - displayedLaps; i < lapsDone; i++) {
if (i < 0) {
lv_label_ins_text(lapText, LV_LABEL_POS_LAST, "\n");
continue;
}
TimeSeparated_t times = convertTicksToTimeSegments(laps[i]);
char buffer[16];
sprintf(buffer, "#%2d %2d:%02d.%02d\n", i + 1, times.mins, times.secs, times.hundredths);
lv_label_ins_text(lapText, LV_LABEL_POS_LAST, buffer);
}
} else if (currentState == States::Halted) {
Reset();

View File

@@ -1,13 +1,11 @@
#pragma once
#include "displayapp/screens/Screen.h"
#include "components/datetime/DateTimeController.h"
#include "displayapp/LittleVgl.h"
#include <lvgl/lvgl.h>
#include <FreeRTOS.h>
#include "portmacro_cmsis.h"
#include <array>
#include "systemtask/SystemTask.h"
namespace Pinetime::Applications::Screens {
@@ -20,46 +18,6 @@ namespace Pinetime::Applications::Screens {
int hundredths;
};
// A simple buffer to hold the latest two laps
template <int N> struct LapTextBuffer_t {
LapTextBuffer_t() : buffer {}, currentSize {}, capacity {N}, head {-1} {
}
void addLaps(const TimeSeparated_t& timeVal) {
head++;
head %= capacity;
buffer[head] = timeVal;
if (currentSize < capacity) {
currentSize++;
}
}
void clearBuffer() {
buffer = {};
currentSize = 0;
head = -1;
}
TimeSeparated_t* operator[](std::size_t idx) {
// Sanity check for out-of-bounds
if (idx >= 0 && idx < capacity) {
if (idx < currentSize) {
// This transformation is to ensure that head is always pointing to index 0.
const auto transformed_idx = (head - idx) % capacity;
return (&buffer[transformed_idx]);
}
}
return nullptr;
}
private:
std::array<TimeSeparated_t, N> buffer;
uint8_t currentSize;
uint8_t capacity;
int8_t head;
};
class StopWatch : public Screen {
public:
StopWatch(DisplayApp* app, System::SystemTask& systemTask);
@@ -76,15 +34,15 @@ namespace Pinetime::Applications::Screens {
private:
Pinetime::System::SystemTask& systemTask;
TickType_t timeElapsed;
States currentState;
States currentState = States::Init;
TickType_t startTime;
TickType_t oldTimeElapsed;
TimeSeparated_t currentTimeSeparated; // Holds Mins, Secs, millisecs
LapTextBuffer_t<2> lapBuffer;
int lapNr = 0;
TickType_t oldTimeElapsed = 0;
static constexpr int maxLapCount = 20;
TickType_t laps[maxLapCount + 1];
static constexpr int displayedLaps = 2;
int lapsDone = 0;
lv_obj_t *time, *msecTime, *btnPlayPause, *btnStopLap, *txtPlayPause, *txtStopLap;
lv_obj_t *lapOneText, *lapTwoText;
lv_obj_t* lapText;
lv_task_t* taskRefresh;
};

View File

@@ -1,8 +1,9 @@
#include "Styles.h"
#include "displayapp/InfiniTimeTheme.h"
void Pinetime::Applications::Screens::SetRadioButtonStyle(lv_obj_t* checkbox) {
lv_obj_set_style_local_radius(checkbox, LV_CHECKBOX_PART_BULLET, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
lv_obj_set_style_local_border_width(checkbox, LV_CHECKBOX_PART_BULLET, LV_STATE_CHECKED, 9);
lv_obj_set_style_local_border_color(checkbox, LV_CHECKBOX_PART_BULLET, LV_STATE_CHECKED, LV_COLOR_MAKE(0x0, 0xb0, 0x0));
lv_obj_set_style_local_border_color(checkbox, LV_CHECKBOX_PART_BULLET, LV_STATE_CHECKED, Colors::highlight);
lv_obj_set_style_local_bg_color(checkbox, LV_CHECKBOX_PART_BULLET, LV_STATE_CHECKED, LV_COLOR_WHITE);
}

View File

@@ -37,20 +37,20 @@ namespace Pinetime {
static constexpr const char* chartLine = "\xEF\x88\x81";
static constexpr const char* eye = "\xEF\x81\xAE";
static constexpr const char* home = "\xEF\x80\x95";
static constexpr const char* sleep = "\xEE\xBD\x84";
static constexpr const char* circle = "\xEF\x84\x91";
// lv_font_sys_48.c
static constexpr const char* settings = "\xEE\xA4\x82"; // e902
static constexpr const char* settings = "\xEE\xA2\xB8";
static constexpr const char* brightnessHigh = "\xEE\xA4\x84"; // e904
static constexpr const char* brightnessLow = "\xEE\xA4\x85"; // e905
static constexpr const char* brightnessMedium = "\xEE\xA4\x86"; // e906
static constexpr const char* brightnessLow = "\xEE\x8E\xAA";
static constexpr const char* brightnessMedium = "\xEE\x8E\xAB";
static constexpr const char* brightnessHigh = "\xEE\x8E\xAC";
static constexpr const char* notificationsOff = "\xEE\xA4\x8B"; // e90b
static constexpr const char* notificationsOn = "\xEE\xA4\x8C"; // e90c
static constexpr const char* highlight = "\xEE\xA4\x87"; // e907
static constexpr const char* notificationsOff = "\xEE\x9F\xB6";
static constexpr const char* notificationsOn = "\xEE\x9F\xB7";
static constexpr const char* flashlight = "\xEF\x80\x8B";
}
}
}

View File

@@ -12,6 +12,7 @@
#include "components/datetime/DateTimeController.h"
#include "components/motion/MotionController.h"
#include "drivers/Watchdog.h"
#include "displayapp/InfiniTimeTheme.h"
using namespace Pinetime::Applications::Screens;
@@ -136,20 +137,25 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen2() {
uptimeSeconds = uptimeSeconds % secondsInAMinute;
// TODO handle more than 100 days of uptime
#ifndef TARGET_DEVICE_NAME
#define TARGET_DEVICE_NAME "UNKNOWN"
#endif
lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_recolor(label, true);
lv_label_set_text_fmt(label,
"#808080 Date# %02d/%02d/%04d\n"
"#808080 Date# %04d-%02d-%02d\n"
"#808080 Time# %02d:%02d:%02d\n"
"#808080 Uptime#\n %02lud %02lu:%02lu:%02lu\n"
"#808080 Battery# %d%%/%03imV\n"
"#808080 Backlight# %s\n"
"#808080 Last reset# %s\n"
"#808080 Accel.# %s\n"
"#808080 Touch.# %x.%x.%x\n",
dateTimeController.Day(),
static_cast<uint8_t>(dateTimeController.Month()),
"#808080 Touch.# %x.%x.%x\n"
"#808080 Model# %s",
dateTimeController.Year(),
static_cast<uint8_t>(dateTimeController.Month()),
dateTimeController.Day(),
dateTimeController.Hours(),
dateTimeController.Minutes(),
dateTimeController.Seconds(),
@@ -164,7 +170,8 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen2() {
ToString(motionController.DeviceType()),
touchPanel.GetChipId(),
touchPanel.GetVendorId(),
touchPanel.GetFwVersion());
touchPanel.GetFwVersion(),
TARGET_DEVICE_NAME);
lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
return std::make_unique<Screens::Label>(1, 5, app, label);
}
@@ -212,7 +219,7 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen4() {
lv_table_set_col_cnt(infoTask, 4);
lv_table_set_row_cnt(infoTask, maxTaskCount + 1);
lv_obj_set_style_local_pad_all(infoTask, LV_TABLE_PART_CELL1, LV_STATE_DEFAULT, 0);
lv_obj_set_style_local_border_color(infoTask, LV_TABLE_PART_CELL1, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0));
lv_obj_set_style_local_border_color(infoTask, LV_TABLE_PART_CELL1, LV_STATE_DEFAULT, Colors::lightGray);
lv_table_set_cell_value(infoTask, 0, 0, "#");
lv_table_set_col_width(infoTask, 0, 30);

View File

@@ -1,6 +1,8 @@
#include "displayapp/screens/Tile.h"
#include "displayapp/DisplayApp.h"
#include "displayapp/screens/BatteryIcon.h"
#include "components/ble/BleController.h"
#include "displayapp/InfiniTimeTheme.h"
using namespace Pinetime::Applications::Screens;
@@ -26,46 +28,26 @@ Tile::Tile(uint8_t screenID,
uint8_t numScreens,
DisplayApp* app,
Controllers::Settings& settingsController,
Pinetime::Controllers::Battery& batteryController,
Controllers::Battery& batteryController,
Controllers::Ble& bleController,
Controllers::DateTime& dateTimeController,
std::array<Applications, 6>& applications)
: Screen(app), batteryController {batteryController}, dateTimeController {dateTimeController} {
: Screen(app),
dateTimeController {dateTimeController},
pageIndicator(screenID, numScreens),
statusIcons(batteryController, bleController) {
settingsController.SetAppMenu(screenID);
statusIcons.Create();
lv_obj_align(statusIcons.GetObject(), lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, -8, 0);
// Time
label_time = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_align(label_time, LV_LABEL_ALIGN_CENTER);
lv_obj_align(label_time, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
// Battery
batteryIcon.Create(lv_scr_act());
lv_obj_align(batteryIcon.GetObject(), nullptr, LV_ALIGN_IN_TOP_RIGHT, -8, 0);
if (numScreens > 1) {
pageIndicatorBasePoints[0].x = LV_HOR_RES - 1;
pageIndicatorBasePoints[0].y = 0;
pageIndicatorBasePoints[1].x = LV_HOR_RES - 1;
pageIndicatorBasePoints[1].y = LV_VER_RES;
pageIndicatorBase = lv_line_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_line_width(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3);
lv_obj_set_style_local_line_color(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x111111));
lv_line_set_points(pageIndicatorBase, pageIndicatorBasePoints, 2);
const uint16_t indicatorSize = LV_VER_RES / numScreens;
const uint16_t indicatorPos = indicatorSize * screenID;
pageIndicatorPoints[0].x = LV_HOR_RES - 1;
pageIndicatorPoints[0].y = indicatorPos;
pageIndicatorPoints[1].x = LV_HOR_RES - 1;
pageIndicatorPoints[1].y = indicatorPos + indicatorSize;
pageIndicator = lv_line_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_line_width(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3);
lv_obj_set_style_local_line_color(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xb0, 0xb0, 0xb0));
lv_line_set_points(pageIndicator, pageIndicatorPoints, 2);
}
pageIndicator.Create();
uint8_t btIndex = 0;
for (uint8_t i = 0; i < 6; i++) {
@@ -90,7 +72,7 @@ Tile::Tile(uint8_t screenID,
lv_obj_set_style_local_bg_opa(btnm1, LV_BTNMATRIX_PART_BTN, LV_STATE_DEFAULT, LV_OPA_50);
lv_obj_set_style_local_bg_color(btnm1, LV_BTNMATRIX_PART_BTN, LV_STATE_DEFAULT, LV_COLOR_AQUA);
lv_obj_set_style_local_bg_opa(btnm1, LV_BTNMATRIX_PART_BTN, LV_STATE_DISABLED, LV_OPA_50);
lv_obj_set_style_local_bg_color(btnm1, LV_BTNMATRIX_PART_BTN, LV_STATE_DISABLED, lv_color_hex(0x111111));
lv_obj_set_style_local_bg_color(btnm1, LV_BTNMATRIX_PART_BTN, LV_STATE_DISABLED, Colors::bgDark);
lv_obj_set_style_local_pad_all(btnm1, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 0);
lv_obj_set_style_local_pad_inner(btnm1, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 10);
@@ -116,7 +98,7 @@ Tile::~Tile() {
void Tile::UpdateScreen() {
lv_label_set_text(label_time, dateTimeController.FormattedTime().c_str());
batteryIcon.SetBatteryPercentage(batteryController.PercentRemaining());
statusIcons.Update();
}
void Tile::OnValueChangedEvent(lv_obj_t* obj, uint32_t buttonId) {

View File

@@ -7,9 +7,9 @@
#include "displayapp/Apps.h"
#include "components/datetime/DateTimeController.h"
#include "components/settings/Settings.h"
#include "components/datetime/DateTimeController.h"
#include "components/battery/BatteryController.h"
#include <displayapp/screens/BatteryIcon.h>
#include "displayapp/widgets/PageIndicator.h"
#include "displayapp/widgets/StatusIcons.h"
namespace Pinetime {
namespace Applications {
@@ -25,7 +25,8 @@ namespace Pinetime {
uint8_t numScreens,
DisplayApp* app,
Controllers::Settings& settingsController,
Pinetime::Controllers::Battery& batteryController,
Controllers::Battery& batteryController,
Controllers::Ble& bleController,
Controllers::DateTime& dateTimeController,
std::array<Applications, 6>& applications);
@@ -35,19 +36,15 @@ namespace Pinetime {
void OnValueChangedEvent(lv_obj_t* obj, uint32_t buttonId);
private:
Pinetime::Controllers::Battery& batteryController;
Controllers::DateTime& dateTimeController;
lv_task_t* taskUpdate;
lv_obj_t* label_time;
lv_point_t pageIndicatorBasePoints[2];
lv_point_t pageIndicatorPoints[2];
lv_obj_t* pageIndicatorBase;
lv_obj_t* pageIndicator;
lv_obj_t* btnm1;
BatteryIcon batteryIcon;
Widgets::PageIndicator pageIndicator;
Widgets::StatusIcons statusIcons;
const char* btnmMap[8];
Pinetime::Applications::Apps apps[6];

View File

@@ -1,13 +1,20 @@
#include "displayapp/screens/Timer.h"
#include "displayapp/screens/Screen.h"
#include "displayapp/screens/Symbols.h"
#include "displayapp/InfiniTimeTheme.h"
#include <lvgl/lvgl.h>
using namespace Pinetime::Applications::Screens;
static void btnEventHandler(lv_obj_t* obj, lv_event_t event) {
auto* screen = static_cast<Timer*>(obj->user_data);
screen->OnButtonEvent(obj, event);
if (event == LV_EVENT_PRESSED) {
screen->ButtonPressed();
} else if (event == LV_EVENT_RELEASED || event == LV_EVENT_PRESS_LOST) {
screen->MaskReset();
} else if (event == LV_EVENT_SHORT_CLICKED) {
screen->ToggleRunning();
}
}
Timer::Timer(DisplayApp* app, Controllers::TimerController& timerController) : Screen(app), timerController {timerController} {
@@ -23,14 +30,37 @@ Timer::Timer(DisplayApp* app, Controllers::TimerController& timerController) : S
lv_obj_align(minuteCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
lv_obj_align(secondCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0);
btnPlayPause = lv_btn_create(lv_scr_act(), nullptr);
highlightObjectMask = lv_objmask_create(lv_scr_act(), nullptr);
lv_obj_set_size(highlightObjectMask, 240, 50);
lv_obj_align(highlightObjectMask, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0);
lv_draw_mask_line_param_t tmpMaskLine;
lv_draw_mask_line_points_init(&tmpMaskLine, 0, 0, 0, 240, LV_DRAW_MASK_LINE_SIDE_LEFT);
highlightMask = lv_objmask_add_mask(highlightObjectMask, &tmpMaskLine);
lv_obj_t* btnHighlight = lv_obj_create(highlightObjectMask, nullptr);
lv_obj_set_style_local_radius(btnHighlight, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
lv_obj_set_style_local_bg_color(btnHighlight, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE);
lv_obj_set_size(btnHighlight, LV_HOR_RES, 50);
lv_obj_align(btnHighlight, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0);
btnObjectMask = lv_objmask_create(lv_scr_act(), nullptr);
lv_obj_set_size(btnObjectMask, 240, 50);
lv_obj_align(btnObjectMask, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0);
lv_draw_mask_line_points_init(&tmpMaskLine, 0, 0, 0, 240, LV_DRAW_MASK_LINE_SIDE_RIGHT);
btnMask = lv_objmask_add_mask(btnObjectMask, &tmpMaskLine);
btnPlayPause = lv_btn_create(btnObjectMask, nullptr);
btnPlayPause->user_data = this;
lv_obj_set_style_local_radius(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x38, 0x38, 0x38));
lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt);
lv_obj_set_event_cb(btnPlayPause, btnEventHandler);
lv_obj_set_size(btnPlayPause, LV_HOR_RES, 50);
lv_obj_align(btnPlayPause, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0);
txtPlayPause = lv_label_create(btnPlayPause, nullptr);
txtPlayPause = lv_label_create(lv_scr_act(), nullptr);
lv_obj_align(txtPlayPause, btnPlayPause, LV_ALIGN_CENTER, 0, 0);
if (timerController.IsRunning()) {
SetTimerRunning();
@@ -46,11 +76,46 @@ Timer::~Timer() {
lv_obj_clean(lv_scr_act());
}
void Timer::ButtonPressed() {
pressTime = xTaskGetTickCount();
buttonPressing = true;
}
void Timer::MaskReset() {
buttonPressing = false;
// A click event is processed before a release event,
// so the release event would override the "Pause" text without this check
if (!timerController.IsRunning()) {
lv_label_set_text_static(txtPlayPause, "Start");
}
maskPosition = 0;
UpdateMask();
}
void Timer::UpdateMask() {
lv_draw_mask_line_param_t maskLine;
lv_draw_mask_line_points_init(&maskLine, maskPosition, 0, maskPosition, 240, LV_DRAW_MASK_LINE_SIDE_LEFT);
lv_objmask_update_mask(highlightObjectMask, highlightMask, &maskLine);
lv_draw_mask_line_points_init(&maskLine, maskPosition, 0, maskPosition, 240, LV_DRAW_MASK_LINE_SIDE_RIGHT);
lv_objmask_update_mask(btnObjectMask, btnMask, &maskLine);
}
void Timer::Refresh() {
if (timerController.IsRunning()) {
uint32_t seconds = timerController.GetTimeRemaining() / 1000;
minuteCounter.SetValue(seconds / 60);
secondCounter.SetValue(seconds % 60);
} else if (buttonPressing && xTaskGetTickCount() > pressTime + pdMS_TO_TICKS(150)) {
lv_label_set_text_static(txtPlayPause, "Reset");
maskPosition += 15;
if (maskPosition > 240) {
MaskReset();
Reset();
} else {
UpdateMask();
}
}
}
@@ -66,25 +131,21 @@ void Timer::SetTimerStopped() {
lv_label_set_text_static(txtPlayPause, "Start");
}
void Timer::OnButtonEvent(lv_obj_t* obj, lv_event_t event) {
if (event == LV_EVENT_CLICKED) {
if (obj == btnPlayPause) {
if (timerController.IsRunning()) {
uint32_t seconds = timerController.GetTimeRemaining() / 1000;
minuteCounter.SetValue(seconds / 60);
secondCounter.SetValue(seconds % 60);
timerController.StopTimer();
SetTimerStopped();
} else if (secondCounter.GetValue() + minuteCounter.GetValue() > 0) {
timerController.StartTimer((secondCounter.GetValue() + minuteCounter.GetValue() * 60) * 1000);
Refresh();
SetTimerRunning();
}
}
void Timer::ToggleRunning() {
if (timerController.IsRunning()) {
uint32_t seconds = timerController.GetTimeRemaining() / 1000;
minuteCounter.SetValue(seconds / 60);
secondCounter.SetValue(seconds % 60);
timerController.StopTimer();
SetTimerStopped();
} else if (secondCounter.GetValue() + minuteCounter.GetValue() > 0) {
timerController.StartTimer((secondCounter.GetValue() + minuteCounter.GetValue() * 60) * 1000);
Refresh();
SetTimerRunning();
}
}
void Timer::SetDone() {
void Timer::Reset() {
minuteCounter.SetValue(0);
secondCounter.SetValue(0);
SetTimerStopped();

View File

@@ -5,29 +5,42 @@
#include "systemtask/SystemTask.h"
#include "displayapp/LittleVgl.h"
#include "displayapp/widgets/Counter.h"
#include <lvgl/lvgl.h>
#include "components/timer/TimerController.h"
namespace Pinetime::Applications::Screens {
class Timer : public Screen {
public:
enum class Modes { Normal, Done };
Timer(DisplayApp* app, Controllers::TimerController& timerController);
~Timer() override;
void Refresh() override;
void SetDone();
void OnButtonEvent(lv_obj_t* obj, lv_event_t event);
void Reset();
void ToggleRunning();
void ButtonPressed();
void MaskReset();
private:
void SetTimerRunning();
void SetTimerStopped();
void UpdateMask();
Controllers::TimerController& timerController;
lv_obj_t* msecTime;
lv_obj_t* btnPlayPause;
lv_obj_t* txtPlayPause;
lv_obj_t* btnObjectMask;
lv_obj_t* highlightObjectMask;
lv_objmask_mask_t* btnMask;
lv_objmask_mask_t* highlightMask;
lv_task_t* taskRefresh;
Widgets::Counter minuteCounter = Widgets::Counter(0, 59);
Widgets::Counter secondCounter = Widgets::Counter(0, 59);
Widgets::Counter minuteCounter = Widgets::Counter(0, 59, jetbrains_mono_76);
Widgets::Counter secondCounter = Widgets::Counter(0, 59, jetbrains_mono_76);
bool buttonPressing = false;
int maskPosition = 0;
TickType_t pressTime;
};
}

View File

@@ -1,10 +1,7 @@
#include "displayapp/screens/Twos.h"
#include <array>
#include <cstdio>
#include <cstdlib>
#include <lvgl/lvgl.h>
#include <utility>
#include <vector>
using namespace Pinetime::Applications::Screens;
@@ -21,33 +18,33 @@ Twos::Twos(Pinetime::Applications::DisplayApp* app) : Screen(app) {
lv_style_set_border_width(&style_cell1, LV_STATE_DEFAULT, 3);
lv_style_set_bg_opa(&style_cell1, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_cell1, LV_STATE_DEFAULT, lv_color_hex(0xcdc0b4));
lv_style_set_pad_top(&style_cell1, LV_STATE_DEFAULT, 25);
lv_style_set_pad_top(&style_cell1, LV_STATE_DEFAULT, 29);
lv_style_set_text_color(&style_cell1, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_style_set_border_color(&style_cell2, LV_STATE_DEFAULT, lv_color_hex(0xbbada0));
lv_style_set_border_width(&style_cell2, LV_STATE_DEFAULT, 3);
lv_style_set_bg_opa(&style_cell2, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_cell2, LV_STATE_DEFAULT, lv_color_hex(0xefdfc6));
lv_style_set_pad_top(&style_cell2, LV_STATE_DEFAULT, 25);
lv_style_set_pad_top(&style_cell2, LV_STATE_DEFAULT, 29);
lv_style_set_text_color(&style_cell2, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_style_set_border_color(&style_cell3, LV_STATE_DEFAULT, lv_color_hex(0xbbada0));
lv_style_set_border_width(&style_cell3, LV_STATE_DEFAULT, 3);
lv_style_set_bg_opa(&style_cell3, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_cell3, LV_STATE_DEFAULT, lv_color_hex(0xef9263));
lv_style_set_pad_top(&style_cell3, LV_STATE_DEFAULT, 25);
lv_style_set_pad_top(&style_cell3, LV_STATE_DEFAULT, 29);
lv_style_set_border_color(&style_cell4, LV_STATE_DEFAULT, lv_color_hex(0xbbada0));
lv_style_set_border_width(&style_cell4, LV_STATE_DEFAULT, 3);
lv_style_set_bg_opa(&style_cell4, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_cell4, LV_STATE_DEFAULT, lv_color_hex(0xf76142));
lv_style_set_pad_top(&style_cell4, LV_STATE_DEFAULT, 25);
lv_style_set_pad_top(&style_cell4, LV_STATE_DEFAULT, 29);
lv_style_set_border_color(&style_cell5, LV_STATE_DEFAULT, lv_color_hex(0xbbada0));
lv_style_set_border_width(&style_cell5, LV_STATE_DEFAULT, 3);
lv_style_set_bg_opa(&style_cell5, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_cell5, LV_STATE_DEFAULT, lv_color_hex(0x007dc5));
lv_style_set_pad_top(&style_cell5, LV_STATE_DEFAULT, 25);
lv_style_set_pad_top(&style_cell5, LV_STATE_DEFAULT, 29);
// format grid display
@@ -57,24 +54,22 @@ Twos::Twos(Pinetime::Applications::DisplayApp* app) : Screen(app) {
lv_obj_add_style(gridDisplay, LV_TABLE_PART_CELL3, &style_cell3);
lv_obj_add_style(gridDisplay, LV_TABLE_PART_CELL4, &style_cell4);
lv_obj_add_style(gridDisplay, LV_TABLE_PART_CELL4 + 1, &style_cell5);
lv_table_set_col_cnt(gridDisplay, 4);
lv_table_set_row_cnt(gridDisplay, 4);
lv_table_set_col_width(gridDisplay, 0, LV_HOR_RES / 4);
lv_table_set_col_width(gridDisplay, 1, LV_HOR_RES / 4);
lv_table_set_col_width(gridDisplay, 2, LV_HOR_RES / 4);
lv_table_set_col_width(gridDisplay, 3, LV_HOR_RES / 4);
lv_obj_align(gridDisplay, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
lv_obj_clean_style_list(gridDisplay, LV_TABLE_PART_BG);
// initialize grid
for (int row = 0; row < 4; row++) {
for (int col = 0; col < 4; col++) {
lv_table_set_col_cnt(gridDisplay, nCols);
lv_table_set_row_cnt(gridDisplay, nRows);
for (int col = 0; col < nCols; col++) {
static constexpr int colWidth = LV_HOR_RES_MAX / nCols;
lv_table_set_col_width(gridDisplay, col, colWidth);
for (int row = 0; row < nRows; row++) {
grid[row][col].value = 0;
lv_table_set_cell_type(gridDisplay, row, col, 1);
lv_table_set_cell_align(gridDisplay, row, col, LV_LABEL_ALIGN_CENTER);
}
}
// Move one pixel down to remove a gap
lv_obj_align(gridDisplay, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, 1);
lv_obj_clean_style_list(gridDisplay, LV_TABLE_PART_BG);
placeNewTile();
placeNewTile();
@@ -82,7 +77,7 @@ Twos::Twos(Pinetime::Applications::DisplayApp* app) : Screen(app) {
scoreText = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_width(scoreText, LV_HOR_RES);
lv_label_set_align(scoreText, LV_ALIGN_IN_LEFT_MID);
lv_obj_align(scoreText, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 10);
lv_obj_align(scoreText, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
lv_label_set_recolor(scoreText, true);
lv_label_set_text_fmt(scoreText, "Score #FFFF00 %i#", score);
}
@@ -97,39 +92,38 @@ Twos::~Twos() {
}
bool Twos::placeNewTile() {
std::vector<std::pair<int, int>> availableCells;
for (int row = 0; row < 4; row++) {
for (int col = 0; col < 4; col++) {
if (!grid[row][col].value) {
availableCells.push_back(std::make_pair(row, col));
}
unsigned int emptyCells[nCells];
unsigned int nEmpty = 0;
for (unsigned int i = 0; i < nCells; i++) {
const unsigned int row = i / nCols;
const unsigned int col = i % nCols;
if (grid[row][col].value == 0) {
emptyCells[nEmpty] = i;
nEmpty++;
}
}
if (availableCells.size() == 0) {
if (nEmpty == 0) {
return false; // game lost
}
auto it = availableCells.cbegin();
int random = rand() % availableCells.size();
std::advance(it, random);
std::pair<int, int> newCell = *it;
int random = rand() % nEmpty;
if ((rand() % 100) < 90)
grid[newCell.first][newCell.second].value = 2;
else
grid[newCell.first][newCell.second].value = 4;
updateGridDisplay(grid);
if ((rand() % 100) < 90) {
grid[emptyCells[random] / nCols][emptyCells[random] % nCols].value = 2;
} else {
grid[emptyCells[random] / nCols][emptyCells[random] % nCols].value = 4;
}
updateGridDisplay();
return true;
}
bool Twos::tryMerge(TwosTile grid[][4], int& newRow, int& newCol, int oldRow, int oldCol) {
bool Twos::tryMerge(int newRow, int newCol, int oldRow, int oldCol) {
if (grid[newRow][newCol].value == grid[oldRow][oldCol].value) {
if ((newCol != oldCol) || (newRow != oldRow)) {
if (!grid[newRow][newCol].merged) {
unsigned int newVal = grid[oldRow][oldCol].value *= 2;
grid[newRow][newCol].value = newVal;
score += newVal;
grid[newRow][newCol].value *= 2;
score += grid[newRow][newCol].value;
lv_label_set_text_fmt(scoreText, "Score #FFFF00 %i#", score);
grid[oldRow][oldCol].value = 0;
grid[newRow][newCol].merged = true;
@@ -140,7 +134,7 @@ bool Twos::tryMerge(TwosTile grid[][4], int& newRow, int& newCol, int oldRow, in
return false;
}
bool Twos::tryMove(TwosTile grid[][4], int newRow, int newCol, int oldRow, int oldCol) {
bool Twos::tryMove(int newRow, int newCol, int oldRow, int oldCol) {
if (((newCol >= 0) && (newCol != oldCol)) || ((newRow >= 0) && (newRow != oldRow))) {
grid[newRow][newCol].value = grid[oldRow][oldCol].value;
grid[oldRow][oldCol].value = 0;
@@ -151,28 +145,30 @@ bool Twos::tryMove(TwosTile grid[][4], int newRow, int newCol, int oldRow, int o
bool Twos::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
bool validMove = false;
for (int row = 0; row < 4; row++) {
for (int col = 0; col < 4; col++) {
grid[row][col].merged = false; // reinitialize merge state
}
for (unsigned int i = 0; i < nCells; i++) {
const unsigned int row = i / nCols;
const unsigned int col = i % nCols;
grid[row][col].merged = false; // reinitialize merge state
}
switch (event) {
case TouchEvents::SwipeLeft:
for (int col = 1; col < 4; col++) { // ignore tiles already on far left
for (int row = 0; row < 4; row++) {
if (grid[row][col].value) {
for (int col = 1; col < nCols; col++) { // ignore tiles already on far left
for (int row = 0; row < nRows; row++) {
if (grid[row][col].value > 0) {
int newCol = -1;
for (int potentialNewCol = col - 1; potentialNewCol >= 0; potentialNewCol--) {
if (!grid[row][potentialNewCol].value) {
if (grid[row][potentialNewCol].value == 0) {
newCol = potentialNewCol;
} else { // blocked by another tile
if (tryMerge(grid, row, potentialNewCol, row, col))
if (tryMerge(row, potentialNewCol, row, col)) {
validMove = true;
}
break;
}
}
if (tryMove(grid, row, newCol, row, col))
if (tryMove(row, newCol, row, col)) {
validMove = true;
}
}
}
}
@@ -181,21 +177,23 @@ bool Twos::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
}
return true;
case TouchEvents::SwipeRight:
for (int col = 2; col >= 0; col--) { // ignore tiles already on far right
for (int row = 0; row < 4; row++) {
if (grid[row][col].value) {
for (int col = nCols - 2; col >= 0; col--) { // ignore tiles already on far right
for (int row = 0; row < nRows; row++) {
if (grid[row][col].value > 0) {
int newCol = -1;
for (int potentialNewCol = col + 1; potentialNewCol < 4; potentialNewCol++) {
if (!grid[row][potentialNewCol].value) {
for (int potentialNewCol = col + 1; potentialNewCol < nCols; potentialNewCol++) {
if (grid[row][potentialNewCol].value == 0) {
newCol = potentialNewCol;
} else { // blocked by another tile
if (tryMerge(grid, row, potentialNewCol, row, col))
if (tryMerge(row, potentialNewCol, row, col)) {
validMove = true;
}
break;
}
}
if (tryMove(grid, row, newCol, row, col))
if (tryMove(row, newCol, row, col)) {
validMove = true;
}
}
}
}
@@ -204,21 +202,23 @@ bool Twos::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
}
return true;
case TouchEvents::SwipeUp:
for (int row = 1; row < 4; row++) { // ignore tiles already on top
for (int col = 0; col < 4; col++) {
if (grid[row][col].value) {
for (int row = 1; row < nRows; row++) { // ignore tiles already on top
for (int col = 0; col < nCols; col++) {
if (grid[row][col].value > 0) {
int newRow = -1;
for (int potentialNewRow = row - 1; potentialNewRow >= 0; potentialNewRow--) {
if (!grid[potentialNewRow][col].value) {
if (grid[potentialNewRow][col].value == 0) {
newRow = potentialNewRow;
} else { // blocked by another tile
if (tryMerge(grid, potentialNewRow, col, row, col))
if (tryMerge(potentialNewRow, col, row, col)) {
validMove = true;
}
break;
}
}
if (tryMove(grid, newRow, col, row, col))
if (tryMove(newRow, col, row, col)) {
validMove = true;
}
}
}
}
@@ -227,21 +227,23 @@ bool Twos::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
}
return true;
case TouchEvents::SwipeDown:
for (int row = 2; row >= 0; row--) { // ignore tiles already on bottom
for (int col = 0; col < 4; col++) {
if (grid[row][col].value) {
for (int row = nRows - 2; row >= 0; row--) { // ignore tiles already on bottom
for (int col = 0; col < nCols; col++) {
if (grid[row][col].value > 0) {
int newRow = -1;
for (int potentialNewRow = row + 1; potentialNewRow < 4; potentialNewRow++) {
if (!grid[potentialNewRow][col].value) {
for (int potentialNewRow = row + 1; potentialNewRow < nRows; potentialNewRow++) {
if (grid[potentialNewRow][col].value == 0) {
newRow = potentialNewRow;
} else { // blocked by another tile
if (tryMerge(grid, potentialNewRow, col, row, col))
if (tryMerge(potentialNewRow, col, row, col)) {
validMove = true;
}
break;
}
}
if (tryMove(grid, newRow, col, row, col))
if (tryMove(newRow, col, row, col)) {
validMove = true;
}
}
}
}
@@ -255,36 +257,36 @@ bool Twos::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
return false;
}
void Twos::updateGridDisplay(TwosTile grid[][4]) {
for (int row = 0; row < 4; row++) {
for (int col = 0; col < 4; col++) {
if (grid[row][col].value) {
char buffer[7];
sprintf(buffer, "%d", grid[row][col].value);
lv_table_set_cell_value(gridDisplay, row, col, buffer);
} else {
lv_table_set_cell_value(gridDisplay, row, col, "");
}
switch (grid[row][col].value) {
case 0:
lv_table_set_cell_type(gridDisplay, row, col, 1);
break;
case 2:
case 4:
lv_table_set_cell_type(gridDisplay, row, col, 2);
break;
case 8:
case 16:
lv_table_set_cell_type(gridDisplay, row, col, 3);
break;
case 32:
case 64:
lv_table_set_cell_type(gridDisplay, row, col, 4);
break;
default:
lv_table_set_cell_type(gridDisplay, row, col, 5);
break;
}
void Twos::updateGridDisplay() {
for (unsigned int i = 0; i < nCells; i++) {
const unsigned int row = i / nCols;
const unsigned int col = i % nCols;
if (grid[row][col].value > 0) {
char buffer[7];
sprintf(buffer, "%d", grid[row][col].value);
lv_table_set_cell_value(gridDisplay, row, col, buffer);
} else {
lv_table_set_cell_value(gridDisplay, row, col, "");
}
switch (grid[row][col].value) {
case 0:
lv_table_set_cell_type(gridDisplay, row, col, 1);
break;
case 2:
case 4:
lv_table_set_cell_type(gridDisplay, row, col, 2);
break;
case 8:
case 16:
lv_table_set_cell_type(gridDisplay, row, col, 3);
break;
case 32:
case 64:
lv_table_set_cell_type(gridDisplay, row, col, 4);
break;
default:
lv_table_set_cell_type(gridDisplay, row, col, 5);
break;
}
}
}

View File

@@ -26,11 +26,14 @@ namespace Pinetime {
lv_obj_t* scoreText;
lv_obj_t* gridDisplay;
TwosTile grid[4][4];
static constexpr int nCols = 4;
static constexpr int nRows = 4;
static constexpr int nCells = nCols * nRows;
TwosTile grid[nRows][nCols];
unsigned int score = 0;
void updateGridDisplay(TwosTile grid[][4]);
bool tryMerge(TwosTile grid[][4], int& newRow, int& newCol, int oldRow, int oldCol);
bool tryMove(TwosTile grid[][4], int newRow, int newCol, int oldRow, int oldCol);
void updateGridDisplay();
bool tryMerge(int newRow, int newCol, int oldRow, int oldCol);
bool tryMove(int newRow, int newCol, int oldRow, int oldCol);
bool placeNewTile();
};
}

View File

@@ -6,6 +6,7 @@
#include "displayapp/screens/Symbols.h"
#include "displayapp/screens/NotificationIcon.h"
#include "components/settings/Settings.h"
#include "displayapp/InfiniTimeTheme.h"
LV_IMG_DECLARE(bg_clock);
@@ -73,14 +74,14 @@ WatchFaceAnalog::WatchFaceAnalog(Pinetime::Applications::DisplayApp* app,
lv_obj_align(plugIcon, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0);
notificationIcon = lv_label_create(lv_scr_act(), NULL);
lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FF00));
lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_LIME);
lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false));
lv_obj_align(notificationIcon, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0);
// Date - Day / Week day
label_date_day = lv_label_create(lv_scr_act(), NULL);
lv_obj_set_style_local_text_color(label_date_day, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0xff, 0xb0, 0x0));
lv_obj_set_style_local_text_color(label_date_day, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::orange);
lv_label_set_text_fmt(label_date_day, "%s\n%02i", dateTimeController.DayOfWeekShortToString(), dateTimeController.Day());
lv_label_set_align(label_date_day, LV_LABEL_ALIGN_CENTER);
lv_obj_align(label_date_day, NULL, LV_ALIGN_CENTER, 50, 0);

View File

@@ -3,8 +3,6 @@
#include <date/date.h>
#include <lvgl/lvgl.h>
#include <cstdio>
#include "displayapp/screens/BatteryIcon.h"
#include "displayapp/screens/BleIcon.h"
#include "displayapp/screens/NotificationIcon.h"
#include "displayapp/screens/Symbols.h"
#include "components/battery/BatteryController.h"
@@ -13,6 +11,7 @@
#include "components/heartrate/HeartRateController.h"
#include "components/motion/MotionController.h"
#include "components/settings/Settings.h"
using namespace Pinetime::Applications::Screens;
WatchFaceDigital::WatchFaceDigital(DisplayApp* app,
@@ -26,28 +25,16 @@ WatchFaceDigital::WatchFaceDigital(DisplayApp* app,
: Screen(app),
currentDateTime {{}},
dateTimeController {dateTimeController},
batteryController {batteryController},
bleController {bleController},
notificatioManager {notificatioManager},
settingsController {settingsController},
heartRateController {heartRateController},
motionController {motionController} {
motionController {motionController},
statusIcons(batteryController, bleController) {
batteryIcon.Create(lv_scr_act());
lv_obj_align(batteryIcon.GetObject(), lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, 0, 0);
batteryPlug = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(batteryPlug, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xFF0000));
lv_label_set_text_static(batteryPlug, Symbols::plug);
lv_obj_align(batteryPlug, batteryIcon.GetObject(), LV_ALIGN_OUT_LEFT_MID, -5, 0);
bleIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x0082FC));
lv_label_set_text_static(bleIcon, Symbols::bluetooth);
lv_obj_align(bleIcon, batteryPlug, LV_ALIGN_OUT_LEFT_MID, -5, 0);
statusIcons.Create();
notificationIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FF00));
lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_LIME);
lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false));
lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
@@ -94,24 +81,7 @@ WatchFaceDigital::~WatchFaceDigital() {
}
void WatchFaceDigital::Refresh() {
powerPresent = batteryController.IsPowerPresent();
if (powerPresent.IsUpdated()) {
lv_label_set_text_static(batteryPlug, BatteryIcon::GetPlugIcon(powerPresent.Get()));
}
batteryPercentRemaining = batteryController.PercentRemaining();
if (batteryPercentRemaining.IsUpdated()) {
auto batteryPercent = batteryPercentRemaining.Get();
batteryIcon.SetBatteryPercentage(batteryPercent);
}
bleState = bleController.IsConnected();
bleRadioEnabled = bleController.IsRadioEnabled();
if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) {
lv_label_set_text_static(bleIcon, BleIcon::GetIcon(bleState.Get()));
}
lv_obj_realign(batteryPlug);
lv_obj_realign(bleIcon);
statusIcons.Update();
notificationState = notificatioManager.AreNewNotificationsAvailable();
if (notificationState.IsUpdated()) {

View File

@@ -1,6 +1,5 @@
#pragma once
#include <displayapp/screens/BatteryIcon.h>
#include <lvgl/src/lv_core/lv_obj.h>
#include <chrono>
#include <cstdint>
@@ -8,6 +7,7 @@
#include "displayapp/screens/Screen.h"
#include "components/datetime/DateTimeController.h"
#include "components/ble/BleController.h"
#include "displayapp/widgets/StatusIcons.h"
namespace Pinetime {
namespace Controllers {
@@ -59,25 +59,20 @@ namespace Pinetime {
lv_obj_t* label_time;
lv_obj_t* label_time_ampm;
lv_obj_t* label_date;
lv_obj_t* bleIcon;
lv_obj_t* batteryPlug;
lv_obj_t* heartbeatIcon;
lv_obj_t* heartbeatValue;
lv_obj_t* stepIcon;
lv_obj_t* stepValue;
lv_obj_t* notificationIcon;
BatteryIcon batteryIcon;
Controllers::DateTime& dateTimeController;
Controllers::Battery& batteryController;
Controllers::Ble& bleController;
Controllers::NotificationManager& notificatioManager;
Controllers::Settings& settingsController;
Controllers::HeartRateController& heartRateController;
Controllers::MotionController& motionController;
lv_task_t* taskRefresh;
Widgets::StatusIcons statusIcons;
};
}
}

View File

@@ -42,13 +42,6 @@ namespace {
auto* screen = static_cast<WatchFacePineTimeStyle*>(obj->user_data);
screen->UpdateSelected(obj, event);
}
bool IsBleIconVisible(bool isRadioEnabled, bool isConnected) {
if (!isRadioEnabled) {
return true;
}
return isConnected;
}
}
WatchFacePineTimeStyle::WatchFacePineTimeStyle(DisplayApp* app,
@@ -111,11 +104,11 @@ WatchFacePineTimeStyle::WatchFacePineTimeStyle(DisplayApp* app,
lv_obj_align(plugIcon, sidebar, LV_ALIGN_IN_TOP_MID, 0, 2);
bleIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_label_set_text_static(bleIcon, "");
notificationIcon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x000000));
lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_label_set_text_static(notificationIcon, "");
// Calendar icon

View File

@@ -149,7 +149,7 @@ void WatchFaceTerminal::Refresh() {
}
if ((year != currentYear) || (month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) {
lv_label_set_text_fmt(label_date, "[DATE]#007fff %04d.%02d.%02d#", short(year), char(month), char(day));
lv_label_set_text_fmt(label_date, "[DATE]#007fff %04d-%02d-%02d#", short(year), char(month), char(day));
currentYear = year;
currentMonth = month;

View File

@@ -2,19 +2,29 @@
#include "displayapp/DisplayApp.h"
#include "displayapp/screens/Symbols.h"
#include "displayapp/screens/BatteryIcon.h"
#include "components/ble/BleController.h"
#include "displayapp/InfiniTimeTheme.h"
using namespace Pinetime::Applications::Screens;
namespace {
void ButtonEventHandler(lv_obj_t* obj, lv_event_t event) {
auto* screen = static_cast<QuickSettings*>(obj->user_data);
screen->OnButtonEvent(obj, event);
if (event == LV_EVENT_CLICKED) {
screen->OnButtonEvent(obj);
}
}
void lv_update_task(struct _lv_task_t* task) {
auto* user_data = static_cast<QuickSettings*>(task->user_data);
user_data->UpdateScreen();
}
enum class ButtonState : lv_state_t {
NotificationsOn = LV_STATE_CHECKED,
NotificationsOff = LV_STATE_DEFAULT,
Sleep = 0x40,
};
}
QuickSettings::QuickSettings(Pinetime::Applications::DisplayApp* app,
@@ -22,13 +32,16 @@ QuickSettings::QuickSettings(Pinetime::Applications::DisplayApp* app,
Controllers::DateTime& dateTimeController,
Controllers::BrightnessController& brightness,
Controllers::MotorController& motorController,
Pinetime::Controllers::Settings& settingsController)
Pinetime::Controllers::Settings& settingsController,
Controllers::Ble& bleController)
: Screen(app),
batteryController {batteryController},
dateTimeController {dateTimeController},
brightness {brightness},
motorController {motorController},
settingsController {settingsController} {
settingsController {settingsController},
statusIcons(batteryController, bleController) {
statusIcons.Create();
// This is the distance (padding) between all objects on this screen.
static constexpr uint8_t innerDistance = 10;
@@ -38,9 +51,6 @@ QuickSettings::QuickSettings(Pinetime::Applications::DisplayApp* app,
lv_label_set_align(label_time, LV_LABEL_ALIGN_CENTER);
lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 0, 0);
batteryIcon.Create(lv_scr_act());
lv_obj_align(batteryIcon.GetObject(), nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0);
static constexpr uint8_t barHeight = 20 + innerDistance;
static constexpr uint8_t buttonHeight = (LV_VER_RES_MAX - barHeight - innerDistance) / 2;
static constexpr uint8_t buttonWidth = (LV_HOR_RES_MAX - innerDistance) / 2; // wide buttons
@@ -49,7 +59,7 @@ QuickSettings::QuickSettings(Pinetime::Applications::DisplayApp* app,
lv_style_init(&btn_style);
lv_style_set_radius(&btn_style, LV_STATE_DEFAULT, buttonHeight / 4);
lv_style_set_bg_color(&btn_style, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x38, 0x38, 0x38));
lv_style_set_bg_color(&btn_style, LV_STATE_DEFAULT, Colors::bgAlt);
btn1 = lv_btn_create(lv_scr_act(), nullptr);
btn1->user_data = this;
@@ -72,25 +82,29 @@ QuickSettings::QuickSettings(Pinetime::Applications::DisplayApp* app,
lv_obj_t* lbl_btn;
lbl_btn = lv_label_create(btn2, nullptr);
lv_obj_set_style_local_text_font(lbl_btn, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &lv_font_sys_48);
lv_label_set_text_static(lbl_btn, Symbols::highlight);
lv_label_set_text_static(lbl_btn, Symbols::flashlight);
btn3 = lv_btn_create(lv_scr_act(), nullptr);
btn3->user_data = this;
lv_obj_set_event_cb(btn3, ButtonEventHandler);
lv_btn_set_checkable(btn3, true);
lv_obj_add_style(btn3, LV_BTN_PART_MAIN, &btn_style);
lv_obj_set_style_local_bg_color(btn3, LV_BTN_PART_MAIN, LV_STATE_CHECKED, LV_COLOR_MAKE(0x0, 0xb0, 0x0));
lv_obj_set_style_local_bg_color(btn3, LV_BTN_PART_MAIN, static_cast<lv_state_t>(ButtonState::NotificationsOff), LV_COLOR_RED);
static constexpr lv_color_t violet = LV_COLOR_MAKE(0x60, 0x00, 0xff);
lv_obj_set_style_local_bg_color(btn3, LV_BTN_PART_MAIN, static_cast<lv_state_t>(ButtonState::Sleep), violet);
lv_obj_set_size(btn3, buttonWidth, buttonHeight);
lv_obj_align(btn3, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, buttonXOffset, 0);
btn3_lvl = lv_label_create(btn3, nullptr);
lv_obj_set_style_local_text_font(btn3_lvl, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &lv_font_sys_48);
if (settingsController.GetNotificationStatus() == Controllers::Settings::Notification::ON) {
lv_obj_add_state(btn3, LV_STATE_CHECKED);
if (settingsController.GetNotificationStatus() == Controllers::Settings::Notification::On) {
lv_label_set_text_static(btn3_lvl, Symbols::notificationsOn);
} else {
lv_obj_set_state(btn3, static_cast<lv_state_t>(ButtonState::NotificationsOn));
} else if (settingsController.GetNotificationStatus() == Controllers::Settings::Notification::Off) {
lv_label_set_text_static(btn3_lvl, Symbols::notificationsOff);
} else {
lv_label_set_text_static(btn3_lvl, Symbols::sleep);
lv_obj_set_state(btn3, static_cast<lv_state_t>(ButtonState::Sleep));
}
btn4 = lv_btn_create(lv_scr_act(), nullptr);
@@ -118,34 +132,36 @@ QuickSettings::~QuickSettings() {
void QuickSettings::UpdateScreen() {
lv_label_set_text(label_time, dateTimeController.FormattedTime().c_str());
batteryIcon.SetBatteryPercentage(batteryController.PercentRemaining());
statusIcons.Update();
}
void QuickSettings::OnButtonEvent(lv_obj_t* object, lv_event_t event) {
if (object == btn2 && event == LV_EVENT_CLICKED) {
running = false;
void QuickSettings::OnButtonEvent(lv_obj_t* object) {
if (object == btn2) {
app->StartApp(Apps::FlashLight, DisplayApp::FullRefreshDirections::Up);
} else if (object == btn1 && event == LV_EVENT_CLICKED) {
} else if (object == btn1) {
brightness.Step();
lv_label_set_text_static(btn1_lvl, brightness.GetIcon());
settingsController.SetBrightness(brightness.Level());
} else if (object == btn3 && event == LV_EVENT_VALUE_CHANGED) {
} else if (object == btn3) {
if (lv_obj_get_state(btn3, LV_BTN_PART_MAIN) & LV_STATE_CHECKED) {
settingsController.SetNotificationStatus(Controllers::Settings::Notification::ON);
motorController.RunForDuration(35);
lv_label_set_text_static(btn3_lvl, Symbols::notificationsOn);
} else {
settingsController.SetNotificationStatus(Controllers::Settings::Notification::OFF);
if (settingsController.GetNotificationStatus() == Controllers::Settings::Notification::On) {
settingsController.SetNotificationStatus(Controllers::Settings::Notification::Off);
lv_label_set_text_static(btn3_lvl, Symbols::notificationsOff);
lv_obj_set_state(btn3, static_cast<lv_state_t>(ButtonState::NotificationsOff));
} else if (settingsController.GetNotificationStatus() == Controllers::Settings::Notification::Off) {
settingsController.SetNotificationStatus(Controllers::Settings::Notification::Sleep);
lv_label_set_text_static(btn3_lvl, Symbols::sleep);
lv_obj_set_state(btn3, static_cast<lv_state_t>(ButtonState::Sleep));
} else {
settingsController.SetNotificationStatus(Controllers::Settings::Notification::On);
lv_label_set_text_static(btn3_lvl, Symbols::notificationsOn);
lv_obj_set_state(btn3, static_cast<lv_state_t>(ButtonState::NotificationsOn));
motorController.RunForDuration(35);
}
} else if (object == btn4 && event == LV_EVENT_CLICKED) {
running = false;
} else if (object == btn4) {
settingsController.SetSettingsMenu(0);
app->StartApp(Apps::Settings, DisplayApp::FullRefreshDirections::Up);
}

View File

@@ -8,7 +8,7 @@
#include "components/motor/MotorController.h"
#include "components/settings/Settings.h"
#include "components/battery/BatteryController.h"
#include <displayapp/screens/BatteryIcon.h>
#include "displayapp/widgets/StatusIcons.h"
namespace Pinetime {
@@ -22,16 +22,16 @@ namespace Pinetime {
Controllers::DateTime& dateTimeController,
Controllers::BrightnessController& brightness,
Controllers::MotorController& motorController,
Pinetime::Controllers::Settings& settingsController);
Pinetime::Controllers::Settings& settingsController,
Controllers::Ble& bleController);
~QuickSettings() override;
void OnButtonEvent(lv_obj_t* object, lv_event_t event);
void OnButtonEvent(lv_obj_t* object);
void UpdateScreen();
private:
Pinetime::Controllers::Battery& batteryController;
Controllers::DateTime& dateTimeController;
Controllers::BrightnessController& brightness;
Controllers::MotorController& motorController;
@@ -49,7 +49,7 @@ namespace Pinetime {
lv_obj_t* btn3_lvl;
lv_obj_t* btn4;
BatteryIcon batteryIcon;
Widgets::StatusIcons statusIcons;
};
}
}

View File

@@ -14,6 +14,8 @@ namespace {
}
}
constexpr std::array<SettingChimes::Option, 3> SettingChimes::options;
SettingChimes::SettingChimes(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController)
: Screen(app), settingsController {settingsController} {
@@ -40,37 +42,16 @@ SettingChimes::SettingChimes(Pinetime::Applications::DisplayApp* app, Pinetime::
lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER);
lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0);
optionsTotal = 0;
cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr);
lv_checkbox_set_text_static(cbOption[optionsTotal], " Off");
cbOption[optionsTotal]->user_data = this;
lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
SetRadioButtonStyle(cbOption[optionsTotal]);
if (settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::None) {
lv_checkbox_set_checked(cbOption[optionsTotal], true);
for (unsigned int i = 0; i < options.size(); i++) {
cbOption[i] = lv_checkbox_create(container1, nullptr);
lv_checkbox_set_text(cbOption[i], options[i].name);
if (settingsController.GetChimeOption() == options[i].chimesOption) {
lv_checkbox_set_checked(cbOption[i], true);
}
cbOption[i]->user_data = this;
lv_obj_set_event_cb(cbOption[i], event_handler);
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() {
@@ -80,18 +61,10 @@ SettingChimes::~SettingChimes() {
void SettingChimes::UpdateSelected(lv_obj_t* object, lv_event_t event) {
if (event == LV_EVENT_VALUE_CHANGED) {
for (uint8_t i = 0; i < optionsTotal; i++) {
for (uint8_t i = 0; i < options.size(); i++) {
if (object == cbOption[i]) {
lv_checkbox_set_checked(cbOption[i], true);
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);
}
settingsController.SetChimeOption(options[i].chimesOption);
} else {
lv_checkbox_set_checked(cbOption[i], false);
}

View File

@@ -4,6 +4,7 @@
#include <lvgl/lvgl.h>
#include "components/settings/Settings.h"
#include "displayapp/screens/Screen.h"
#include <array>
namespace Pinetime {
@@ -18,9 +19,19 @@ namespace Pinetime {
void UpdateSelected(lv_obj_t* object, lv_event_t event);
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;
uint8_t optionsTotal;
lv_obj_t* cbOption[3];
};
}
}

View File

@@ -15,7 +15,7 @@ namespace {
}
}
constexpr std::array<uint16_t, 4> SettingDisplay::options;
constexpr std::array<uint16_t, 6> SettingDisplay::options;
SettingDisplay::SettingDisplay(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController)
: Screen(app), settingsController {settingsController} {
@@ -30,7 +30,7 @@ SettingDisplay::SettingDisplay(Pinetime::Applications::DisplayApp* app, Pinetime
lv_obj_set_pos(container1, 10, 60);
lv_obj_set_width(container1, LV_HOR_RES - 20);
lv_obj_set_height(container1, LV_VER_RES - 50);
lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT);
lv_cont_set_layout(container1, LV_LAYOUT_PRETTY_TOP);
lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_text_static(title, "Display timeout");
@@ -46,7 +46,7 @@ SettingDisplay::SettingDisplay(Pinetime::Applications::DisplayApp* app, Pinetime
char buffer[12];
for (unsigned int i = 0; i < options.size(); i++) {
cbOption[i] = lv_checkbox_create(container1, nullptr);
sprintf(buffer, "%3d seconds", options[i] / 1000);
sprintf(buffer, "%2ds", options[i] / 1000);
lv_checkbox_set_text(cbOption[i], buffer);
cbOption[i]->user_data = this;
lv_obj_set_event_cb(cbOption[i], event_handler);

View File

@@ -20,7 +20,7 @@ namespace Pinetime {
void UpdateSelected(lv_obj_t* object, lv_event_t event);
private:
static constexpr std::array<uint16_t, 4> options = {5000, 15000, 20000, 30000};
static constexpr std::array<uint16_t, 6> options = {5000, 7000, 10000, 15000, 20000, 30000};
Controllers::Settings& settingsController;
lv_obj_t* cbOption[options.size()];

View File

@@ -11,13 +11,36 @@ namespace {
constexpr int16_t POS_X_DAY = -72;
constexpr int16_t POS_X_MONTH = 0;
constexpr int16_t POS_X_YEAR = 72;
constexpr int16_t POS_Y_PLUS = -50;
constexpr int16_t POS_Y_TEXT = -6;
constexpr int16_t POS_Y_MINUS = 40;
void event_handler(lv_obj_t* obj, lv_event_t event) {
auto* screen = static_cast<SettingSetDate*>(obj->user_data);
screen->HandleButtonPress(obj, event);
if (event == LV_EVENT_CLICKED) {
screen->HandleButtonPress();
}
}
void ValueChangedHandler(void* userData) {
auto* screen = static_cast<SettingSetDate*>(userData);
screen->CheckDay();
}
int MaximumDayOfMonth(uint8_t month, uint16_t year) {
switch (month) {
case 2: {
if ((((year % 4) == 0) && ((year % 100) != 0)) || ((year % 400) == 0)) {
return 29;
}
return 28;
}
case 4:
case 6:
case 9:
case 11:
return 30;
default:
return 31;
}
}
}
@@ -35,164 +58,54 @@ SettingSetDate::SettingSetDate(Pinetime::Applications::DisplayApp* app, Pinetime
lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER);
lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0);
dayValue = static_cast<int>(dateTimeController.Day());
lblDay = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_text_fmt(lblDay, "%d", dayValue);
lv_label_set_align(lblDay, LV_LABEL_ALIGN_CENTER);
lv_obj_align(lblDay, lv_scr_act(), LV_ALIGN_CENTER, POS_X_DAY, POS_Y_TEXT);
lv_obj_set_auto_realign(lblDay, true);
dayCounter.SetValueChangedEventCallback(this, ValueChangedHandler);
dayCounter.Create();
dayCounter.SetValue(dateTimeController.Day());
lv_obj_align(dayCounter.GetObject(), nullptr, LV_ALIGN_CENTER, POS_X_DAY, POS_Y_TEXT);
monthValue = static_cast<int>(dateTimeController.Month());
lblMonth = lv_label_create(lv_scr_act(), nullptr);
UpdateMonthLabel();
lv_label_set_align(lblMonth, LV_LABEL_ALIGN_CENTER);
lv_obj_align(lblMonth, lv_scr_act(), LV_ALIGN_CENTER, POS_X_MONTH, POS_Y_TEXT);
lv_obj_set_auto_realign(lblMonth, true);
monthCounter.EnableMonthMode();
monthCounter.SetValueChangedEventCallback(this, ValueChangedHandler);
monthCounter.Create();
monthCounter.SetValue(static_cast<int>(dateTimeController.Month()));
lv_obj_align(monthCounter.GetObject(), nullptr, LV_ALIGN_CENTER, POS_X_MONTH, POS_Y_TEXT);
yearValue = static_cast<int>(dateTimeController.Year());
if (yearValue < 2021)
yearValue = 2021;
lblYear = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_text_fmt(lblYear, "%d", yearValue);
lv_label_set_align(lblYear, LV_LABEL_ALIGN_CENTER);
lv_obj_align(lblYear, lv_scr_act(), LV_ALIGN_CENTER, POS_X_YEAR, POS_Y_TEXT);
lv_obj_set_auto_realign(lblYear, true);
btnDayPlus = lv_btn_create(lv_scr_act(), nullptr);
btnDayPlus->user_data = this;
lv_obj_set_size(btnDayPlus, 50, 40);
lv_obj_align(btnDayPlus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_DAY, POS_Y_PLUS);
lv_obj_set_style_local_value_str(btnDayPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "+");
lv_obj_set_event_cb(btnDayPlus, event_handler);
btnDayMinus = lv_btn_create(lv_scr_act(), nullptr);
btnDayMinus->user_data = this;
lv_obj_set_size(btnDayMinus, 50, 40);
lv_obj_align(btnDayMinus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_DAY, POS_Y_MINUS);
lv_obj_set_style_local_value_str(btnDayMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "-");
lv_obj_set_event_cb(btnDayMinus, event_handler);
btnMonthPlus = lv_btn_create(lv_scr_act(), nullptr);
btnMonthPlus->user_data = this;
lv_obj_set_size(btnMonthPlus, 50, 40);
lv_obj_align(btnMonthPlus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_MONTH, POS_Y_PLUS);
lv_obj_set_style_local_value_str(btnMonthPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "+");
lv_obj_set_event_cb(btnMonthPlus, event_handler);
btnMonthMinus = lv_btn_create(lv_scr_act(), nullptr);
btnMonthMinus->user_data = this;
lv_obj_set_size(btnMonthMinus, 50, 40);
lv_obj_align(btnMonthMinus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_MONTH, POS_Y_MINUS);
lv_obj_set_style_local_value_str(btnMonthMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "-");
lv_obj_set_event_cb(btnMonthMinus, event_handler);
btnYearPlus = lv_btn_create(lv_scr_act(), nullptr);
btnYearPlus->user_data = this;
lv_obj_set_size(btnYearPlus, 50, 40);
lv_obj_align(btnYearPlus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_YEAR, POS_Y_PLUS);
lv_obj_set_style_local_value_str(btnYearPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "+");
lv_obj_set_event_cb(btnYearPlus, event_handler);
btnYearMinus = lv_btn_create(lv_scr_act(), nullptr);
btnYearMinus->user_data = this;
lv_obj_set_size(btnYearMinus, 50, 40);
lv_obj_align(btnYearMinus, lv_scr_act(), LV_ALIGN_CENTER, POS_X_YEAR, POS_Y_MINUS);
lv_obj_set_style_local_value_str(btnYearMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "-");
lv_obj_set_event_cb(btnYearMinus, event_handler);
yearCounter.SetValueChangedEventCallback(this, ValueChangedHandler);
yearCounter.Create();
yearCounter.SetValue(dateTimeController.Year());
lv_obj_align(yearCounter.GetObject(), nullptr, LV_ALIGN_CENTER, POS_X_YEAR, POS_Y_TEXT);
btnSetTime = lv_btn_create(lv_scr_act(), nullptr);
btnSetTime->user_data = this;
lv_obj_set_size(btnSetTime, 120, 48);
lv_obj_align(btnSetTime, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0);
lv_obj_set_style_local_bg_color(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x38, 0x38, 0x38));
lv_obj_set_style_local_value_str(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Set");
lv_obj_set_event_cb(btnSetTime, event_handler);
lv_btn_set_state(btnSetTime, LV_BTN_STATE_DISABLED);
}
SettingSetDate::~SettingSetDate() {
lv_obj_clean(lv_scr_act());
}
void SettingSetDate::HandleButtonPress(lv_obj_t* object, lv_event_t event) {
if (event != LV_EVENT_CLICKED)
return;
if (object == btnDayPlus) {
dayValue++;
if (dayValue > MaximumDayOfMonth())
dayValue = 1;
lv_label_set_text_fmt(lblDay, "%d", dayValue);
lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
} else if (object == btnDayMinus) {
dayValue--;
if (dayValue < 1)
dayValue = MaximumDayOfMonth();
lv_label_set_text_fmt(lblDay, "%d", dayValue);
lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
} else if (object == btnMonthPlus) {
monthValue++;
if (monthValue > 12)
monthValue = 1;
UpdateMonthLabel();
lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
CheckDay();
} else if (object == btnMonthMinus) {
monthValue--;
if (monthValue < 1)
monthValue = 12;
UpdateMonthLabel();
lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
CheckDay();
} else if (object == btnYearPlus) {
yearValue++;
lv_label_set_text_fmt(lblYear, "%d", yearValue);
lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
CheckDay();
} else if (object == btnYearMinus) {
yearValue--;
lv_label_set_text_fmt(lblYear, "%d", yearValue);
lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
CheckDay();
} else if (object == btnSetTime) {
NRF_LOG_INFO("Setting date (manually) to %04d-%02d-%02d", yearValue, monthValue, dayValue);
dateTimeController.SetTime(static_cast<uint16_t>(yearValue),
static_cast<uint8_t>(monthValue),
static_cast<uint8_t>(dayValue),
0,
dateTimeController.Hours(),
dateTimeController.Minutes(),
dateTimeController.Seconds(),
nrf_rtc_counter_get(portNRF_RTC_REG));
lv_btn_set_state(btnSetTime, LV_BTN_STATE_DISABLED);
}
}
int SettingSetDate::MaximumDayOfMonth() const {
switch (monthValue) {
case 2:
if ((((yearValue % 4) == 0) && ((yearValue % 100) != 0)) || ((yearValue % 400) == 0))
return 29;
return 28;
case 4:
case 6:
case 9:
case 11:
return 30;
default:
return 31;
}
void SettingSetDate::HandleButtonPress() {
const uint16_t yearValue = yearCounter.GetValue();
const uint8_t monthValue = monthCounter.GetValue();
const uint8_t dayValue = dayCounter.GetValue();
NRF_LOG_INFO("Setting date (manually) to %04d-%02d-%02d", yearValue, monthValue, dayValue);
dateTimeController.SetTime(yearValue,
monthValue,
dayValue,
0,
dateTimeController.Hours(),
dateTimeController.Minutes(),
dateTimeController.Seconds(),
nrf_rtc_counter_get(portNRF_RTC_REG));
lv_btn_set_state(btnSetTime, LV_BTN_STATE_DISABLED);
}
void SettingSetDate::CheckDay() {
int maxDay = MaximumDayOfMonth();
if (dayValue > maxDay) {
dayValue = maxDay;
lv_label_set_text_fmt(lblDay, "%d", dayValue);
lv_obj_align(lblDay, lv_scr_act(), LV_ALIGN_CENTER, POS_X_DAY, POS_Y_TEXT);
}
}
void SettingSetDate::UpdateMonthLabel() {
lv_label_set_text_static(
lblMonth,
Pinetime::Controllers::DateTime::MonthShortToStringLow(static_cast<Pinetime::Controllers::DateTime::Months>(monthValue)));
const int maxDay = MaximumDayOfMonth(monthCounter.GetValue(), yearCounter.GetValue());
dayCounter.SetMax(maxDay);
lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
}

View File

@@ -4,6 +4,7 @@
#include <lvgl/lvgl.h>
#include "components/datetime/DateTimeController.h"
#include "displayapp/screens/Screen.h"
#include "displayapp/widgets/Counter.h"
namespace Pinetime {
namespace Applications {
@@ -13,28 +14,17 @@ namespace Pinetime {
SettingSetDate(DisplayApp* app, Pinetime::Controllers::DateTime& dateTimeController);
~SettingSetDate() override;
void HandleButtonPress(lv_obj_t* object, lv_event_t event);
void HandleButtonPress();
void CheckDay();
private:
Controllers::DateTime& dateTimeController;
int dayValue;
int monthValue;
int yearValue;
lv_obj_t* lblDay;
lv_obj_t* lblMonth;
lv_obj_t* lblYear;
lv_obj_t* btnDayPlus;
lv_obj_t* btnDayMinus;
lv_obj_t* btnMonthPlus;
lv_obj_t* btnMonthMinus;
lv_obj_t* btnYearPlus;
lv_obj_t* btnYearMinus;
lv_obj_t* btnSetTime;
int MaximumDayOfMonth() const;
void CheckDay();
void UpdateMonthLabel();
Widgets::Counter dayCounter = Widgets::Counter(1, 31, jetbrains_mono_bold_20);
Widgets::Counter monthCounter = Widgets::Counter(1, 12, jetbrains_mono_bold_20);
Widgets::Counter yearCounter = Widgets::Counter(1970, 9999, jetbrains_mono_bold_20);
};
}
}

View File

@@ -5,21 +5,22 @@
#include "displayapp/DisplayApp.h"
#include "displayapp/screens/Symbols.h"
#include "components/settings/Settings.h"
#include "displayapp/InfiniTimeTheme.h"
using namespace Pinetime::Applications::Screens;
namespace {
constexpr int16_t POS_X_HOURS = -72;
constexpr int16_t POS_X_MINUTES = 0;
constexpr int16_t POS_X_SECONDS = 72;
constexpr int16_t POS_Y_PLUS = -50;
constexpr int16_t POS_Y_TEXT = -6;
constexpr int16_t POS_Y_MINUS = 40;
constexpr int16_t OFS_Y_COLON = -2;
constexpr int16_t POS_Y_TEXT = -7;
void event_handler(lv_obj_t* obj, lv_event_t event) {
void SetTimeEventHandler(lv_obj_t* obj, lv_event_t event) {
auto* screen = static_cast<SettingSetTime*>(obj->user_data);
screen->HandleButtonPress(obj, event);
if (event == LV_EVENT_CLICKED) {
screen->SetTime();
}
}
void ValueChangedHandler(void* userData) {
auto* screen = static_cast<SettingSetTime*>(userData);
screen->UpdateScreen();
}
}
@@ -27,6 +28,7 @@ SettingSetTime::SettingSetTime(Pinetime::Applications::DisplayApp* app,
Pinetime::Controllers::DateTime& dateTimeController,
Pinetime::Controllers::Settings& settingsController)
: Screen(app), dateTimeController {dateTimeController}, settingsController {settingsController} {
lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr);
lv_label_set_text_static(title, "Set current time");
lv_label_set_align(title, LV_LABEL_ALIGN_CENTER);
@@ -34,160 +36,72 @@ SettingSetTime::SettingSetTime(Pinetime::Applications::DisplayApp* app,
lv_obj_t* icon = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE);
lv_label_set_text_static(icon, Symbols::clock);
lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER);
lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0);
hoursValue = static_cast<int>(dateTimeController.Hours());
lblHours = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(lblHours, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
lv_label_set_text_fmt(lblHours, "%02d", hoursValue);
lv_label_set_align(lblHours, LV_LABEL_ALIGN_CENTER);
lv_obj_align(lblHours, lv_scr_act(), LV_ALIGN_CENTER, POS_X_HOURS, POS_Y_TEXT);
lv_obj_set_auto_realign(lblHours, true);
lv_obj_t* staticLabel = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(staticLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
lv_label_set_text_static(staticLabel, "00:00:00");
lv_obj_align(staticLabel, lv_scr_act(), LV_ALIGN_CENTER, 0, POS_Y_TEXT);
lv_obj_t* lblColon1 = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(lblColon1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
lv_label_set_text_static(lblColon1, ":");
lv_label_set_align(lblColon1, LV_LABEL_ALIGN_CENTER);
lv_obj_align(lblColon1, lv_scr_act(), LV_ALIGN_CENTER, (POS_X_HOURS + POS_X_MINUTES) / 2, POS_Y_TEXT + OFS_Y_COLON);
hourCounter.Create();
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
hourCounter.EnableTwelveHourMode();
}
hourCounter.SetValue(dateTimeController.Hours());
lv_obj_align(hourCounter.GetObject(), nullptr, LV_ALIGN_CENTER, -75, POS_Y_TEXT);
hourCounter.SetValueChangedEventCallback(this, ValueChangedHandler);
minutesValue = static_cast<int>(dateTimeController.Minutes());
lblMinutes = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(lblMinutes, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
lv_label_set_text_fmt(lblMinutes, "%02d", minutesValue);
lv_label_set_align(lblMinutes, LV_LABEL_ALIGN_CENTER);
lv_obj_align(lblMinutes, lv_scr_act(), LV_ALIGN_CENTER, POS_X_MINUTES, POS_Y_TEXT);
lv_obj_set_auto_realign(lblMinutes, true);
lv_obj_t* lblColon2 = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(lblColon2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
lv_label_set_text_static(lblColon2, ":");
lv_label_set_align(lblColon2, LV_LABEL_ALIGN_CENTER);
lv_obj_align(lblColon2, lv_scr_act(), LV_ALIGN_CENTER, (POS_X_MINUTES + POS_X_SECONDS) / 2, POS_Y_TEXT + OFS_Y_COLON);
lv_obj_t* lblSeconds = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(lblSeconds, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42);
lv_label_set_text_static(lblSeconds, "00");
lv_label_set_align(lblSeconds, LV_LABEL_ALIGN_CENTER);
lv_obj_align(lblSeconds, lv_scr_act(), LV_ALIGN_CENTER, POS_X_SECONDS, POS_Y_TEXT);
minuteCounter.Create();
minuteCounter.SetValue(dateTimeController.Minutes());
lv_obj_align(minuteCounter.GetObject(), nullptr, LV_ALIGN_CENTER, 0, POS_Y_TEXT);
minuteCounter.SetValueChangedEventCallback(this, ValueChangedHandler);
lblampm = lv_label_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_text_font(lblampm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20);
lv_label_set_text_static(lblampm, " ");
lv_label_set_align(lblampm, LV_LABEL_ALIGN_CENTER);
lv_obj_align(lblampm, lv_scr_act(), LV_ALIGN_CENTER, POS_X_SECONDS, POS_Y_PLUS);
btnHoursPlus = lv_btn_create(lv_scr_act(), nullptr);
btnHoursPlus->user_data = this;
lv_obj_set_size(btnHoursPlus, 50, 40);
lv_obj_align(btnHoursPlus, lv_scr_act(), LV_ALIGN_CENTER, -72, -50);
lv_obj_set_style_local_value_str(btnHoursPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "+");
lv_obj_set_event_cb(btnHoursPlus, event_handler);
btnHoursMinus = lv_btn_create(lv_scr_act(), nullptr);
btnHoursMinus->user_data = this;
lv_obj_set_size(btnHoursMinus, 50, 40);
lv_obj_align(btnHoursMinus, lv_scr_act(), LV_ALIGN_CENTER, -72, 40);
lv_obj_set_style_local_value_str(btnHoursMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "-");
lv_obj_set_event_cb(btnHoursMinus, event_handler);
btnMinutesPlus = lv_btn_create(lv_scr_act(), nullptr);
btnMinutesPlus->user_data = this;
lv_obj_set_size(btnMinutesPlus, 50, 40);
lv_obj_align(btnMinutesPlus, lv_scr_act(), LV_ALIGN_CENTER, 0, -50);
lv_obj_set_style_local_value_str(btnMinutesPlus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "+");
lv_obj_set_event_cb(btnMinutesPlus, event_handler);
btnMinutesMinus = lv_btn_create(lv_scr_act(), nullptr);
btnMinutesMinus->user_data = this;
lv_obj_set_size(btnMinutesMinus, 50, 40);
lv_obj_align(btnMinutesMinus, lv_scr_act(), LV_ALIGN_CENTER, 0, 40);
lv_obj_set_style_local_value_str(btnMinutesMinus, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "-");
lv_obj_set_event_cb(btnMinutesMinus, event_handler);
lv_obj_align(lblampm, lv_scr_act(), LV_ALIGN_CENTER, 75, -50);
btnSetTime = lv_btn_create(lv_scr_act(), nullptr);
btnSetTime->user_data = this;
lv_obj_set_size(btnSetTime, 120, 48);
lv_obj_set_size(btnSetTime, 120, 50);
lv_obj_align(btnSetTime, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0);
lv_obj_set_style_local_value_str(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, "Set");
lv_obj_set_event_cb(btnSetTime, event_handler);
lv_obj_set_style_local_bg_color(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt);
lv_obj_set_style_local_value_color(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DISABLED, LV_COLOR_GRAY);
lv_obj_set_event_cb(btnSetTime, SetTimeEventHandler);
SetHourLabels();
UpdateScreen();
lv_obj_set_state(btnSetTime, LV_STATE_DISABLED);
}
SettingSetTime::~SettingSetTime() {
lv_obj_clean(lv_scr_act());
}
void SettingSetTime::SetHourLabels() {
void SettingSetTime::UpdateScreen() {
if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) {
switch (hoursValue) {
case 0:
lv_label_set_text_static(lblHours, "12");
lv_label_set_text_static(lblampm, "AM");
break;
case 1 ... 11:
lv_label_set_text_fmt(lblHours, "%02d", hoursValue);
lv_label_set_text_static(lblampm, "AM");
break;
case 12:
lv_label_set_text_static(lblHours, "12");
lv_label_set_text_static(lblampm, "PM");
break;
case 13 ... 23:
lv_label_set_text_fmt(lblHours, "%02d", hoursValue - 12);
lv_label_set_text_static(lblampm, "PM");
break;
if (hourCounter.GetValue() >= 12) {
lv_label_set_text_static(lblampm, "PM");
} else {
lv_label_set_text_static(lblampm, "AM");
}
} else {
lv_label_set_text_fmt(lblHours, "%02d", hoursValue);
}
lv_obj_set_state(btnSetTime, LV_STATE_DEFAULT);
}
void SettingSetTime::HandleButtonPress(lv_obj_t* object, lv_event_t event) {
if (event != LV_EVENT_CLICKED)
return;
if (object == btnHoursPlus) {
hoursValue++;
if (hoursValue > 23) {
hoursValue = 0;
}
SetHourLabels();
lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
} else if (object == btnHoursMinus) {
hoursValue--;
if (hoursValue < 0) {
hoursValue = 23;
}
SetHourLabels();
lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
} else if (object == btnMinutesPlus) {
minutesValue++;
if (minutesValue > 59) {
minutesValue = 0;
}
lv_label_set_text_fmt(lblMinutes, "%02d", minutesValue);
lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
} else if (object == btnMinutesMinus) {
minutesValue--;
if (minutesValue < 0) {
minutesValue = 59;
}
lv_label_set_text_fmt(lblMinutes, "%02d", minutesValue);
lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED);
} else if (object == btnSetTime) {
NRF_LOG_INFO("Setting time (manually) to %02d:%02d:00", hoursValue, minutesValue);
dateTimeController.SetTime(dateTimeController.Year(),
static_cast<uint8_t>(dateTimeController.Month()),
dateTimeController.Day(),
static_cast<uint8_t>(dateTimeController.DayOfWeek()),
static_cast<uint8_t>(hoursValue),
static_cast<uint8_t>(minutesValue),
0,
nrf_rtc_counter_get(portNRF_RTC_REG));
lv_btn_set_state(btnSetTime, LV_BTN_STATE_DISABLED);
}
void SettingSetTime::SetTime() {
const int hoursValue = hourCounter.GetValue();
const int minutesValue = minuteCounter.GetValue();
NRF_LOG_INFO("Setting time (manually) to %02d:%02d:00", hoursValue, minutesValue);
dateTimeController.SetTime(dateTimeController.Year(),
static_cast<uint8_t>(dateTimeController.Month()),
dateTimeController.Day(),
static_cast<uint8_t>(dateTimeController.DayOfWeek()),
static_cast<uint8_t>(hoursValue),
static_cast<uint8_t>(minutesValue),
0,
nrf_rtc_counter_get(portNRF_RTC_REG));
lv_obj_set_state(btnSetTime, LV_STATE_DISABLED);
}

View File

@@ -4,6 +4,7 @@
#include <lvgl/lvgl.h>
#include "components/datetime/DateTimeController.h"
#include "components/settings/Settings.h"
#include "displayapp/widgets/Counter.h"
#include "displayapp/screens/Screen.h"
namespace Pinetime {
@@ -16,24 +17,17 @@ namespace Pinetime {
Pinetime::Controllers::Settings& settingsController);
~SettingSetTime() override;
void HandleButtonPress(lv_obj_t* object, lv_event_t event);
void SetTime();
void UpdateScreen();
private:
Controllers::DateTime& dateTimeController;
Controllers::Settings& settingsController;
void SetHourLabels();
int hoursValue;
int minutesValue;
lv_obj_t* lblHours;
lv_obj_t* lblMinutes;
lv_obj_t* lblampm;
lv_obj_t* btnHoursPlus;
lv_obj_t* btnHoursMinus;
lv_obj_t* btnMinutesPlus;
lv_obj_t* btnMinutesMinus;
lv_obj_t* btnSetTime;
Widgets::Counter hourCounter = Widgets::Counter(0, 23, jetbrains_mono_42);
Widgets::Counter minuteCounter = Widgets::Counter(0, 59, jetbrains_mono_42);
};
}
}

View File

@@ -3,6 +3,7 @@
#include "displayapp/DisplayApp.h"
#include "displayapp/screens/Screen.h"
#include "displayapp/screens/Symbols.h"
#include "displayapp/InfiniTimeTheme.h"
using namespace Pinetime::Applications::Screens;
@@ -123,8 +124,7 @@ void SettingShakeThreshold::UpdateSelected(lv_obj_t* object, lv_event_t event) {
vCalTime = xTaskGetTickCount();
lv_label_set_text_static(calLabel, "Ready!");
lv_obj_set_click(positionArc, false);
lv_obj_set_style_local_bg_color(calButton, LV_BTN_PART_MAIN, LV_STATE_CHECKED, LV_COLOR_MAKE(0x0, 0xb0, 0x0));
lv_obj_set_style_local_bg_color(calButton, LV_BTN_PART_MAIN, LV_STATE_CHECKED, LV_COLOR_MAKE(0x0, 0xb0, 0x0));
lv_obj_set_style_local_bg_color(calButton, LV_BTN_PART_MAIN, LV_STATE_CHECKED, Colors::highlight);
} else if (lv_btn_get_state(calButton) == LV_BTN_STATE_RELEASED) {
calibrating = 0;
lv_obj_set_click(positionArc, true);

View File

@@ -17,7 +17,6 @@ SettingSteps::SettingSteps(Pinetime::Applications::DisplayApp* app, Pinetime::Co
lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr);
// lv_obj_set_style_local_bg_color(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x111111));
lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10);
lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5);

View File

@@ -20,7 +20,7 @@ namespace Pinetime {
void UpdateSelected(lv_obj_t* object, lv_event_t event);
private:
static constexpr std::array<const char*, 2> options = {" 12-hour", " 24-hour"};
static constexpr std::array<const char*, 2> options = {"12-hour", "24-hour"};
Controllers::Settings& settingsController;
lv_obj_t* cbOption[options.size()];
};

View File

@@ -42,7 +42,7 @@ SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime::
optionsTotal = 0;
cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr);
lv_checkbox_set_text_static(cbOption[optionsTotal], " Single Tap");
lv_checkbox_set_text_static(cbOption[optionsTotal], "Single Tap");
cbOption[optionsTotal]->user_data = this;
lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::SingleTap)) {
@@ -50,7 +50,7 @@ SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime::
}
optionsTotal++;
cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr);
lv_checkbox_set_text_static(cbOption[optionsTotal], " Double Tap");
lv_checkbox_set_text_static(cbOption[optionsTotal], "Double Tap");
cbOption[optionsTotal]->user_data = this;
lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) {
@@ -58,7 +58,7 @@ SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime::
}
optionsTotal++;
cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr);
lv_checkbox_set_text_static(cbOption[optionsTotal], " Raise Wrist");
lv_checkbox_set_text_static(cbOption[optionsTotal], "Raise Wrist");
cbOption[optionsTotal]->user_data = this;
lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist)) {
@@ -66,7 +66,7 @@ SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime::
}
optionsTotal++;
cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr);
lv_checkbox_set_text_static(cbOption[optionsTotal], " Shake Wake");
lv_checkbox_set_text_static(cbOption[optionsTotal], "Shake Wake");
cbOption[optionsTotal]->user_data = this;
lv_obj_set_event_cb(cbOption[optionsTotal], event_handler);
if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::Shake)) {

View File

@@ -38,7 +38,7 @@ bool SettingWatchFace::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
}
std::unique_ptr<Screen> SettingWatchFace::CreateScreen1() {
std::array<const char*, 4> watchfaces {" Digital face", " Analog face", " PineTimeStyle", " Terminal"};
std::array<const char*, 4> watchfaces {"Digital face", "Analog face", "PineTimeStyle", "Terminal"};
return std::make_unique<Screens::CheckboxList>(0, 2, app, settingsController, title,
symbol, &Controllers::Settings::SetClockFace,
&Controllers::Settings::GetClockFace,
@@ -46,7 +46,7 @@ std::unique_ptr<Screen> SettingWatchFace::CreateScreen1() {
}
std::unique_ptr<Screen> SettingWatchFace::CreateScreen2() {
std::array<const char*, 4> watchfaces {" Infineat face", "", "", ""};
std::array<const char*, 4> watchfaces {"Infineat face", "", "", ""};
return std::make_unique<Screens::CheckboxList>(1, 2, app, settingsController, title,
symbol, &Controllers::Settings::SetClockFace,
&Controllers::Settings::GetClockFace,

View File

@@ -1,33 +1,27 @@
#include "displayapp/screens/settings/Settings.h"
#include <lvgl/lvgl.h>
#include <array>
#include "displayapp/screens/List.h"
#include <functional>
#include "displayapp/Apps.h"
#include "displayapp/DisplayApp.h"
#include "displayapp/screens/Symbols.h"
using namespace Pinetime::Applications::Screens;
constexpr std::array<List::Applications, Settings::entries.size()> Settings::entries;
auto Settings::CreateScreenList() const {
std::array<std::function<std::unique_ptr<Screen>()>, nScreens> screens;
for (size_t i = 0; i < screens.size(); i++) {
screens[i] = [this, i]() -> std::unique_ptr<Screen> {
return CreateScreen(i);
};
}
return screens;
}
Settings::Settings(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController)
: Screen(app),
settingsController {settingsController},
screens {app,
settingsController.GetSettingsMenu(),
{
[this]() -> std::unique_ptr<Screen> {
return CreateScreen1();
},
[this]() -> std::unique_ptr<Screen> {
return CreateScreen2();
},
[this]() -> std::unique_ptr<Screen> {
return CreateScreen3();
},
[this]() -> std::unique_ptr<Screen> {
return CreateScreen4();
},
},
Screens::ScreenListModes::UpDown} {
screens {app, settingsController.GetSettingsMenu(), CreateScreenList(), Screens::ScreenListModes::UpDown} {
}
Settings::~Settings() {
@@ -38,48 +32,11 @@ bool Settings::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
return screens.OnTouchEvent(event);
}
std::unique_ptr<Screen> Settings::CreateScreen1() {
std::array<Screens::List::Applications, 4> applications {{
{Symbols::sun, "Display", Apps::SettingDisplay},
{Symbols::eye, "Wake Up", Apps::SettingWakeUp},
{Symbols::clock, "Time format", Apps::SettingTimeFormat},
{Symbols::home, "Watch face", Apps::SettingWatchFace},
}};
std::unique_ptr<Screen> Settings::CreateScreen(unsigned int screenNum) const {
std::array<List::Applications, entriesPerScreen> screens;
for (int i = 0; i < entriesPerScreen; i++) {
screens[i] = entries[screenNum * entriesPerScreen + i];
}
return std::make_unique<Screens::List>(0, 4, app, settingsController, applications);
}
std::unique_ptr<Screen> Settings::CreateScreen2() {
std::array<Screens::List::Applications, 4> applications {{
{Symbols::shoe, "Steps", Apps::SettingSteps},
{Symbols::clock, "Set date", Apps::SettingSetDate},
{Symbols::clock, "Set time", Apps::SettingSetTime},
{Symbols::batteryHalf, "Battery", Apps::BatteryInfo},
}};
return std::make_unique<Screens::List>(1, 4, app, settingsController, applications);
}
std::unique_ptr<Screen> Settings::CreateScreen3() {
std::array<Screens::List::Applications, 4> applications {{
{Symbols::clock, "Chimes", Apps::SettingChimes},
{Symbols::tachometer, "Shake Calib.", Apps::SettingShakeThreshold},
{Symbols::check, "Firmware", Apps::FirmwareValidation},
{Symbols::bluetooth, "Bluetooth", Apps::SettingBluetooth},
}};
return std::make_unique<Screens::List>(2, 4, app, settingsController, applications);
}
std::unique_ptr<Screen> Settings::CreateScreen4() {
std::array<Screens::List::Applications, 4> applications {{
{Symbols::list, "About", Apps::SysInfo},
{Symbols::none, "None", Apps::None},
{Symbols::none, "None", Apps::None},
{Symbols::none, "None", Apps::None},
}};
return std::make_unique<Screens::List>(3, 4, app, settingsController, applications);
return std::make_unique<Screens::List>(screenNum, nScreens, app, settingsController, screens);
}

View File

@@ -1,8 +1,11 @@
#pragma once
#include <cstdint>
#include <array>
#include <memory>
#include "displayapp/screens/Screen.h"
#include "displayapp/screens/ScreenList.h"
#include "displayapp/screens/Symbols.h"
#include "displayapp/screens/List.h"
namespace Pinetime {
@@ -17,14 +20,38 @@ namespace Pinetime {
bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override;
private:
auto CreateScreenList() const;
std::unique_ptr<Screen> CreateScreen(unsigned int screenNum) const;
Controllers::Settings& settingsController;
ScreenList<4> screens;
static constexpr int entriesPerScreen = 4;
std::unique_ptr<Screen> CreateScreen1();
std::unique_ptr<Screen> CreateScreen2();
std::unique_ptr<Screen> CreateScreen3();
std::unique_ptr<Screen> CreateScreen4();
// Increment this when more space is needed
static constexpr int nScreens = 4;
static constexpr std::array<List::Applications, entriesPerScreen * nScreens> entries {{
{Symbols::sun, "Display", Apps::SettingDisplay},
{Symbols::eye, "Wake Up", Apps::SettingWakeUp},
{Symbols::clock, "Time format", Apps::SettingTimeFormat},
{Symbols::home, "Watch face", Apps::SettingWatchFace},
{Symbols::shoe, "Steps", Apps::SettingSteps},
{Symbols::clock, "Set date", Apps::SettingSetDate},
{Symbols::clock, "Set time", Apps::SettingSetTime},
{Symbols::batteryHalf, "Battery", Apps::BatteryInfo},
{Symbols::clock, "Chimes", Apps::SettingChimes},
{Symbols::tachometer, "Shake Calib.", Apps::SettingShakeThreshold},
{Symbols::check, "Firmware", Apps::FirmwareValidation},
{Symbols::bluetooth, "Bluetooth", Apps::SettingBluetooth},
{Symbols::list, "About", Apps::SysInfo},
{Symbols::none, "None", Apps::None},
{Symbols::none, "None", Apps::None},
{Symbols::none, "None", Apps::None},
}};
ScreenList<nScreens> screens;
};
}
}

View File

@@ -1,4 +1,6 @@
#include "displayapp/widgets/Counter.h"
#include "components/datetime/DateTimeController.h"
#include "displayapp/InfiniTimeTheme.h"
using namespace Pinetime::Applications::Widgets;
@@ -6,35 +8,51 @@ namespace {
void upBtnEventHandler(lv_obj_t* obj, lv_event_t event) {
auto* widget = static_cast<Counter*>(obj->user_data);
if (event == LV_EVENT_SHORT_CLICKED || event == LV_EVENT_LONG_PRESSED_REPEAT) {
widget->Increment();
widget->UpBtnPressed();
}
}
void downBtnEventHandler(lv_obj_t* obj, lv_event_t event) {
auto* widget = static_cast<Counter*>(obj->user_data);
if (event == LV_EVENT_SHORT_CLICKED || event == LV_EVENT_LONG_PRESSED_REPEAT) {
widget->Decrement();
widget->DownBtnPressed();
}
}
constexpr int digitCount(int number) {
int digitCount = 0;
while (number > 0) {
digitCount++;
number /= 10;
}
return digitCount;
}
}
Counter::Counter(int min, int max) : min {min}, max {max} {
Counter::Counter(int min, int max, lv_font_t& font) : min {min}, max {max}, value {min}, font {font}, leadingZeroCount {digitCount(max)} {
}
void Counter::Increment() {
void Counter::UpBtnPressed() {
value++;
if (value > max) {
value = min;
}
UpdateLabel();
if (ValueChangedHandler != nullptr) {
ValueChangedHandler(userData);
}
};
void Counter::Decrement() {
void Counter::DownBtnPressed() {
value--;
if (value < min) {
value = max;
}
UpdateLabel();
if (ValueChangedHandler != nullptr) {
ValueChangedHandler(userData);
}
};
void Counter::SetValue(int newValue) {
@@ -58,23 +76,64 @@ void Counter::ShowControls() {
}
void Counter::UpdateLabel() {
lv_label_set_text_fmt(number, "%.2i", value);
if (twelveHourMode) {
if (value == 0) {
lv_label_set_text_static(number, "12");
} else if (value <= 12) {
lv_label_set_text_fmt(number, "%.*i", leadingZeroCount, value);
} else {
lv_label_set_text_fmt(number, "%.*i", leadingZeroCount, value - 12);
}
} else if (monthMode) {
lv_label_set_text(number, Controllers::DateTime::MonthShortToStringLow(static_cast<Controllers::DateTime::Months>(value)));
} else {
lv_label_set_text_fmt(number, "%.*i", leadingZeroCount, value);
}
}
// Value is kept between 0 and 23, but the displayed value is converted to 12-hour.
// Make sure to set the max and min values to 0 and 23. Otherwise behaviour is undefined
void Counter::EnableTwelveHourMode() {
twelveHourMode = true;
}
// Value is kept between 1 and 12, but the displayed value is the corresponding month
// Make sure to set the max and min values to 1 and 12. Otherwise behaviour is undefined
void Counter::EnableMonthMode() {
monthMode = true;
}
// Counter cannot be resized after creation,
// so the newMax value must have the same number of digits as the old one
void Counter::SetMax(int newMax) {
max = newMax;
if (value > max) {
value = max;
UpdateLabel();
}
}
void Counter::SetValueChangedEventCallback(void* userData, void (*handler)(void* userData)) {
this->userData = userData;
this->ValueChangedHandler = handler;
}
void Counter::Create() {
constexpr lv_color_t bgColor = LV_COLOR_MAKE(0x38, 0x38, 0x38);
counterContainer = lv_obj_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_bg_color(counterContainer, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, bgColor);
lv_obj_set_style_local_bg_color(counterContainer, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt);
number = lv_label_create(counterContainer, nullptr);
lv_obj_set_style_local_text_font(number, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76);
lv_obj_set_style_local_text_font(number, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &font);
lv_obj_align(number, nullptr, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_auto_realign(number, true);
lv_label_set_text_static(number, "00");
if (monthMode) {
lv_label_set_text_static(number, "Jan");
} else {
lv_label_set_text_fmt(number, "%d", max);
}
static constexpr uint8_t padding = 5;
const uint8_t width = lv_obj_get_width(number) + padding * 2;
const uint8_t width = std::max(lv_obj_get_width(number) + padding * 2, 58);
static constexpr uint8_t btnHeight = 50;
const uint8_t containerHeight = btnHeight * 2 + lv_obj_get_height(number) + padding * 2;
@@ -83,7 +142,7 @@ void Counter::Create() {
UpdateLabel();
upBtn = lv_btn_create(counterContainer, nullptr);
lv_obj_set_style_local_bg_color(upBtn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, bgColor);
lv_obj_set_style_local_bg_color(upBtn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt);
lv_obj_set_size(upBtn, width, btnHeight);
lv_obj_align(upBtn, nullptr, LV_ALIGN_IN_TOP_MID, 0, 0);
upBtn->user_data = this;
@@ -95,7 +154,7 @@ void Counter::Create() {
lv_obj_align(upLabel, nullptr, LV_ALIGN_CENTER, 0, 0);
downBtn = lv_btn_create(counterContainer, nullptr);
lv_obj_set_style_local_bg_color(downBtn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, bgColor);
lv_obj_set_style_local_bg_color(downBtn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt);
lv_obj_set_size(downBtn, width, btnHeight);
lv_obj_align(downBtn, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
downBtn->user_data = this;

View File

@@ -6,14 +6,18 @@ namespace Pinetime {
namespace Widgets {
class Counter {
public:
Counter(int min, int max);
Counter(int min, int max, lv_font_t& font);
void Create();
void Increment();
void Decrement();
void UpBtnPressed();
void DownBtnPressed();
void SetValue(int newValue);
void HideControls();
void ShowControls();
void EnableTwelveHourMode();
void EnableMonthMode();
void SetMax(int newMax);
void SetValueChangedEventCallback(void* userData, void (*handler)(void* userData));
int GetValue() const {
return value;
@@ -25,6 +29,7 @@ namespace Pinetime {
private:
void UpdateLabel();
void (*ValueChangedHandler)(void* userData) = nullptr;
lv_obj_t* counterContainer;
lv_obj_t* upBtn;
@@ -33,9 +38,15 @@ namespace Pinetime {
lv_obj_t* upperLine;
lv_obj_t* lowerLine;
lv_point_t linePoints[2];
int value = 0;
int min;
int max;
int value;
const int leadingZeroCount;
bool twelveHourMode = false;
bool monthMode = false;
lv_font_t& font;
void* userData = nullptr;
};
}
}

View File

@@ -0,0 +1,32 @@
#include "displayapp/widgets/PageIndicator.h"
#include "displayapp/InfiniTimeTheme.h"
using namespace Pinetime::Applications::Widgets;
PageIndicator::PageIndicator(uint8_t nCurrentScreen, uint8_t nScreens) : nCurrentScreen {nCurrentScreen}, nScreens {nScreens} {
}
void PageIndicator::Create() {
pageIndicatorBasePoints[0].x = LV_HOR_RES - 1;
pageIndicatorBasePoints[0].y = 0;
pageIndicatorBasePoints[1].x = LV_HOR_RES - 1;
pageIndicatorBasePoints[1].y = LV_VER_RES;
pageIndicatorBase = lv_line_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_line_width(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3);
lv_obj_set_style_local_line_color(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark);
lv_line_set_points(pageIndicatorBase, pageIndicatorBasePoints, 2);
const int16_t indicatorSize = LV_VER_RES / nScreens;
const int16_t indicatorPos = indicatorSize * nCurrentScreen;
pageIndicatorPoints[0].x = LV_HOR_RES - 1;
pageIndicatorPoints[0].y = indicatorPos;
pageIndicatorPoints[1].x = LV_HOR_RES - 1;
pageIndicatorPoints[1].y = indicatorPos + indicatorSize;
pageIndicator = lv_line_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_line_width(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3);
lv_obj_set_style_local_line_color(pageIndicator, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray);
lv_line_set_points(pageIndicator, pageIndicatorPoints, 2);
}

View File

@@ -0,0 +1,23 @@
#pragma once
#include <lvgl/lvgl.h>
namespace Pinetime {
namespace Applications {
namespace Widgets {
class PageIndicator {
public:
PageIndicator(uint8_t nCurrentScreen, uint8_t nScreens);
void Create();
private:
uint8_t nCurrentScreen;
uint8_t nScreens;
lv_point_t pageIndicatorBasePoints[2];
lv_point_t pageIndicatorPoints[2];
lv_obj_t* pageIndicatorBase;
lv_obj_t* pageIndicator;
};
}
}
}

View File

@@ -0,0 +1,49 @@
#include "displayapp/widgets/StatusIcons.h"
#include "displayapp/screens/Symbols.h"
using namespace Pinetime::Applications::Widgets;
StatusIcons::StatusIcons(Controllers::Battery& batteryController, Controllers::Ble& bleController)
: batteryController {batteryController}, bleController {bleController} {
}
void StatusIcons::Create() {
container = lv_cont_create(lv_scr_act(), nullptr);
lv_cont_set_layout(container, LV_LAYOUT_ROW_TOP);
lv_cont_set_fit(container, LV_FIT_TIGHT);
lv_obj_set_style_local_pad_inner(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5);
lv_obj_set_style_local_bg_opa(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP);
bleIcon = lv_label_create(container, nullptr);
lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x0082FC));
lv_label_set_text_static(bleIcon, Screens::Symbols::bluetooth);
batteryPlug = lv_label_create(container, nullptr);
lv_obj_set_style_local_text_color(batteryPlug, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED);
lv_label_set_text_static(batteryPlug, Screens::Symbols::plug);
batteryIcon.Create(container);
lv_obj_align(container, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0);
}
void StatusIcons::Update() {
powerPresent = batteryController.IsPowerPresent();
if (powerPresent.IsUpdated()) {
lv_obj_set_hidden(batteryPlug, !powerPresent.Get());
}
batteryPercentRemaining = batteryController.PercentRemaining();
if (batteryPercentRemaining.IsUpdated()) {
auto batteryPercent = batteryPercentRemaining.Get();
batteryIcon.SetBatteryPercentage(batteryPercent);
}
bleState = bleController.IsConnected();
bleRadioEnabled = bleController.IsRadioEnabled();
if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) {
lv_obj_set_hidden(bleIcon, !bleState.Get());
}
lv_obj_realign(container);
}

View File

@@ -0,0 +1,39 @@
#pragma once
#include <lvgl/lvgl.h>
#include "displayapp/screens/Screen.h"
#include "components/battery/BatteryController.h"
#include "components/ble/BleController.h"
#include "displayapp/screens/BatteryIcon.h"
namespace Pinetime {
namespace Applications {
namespace Widgets {
class StatusIcons {
public:
StatusIcons(Controllers::Battery& batteryController, Controllers::Ble& bleController);
void Align();
void Create();
lv_obj_t* GetObject() {
return container;
}
void Update();
private:
Screens::BatteryIcon batteryIcon;
Pinetime::Controllers::Battery& batteryController;
Controllers::Ble& bleController;
Screens::DirtyValue<uint8_t> batteryPercentRemaining {};
Screens::DirtyValue<bool> powerPresent {};
Screens::DirtyValue<bool> bleState {};
Screens::DirtyValue<bool> bleRadioEnabled {};
lv_obj_t* bleIcon;
lv_obj_t* batteryPlug;
lv_obj_t* container;
};
}
}
}

View File

@@ -4,8 +4,8 @@
namespace Pinetime {
namespace PinMap {
#ifdef WATCH_P8
// COLMI P8
#if defined(DRIVER_PINMAP_P8)
// COLMI P8 and variants
static constexpr uint8_t Charging = 19;
static constexpr uint8_t Cst816sReset = 13;
static constexpr uint8_t Button = 17;

View File

@@ -21,7 +21,10 @@ void St7789::Init() {
MemoryDataAccessControl();
ColumnAddressSet();
RowAddressSet();
// P8B Mirrored version does not need display inversion.
#ifndef DRIVER_DISPLAY_MIRROR
DisplayInversionOn();
#endif
NormalModeOn();
SetVdv();
DisplayOn();
@@ -62,7 +65,18 @@ void St7789::ColMod() {
void St7789::MemoryDataAccessControl() {
WriteCommand(static_cast<uint8_t>(Commands::MemoryDataAccessControl));
#ifdef DRIVER_DISPLAY_MIRROR
// [7] = MY = Page Address Order, 0 = Top to bottom, 1 = Bottom to top
// [6] = MX = Column Address Order, 0 = Left to right, 1 = Right to left
// [5] = MV = Page/Column Order, 0 = Normal mode, 1 = Reverse mode
// [4] = ML = Line Address Order, 0 = LCD refresh from top to bottom, 1 = Bottom to top
// [3] = RGB = RGB/BGR Order, 0 = RGB, 1 = BGR
// [2] = MH = Display Data Latch Order, 0 = LCD refresh from left to right, 1 = Right to left
// [0 .. 1] = Unused
WriteData(0b01000000);
#else
WriteData(0x00);
#endif
}
void St7789::ColumnAddressSet() {

View File

@@ -161,7 +161,7 @@ typedef void* lv_anim_user_data_t;
#define LV_USE_OUTLINE 0
/*1: enable pattern drawing on rectangles*/
#define LV_USE_PATTERN 0
#define LV_USE_PATTERN 1
/*1: enable value string drawing on rectangles*/
#define LV_USE_VALUE_STR 1
@@ -678,7 +678,7 @@ typedef void* lv_obj_user_data_t;
#endif
/*Mask (dependencies: -)*/
#define LV_USE_OBJMASK 0
#define LV_USE_OBJMASK 1
/*Message box (dependencies: lv_rect, lv_btnm, lv_label)*/
#define LV_USE_MSGBOX 0

View File

@@ -300,10 +300,29 @@ void nimble_port_ll_task_func(void* args) {
}
}
void calibrate_lf_clock_rc(nrf_drv_clock_evt_type_t event) {
// 16 * 0.25s = 4s calibration cycle
// Not recursive, call is deferred via internal calibration timer
nrf_drv_clock_calibration_start(16, calibrate_lf_clock_rc);
}
int main(void) {
logger.Init();
nrf_drv_clock_init();
nrf_drv_clock_lfclk_request(NULL);
// When loading the firmware via the Wasp-OS reloader-factory, which uses the used internal LF RC oscillator,
// the LF clock has to be explicitly restarted because InfiniTime uses the external crystal oscillator if available.
// If the clock is not restarted, the Bluetooth timers fail to initialize.
nrfx_clock_lfclk_start();
while (!nrf_clock_lf_is_running()) {
}
// The RC source for the LF clock has to be calibrated
#if (CLOCK_CONFIG_LF_SRC == NRF_CLOCK_LFCLK_RC)
nrf_drv_clock_calibration_start(0, calibrate_lf_clock_rc);
#endif
// Unblock i2c?
nrf_gpio_cfg(Pinetime::PinMap::TwiScl,

View File

@@ -0,0 +1,29 @@
find_program(LV_FONT_CONV "lv_font_conv" NO_CACHE REQUIRED
HINTS "${CMAKE_SOURCE_DIR}/node_modules/.bin")
message(STATUS "Using ${LV_FONT_CONV} to generate font files")
find_program(LV_IMG_CONV "lv_img_conv" NO_CACHE REQUIRED
HINTS "${CMAKE_SOURCE_DIR}/node_modules/.bin")
message(STATUS "Using ${LV_IMG_CONV} to generate font files")
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12)
# FindPython3 module introduces with CMake 3.12
# https://cmake.org/cmake/help/latest/module/FindPython3.html
find_package(Python3 REQUIRED)
else()
set(Python3_EXECUTABLE "python")
endif()
# generate fonts
add_custom_target(GenerateResources
COMMAND "${Python3_EXECUTABLE}" ${CMAKE_CURRENT_SOURCE_DIR}/generate-fonts.py --lv-font-conv "${LV_FONT_CONV}" ${CMAKE_CURRENT_SOURCE_DIR}/fonts.json
COMMAND "${Python3_EXECUTABLE}" ${CMAKE_CURRENT_SOURCE_DIR}/generate-img.py --lv-img-conv "${LV_IMG_CONV}" ${CMAKE_CURRENT_SOURCE_DIR}/images.json
COMMAND "${Python3_EXECUTABLE}" ${CMAKE_CURRENT_SOURCE_DIR}/generate-package.py --config ${CMAKE_CURRENT_SOURCE_DIR}/fonts.json --config ${CMAKE_CURRENT_SOURCE_DIR}/images.json --obsolete obsolete_files.json --output infinitime-resources-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.zip
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/fonts.json
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/images.json
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generate fonts and images for resource package"
)

62
src/resources/fonts.json Normal file
View File

@@ -0,0 +1,62 @@
{
"teko" : {
"sources": [
{
"file": "fonts/Teko-Light.ttf",
"symbols": "0123456789:/amp"
}
],
"bpp": 1,
"size": 28,
"format": "bin",
"target_path": "/fonts/"
},
"bebas" : {
"sources": [
{
"file": "fonts/BebasNeue-Regular.ttf",
"symbols": "0123456789:"
}
],
"bpp": 1,
"size": 120,
"format": "bin",
"target_path": "/fonts/"
},
"lv_font_dots_40": {
"sources": [
{
"file": "fonts/repetitionscrolling.ttf",
"symbols": "0123456789-MONTUEWEDTHUFRISATSUN WK"
}
],
"bpp": 1,
"size": 40,
"format": "bin",
"target_path": "/fonts/"
},
"7segments_40" : {
"sources": [
{
"file": "fonts/7segment.woff",
"symbols": "0123456789: -"
}
],
"bpp": 1,
"size": 40,
"format": "bin",
"target_path": "/fonts/"
},
"7segments_115" : {
"sources": [
{
"file": "fonts/7segment.woff",
"symbols": "0123456789: -"
}
],
"bpp": 1,
"size": 115,
"format": "bin",
"target_path": "/fonts/"
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

80
src/resources/generate-fonts.py Executable file
View File

@@ -0,0 +1,80 @@
#!/usr/bin/env python
import io
import sys
import json
import shutil
import typing
import os.path
import argparse
import subprocess
class Source(object):
def __init__(self, d):
self.file = d['file']
if not os.path.exists(self.file):
self.file = os.path.join(os.path.dirname(sys.argv[0]), self.file)
self.range = d.get('range')
self.symbols = d.get('symbols')
def gen_lvconv_line(lv_font_conv: str, dest: str, size: int, bpp: int, format: str, sources: typing.List[Source], compress:bool=False):
if format != "lvgl" and format != "bin":
format = "bin" if dest.lower().endswith(".bin") else "lvgl"
args = [lv_font_conv, '--size', str(size), '--output', dest, '--bpp', str(bpp), '--format', format]
if not compress:
args.append('--no-compress')
for source in sources:
args.extend(['--font', source.file])
if source.range:
args.extend(['--range', source.range])
if source.symbols:
args.extend(['--symbols', source.symbols])
return args
def main():
ap = argparse.ArgumentParser(description='auto generate LVGL font files from fonts')
ap.add_argument('config', type=str, help='config file to use')
ap.add_argument('-f', '--font', type=str, action='append', help='Choose specific fonts to generate (default: all)', default=[])
ap.add_argument('--lv-font-conv', type=str, help='Path to "lv_font_conf" executable', default="lv_font_conv")
args = ap.parse_args()
if not shutil.which(args.lv_font_conv):
sys.exit(f"Missing lv_font_conv. Make sure it's findable (in PATH) or specify it manually")
if not os.path.exists(args.config):
sys.exit(f'Error: the config file {args.config} does not exist.')
if not os.access(args.config, os.R_OK):
sys.exit(f'Error: the config file {args.config} is not accessible (permissions?).')
with open(args.config, 'r') as fd:
data = json.load(fd)
fonts_to_run = set(data.keys())
if args.font:
enabled_fonts = set()
for font in args.font:
enabled_fonts.add(font[:-2] if font.endswith('.c') else font)
d = enabled_fonts.difference(fonts_to_run)
if d:
print(f'Warning: requested font{"s" if len(d)>1 else ""} missing: {" ".join(d)}')
fonts_to_run = fonts_to_run.intersection(enabled_fonts)
for name in fonts_to_run:
font = data[name]
sources = font.pop('sources')
patches = font.pop('patches') if 'patches' in font else []
font['sources'] = [Source(thing) for thing in sources]
extension = 'c' if font['format'] != 'bin' else 'bin'
font.pop('target_path')
line = gen_lvconv_line(args.lv_font_conv, f'{name}.{extension}', **font)
subprocess.check_call(line)
if patches:
for patch in patches:
subprocess.check_call(['/usr/bin/env', 'patch', name+'.'+extension, patch])
if __name__ == '__main__':
main()

56
src/resources/generate-img.py Executable file
View File

@@ -0,0 +1,56 @@
#!/usr/bin/env python
import io
import sys
import json
import shutil
import typing
import os.path
import argparse
import subprocess
def gen_lvconv_line(lv_img_conv: str, dest: str, color_format: str, output_format: str, binary_format: str, sources: str):
args = [lv_img_conv, sources, '--force', '--output-file', dest, '--color-format', color_format, '--output-format', output_format, '--binary-format', binary_format]
return args
def main():
ap = argparse.ArgumentParser(description='auto generate LVGL font files from fonts')
ap.add_argument('config', type=str, help='config file to use')
ap.add_argument('-i', '--image', type=str, action='append', help='Choose specific images to generate (default: all)', default=[])
ap.add_argument('--lv-img-conv', type=str, help='Path to "lv_img_conf" executable', default="lv_img_conv")
args = ap.parse_args()
if not shutil.which(args.lv_img_conv):
sys.exit(f"Missing lv_img_conv. Make sure it's findable (in PATH) or specify it manually")
if not os.path.exists(args.config):
sys.exit(f'Error: the config file {args.config} does not exist.')
if not os.access(args.config, os.R_OK):
sys.exit(f'Error: the config file {args.config} is not accessible (permissions?).')
with open(args.config, 'r') as fd:
data = json.load(fd)
images_to_run = set(data.keys())
if args.image:
enabled_images = set()
for image in args.image:
enabled_images.add(image[:-2] if image.endswith('.c') else image)
d = enabled_images.difference(images_to_run)
if d:
print(f'Warning: requested image{"s" if len(d)>1 else ""} missing: {" ".join(d)}')
images_to_run = images_to_run.intersection(enabled_images)
for name in images_to_run:
image = data[name]
if not os.path.exists(image['sources']):
image['sources'] = os.path.join(os.path.dirname(sys.argv[0]), image['sources'])
extension = 'bin'
image.pop('target_path')
line = gen_lvconv_line(args.lv_img_conv, f'{name}.{extension}', **image)
subprocess.check_call(line)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,72 @@
#!/usr/bin/env python
import io
import sys
import json
import shutil
import typing
import os.path
import argparse
import subprocess
from zipfile import ZipFile
def main():
ap = argparse.ArgumentParser(description='auto generate LVGL font files from fonts')
ap.add_argument('--config', '-c', type=str, action='append', help='config file to use')
ap.add_argument('--obsolete', type=str, help='List of obsolete files')
ap.add_argument('--output', type=str, help='output file name')
args = ap.parse_args()
for config_file in args.config:
if not os.path.exists(config_file):
sys.exit(f'Error: the config file {config_file} does not exist.')
if not os.access(config_file, os.R_OK):
sys.exit(f'Error: the config file {config_file} is not accessible (permissions?).')
if args.obsolete:
obsolete_file_path = os.path.join(os.path.dirname(sys.argv[0]), args.obsolete)
if not os.path.exists(obsolete_file_path):
sys.exit(f'Error: the "obsolete" file {args.obsolete} does not exist.')
if not os.access(obsolete_file_path, os.R_OK):
sys.exit(f'Error: the "obsolete" file {args.obsolete} is not accessible (permissions?).')
zf = ZipFile(args.output, mode='w')
resource_files = []
for config_file in args.config:
with open(config_file, 'r') as fd:
data = json.load(fd)
resource_names = set(data.keys())
for name in resource_names:
resource = data[name]
resource_files.append({
"filename": name+'.bin',
"path": resource['target_path'] + name+'.bin'
})
path = name + '.bin'
if not os.path.exists(path):
path = os.path.join(os.path.dirname(sys.argv[0]), path)
zf.write(path)
if args.obsolete:
obsolete_file_path = os.path.join(os.path.dirname(sys.argv[0]), args.obsolete)
with open(obsolete_file_path, 'r') as fd:
obsolete_data = json.load(fd)
else:
obsolete_data = {}
output = {
'resources': resource_files,
'obsolete_files': obsolete_data
}
with open("resources.json", 'w') as fd:
json.dump(output, fd, indent=4)
zf.write('resources.json')
zf.close()
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,9 @@
{
"pine_small" : {
"sources": "images/pine_logo.png",
"color_format": "CF_TRUE_COLOR",
"output_format": "bin",
"binary_format": "ARGB8565_RBSWAP",
"target_path": "/images/"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,253 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="110.49872"
height="150.24246"
viewBox="0 0 29.236118 39.751652"
version="1.1"
id="svg2418"
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04, custom)"
sodipodi:docname="pine_logo.svg"
inkscape:export-filename="/home/diegomiguel/Syncthing/Watchface/pine_logo_new_2_transparent.png"
inkscape:export-xdpi="19.807983"
inkscape:export-ydpi="19.807983"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview2420"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:document-units="mm"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
units="px"
inkscape:zoom="4.1424077"
inkscape:cx="69.886892"
inkscape:cy="73.387272"
inkscape:window-width="1920"
inkscape:window-height="1026"
inkscape:window-x="0"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:current-layer="g972"
inkscape:snap-page="true" />
<defs
id="defs2415" />
<g
inkscape:label="Layer 1"
id="layer1"
transform="translate(-91.35232,-110.1768)"
inkscape:groupmode="layer">
<rect
style="display:none;opacity:1;fill:#ffffff;fill-opacity:1;stroke:#4d4d4d;stroke-width:0"
id="rect2129"
width="29.236118"
height="39.751652"
x="91.352318"
y="110.1768"
inkscape:label="bg" />
<g
id="g32004"
style="display:none;stroke:none"
inkscape:export-filename="/Users/diegomiguel/Syncthing/Watchface/logo_pine.png"
inkscape:export-xdpi="19.965168"
inkscape:export-ydpi="19.965168"
inkscape:label="pine_logo"
transform="translate(75.060638,-5.5438717)">
<g
id="g13016"
inkscape:label="pine"
style="display:inline;fill:#6f2d00;fill-opacity:1;stroke:none"
transform="matrix(1.1631294,0,0,1.1631294,-5.0422885,-22.11978)"
inkscape:export-filename="/Users/diegomiguel/Syncthing/Watchface/logo_pine.png"
inkscape:export-xdpi="31.276381"
inkscape:export-ydpi="31.276381"
sodipodi:insensitive="true">
<path
id="path5716"
style="fill:#6f2d00;fill-opacity:1;stroke:none;stroke-width:2.34917;stroke-linecap:round"
inkscape:transform-center-x="1.2687941"
d="M 116.82422,535.70898 102.4375,542.5 l -14.386719,6.78906 14.386719,6.78906 11,5.19141 v 15.80664 h 3.38672 v -14.20703 -3.93555 -9.64453 z"
transform="scale(0.26458333)" />
<path
style="fill:#6f2d00;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 18.341872,136.77692 3.331558,7.57837 7.029221,-3.22172 z"
id="path5936"
sodipodi:nodetypes="cccc" />
<path
sodipodi:type="star"
style="fill:#6f2d00;fill-opacity:1;stroke:none;stroke-width:1.51181;stroke-linecap:round"
id="path7773"
inkscape:flatsided="false"
sodipodi:sides="3"
sodipodi:cx="116.64632"
sodipodi:cy="501.86975"
sodipodi:r1="14.699218"
sodipodi:r2="7.3496094"
sodipodi:arg1="1.0471976"
sodipodi:arg2="2.0943951"
inkscape:rounded="0"
inkscape:randomized="0"
transform="matrix(0.39243637,0,0,0.31059853,-17.750778,-19.228227)"
inkscape:transform-center-x="1.4421265"
d="m 123.99592,514.59965 -11.02441,-6.36495 -11.02441,-6.36495 11.02441,-6.36495 11.02442,-6.36494 0,12.72989 z" />
<path
sodipodi:type="star"
style="fill:#6f2d00;fill-opacity:1;stroke:none;stroke-width:1.51181;stroke-linecap:round"
id="path7877"
inkscape:flatsided="false"
sodipodi:sides="3"
sodipodi:cx="116.64632"
sodipodi:cy="501.86975"
sodipodi:r1="14.699218"
sodipodi:r2="7.3496094"
sodipodi:arg1="1.0471976"
sodipodi:arg2="2.0943951"
inkscape:rounded="0"
inkscape:randomized="0"
transform="matrix(-0.3940968,0,0,-0.29190487,69.062729,278.57074)"
inkscape:transform-center-x="-1.4482278"
inkscape:transform-center-y="3.6892669e-06"
d="m 123.99592,514.59965 -11.02441,-6.36495 -11.02441,-6.36495 11.02441,-6.36495 11.02442,-6.36494 0,12.72989 z" />
<path
sodipodi:type="star"
style="fill:#6f2d00;fill-opacity:1;stroke:none;stroke-width:1.51181;stroke-linecap:round"
id="path7929"
inkscape:flatsided="false"
sodipodi:sides="3"
sodipodi:cx="116.64632"
sodipodi:cy="501.86975"
sodipodi:r1="14.699218"
sodipodi:r2="7.3496094"
sodipodi:arg1="1.0471976"
sodipodi:arg2="2.0943951"
inkscape:rounded="0"
inkscape:randomized="0"
transform="matrix(0.34926521,0,0,0.27033526,-12.397729,-7.5515591)"
inkscape:transform-center-x="1.28348"
inkscape:transform-center-y="1.7340579e-06"
d="m 123.99592,514.59965 -11.02441,-6.36495 -11.02441,-6.36495 11.02441,-6.36495 11.02442,-6.36494 0,12.72989 z" />
<path
style="fill:#6f2d00;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 24.903849,122.34368 -1.378447,3.99721 5.0395,-2.31516 z"
id="path7964"
sodipodi:nodetypes="cccc" />
<path
style="fill:#6f2d00;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 30.909733,118.50827 v 4.63122 l -3.122345,-1.29967 z"
id="path11445" />
</g>
<g
id="g13032"
transform="matrix(-1.1631294,0,0,1.1631294,66.861771,-22.11978)"
style="fill:#de5a00;fill-opacity:1;stroke:none"
inkscape:label="pine"
inkscape:export-filename="/Users/diegomiguel/Syncthing/Watchface/logo_pine.png"
inkscape:export-xdpi="31.276381"
inkscape:export-ydpi="31.276381">
<path
id="path13018"
style="fill:#de5a00;fill-opacity:1;stroke:none;stroke-width:2.34917;stroke-linecap:round"
inkscape:transform-center-x="1.2687941"
d="M 116.82422,535.70898 102.4375,542.5 l -14.386719,6.78906 14.386719,6.78906 11,5.19141 v 15.80664 h 3.38672 v -14.20703 -3.93555 -9.64453 z"
transform="scale(0.26458333)" />
<path
style="fill:#de5a00;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 18.341872,136.77692 3.331558,7.57837 7.029221,-3.22172 z"
id="path13020"
sodipodi:nodetypes="cccc" />
<path
sodipodi:type="star"
style="fill:#de5a00;fill-opacity:1;stroke:none;stroke-width:1.51181;stroke-linecap:round"
id="path13022"
inkscape:flatsided="false"
sodipodi:sides="3"
sodipodi:cx="116.64632"
sodipodi:cy="501.86975"
sodipodi:r1="14.699218"
sodipodi:r2="7.3496094"
sodipodi:arg1="1.0471976"
sodipodi:arg2="2.0943951"
inkscape:rounded="0"
inkscape:randomized="0"
transform="matrix(0.39243637,0,0,0.31059853,-17.750778,-19.228227)"
inkscape:transform-center-x="1.4421265"
d="m 123.99592,514.59965 -11.02441,-6.36495 -11.02441,-6.36495 11.02441,-6.36495 11.02442,-6.36494 0,12.72989 z" />
<path
sodipodi:type="star"
style="fill:#de5a00;fill-opacity:1;stroke:none;stroke-width:1.51181;stroke-linecap:round"
id="path13024"
inkscape:flatsided="false"
sodipodi:sides="3"
sodipodi:cx="116.64632"
sodipodi:cy="501.86975"
sodipodi:r1="14.699218"
sodipodi:r2="7.3496094"
sodipodi:arg1="1.0471976"
sodipodi:arg2="2.0943951"
inkscape:rounded="0"
inkscape:randomized="0"
transform="matrix(-0.3940968,0,0,-0.29190487,69.062729,278.57074)"
inkscape:transform-center-x="-1.4482278"
inkscape:transform-center-y="3.6892669e-06"
d="m 123.99592,514.59965 -11.02441,-6.36495 -11.02441,-6.36495 11.02441,-6.36495 11.02442,-6.36494 0,12.72989 z" />
<path
sodipodi:type="star"
style="fill:#de5a00;fill-opacity:1;stroke:none;stroke-width:1.51181;stroke-linecap:round"
id="path13026"
inkscape:flatsided="false"
sodipodi:sides="3"
sodipodi:cx="116.64632"
sodipodi:cy="501.86975"
sodipodi:r1="14.699218"
sodipodi:r2="7.3496094"
sodipodi:arg1="1.0471976"
sodipodi:arg2="2.0943951"
inkscape:rounded="0"
inkscape:randomized="0"
transform="matrix(0.34926521,0,0,0.27033526,-12.397729,-7.5515591)"
inkscape:transform-center-x="1.28348"
inkscape:transform-center-y="1.7340579e-06"
d="m 123.99592,514.59965 -11.02441,-6.36495 -11.02441,-6.36495 11.02441,-6.36495 11.02442,-6.36494 0,12.72989 z" />
<path
style="fill:#de5a00;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 24.903849,122.34368 -1.378447,3.99721 5.0395,-2.31516 z"
id="path13028"
sodipodi:nodetypes="cccc" />
<path
style="fill:#de5a00;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 30.909733,118.50827 v 4.63122 l -3.122345,-1.29967 z"
id="path13030" />
</g>
</g>
<g
id="g972"
style="display:inline;stroke:none"
inkscape:export-filename="/Users/diegomiguel/Syncthing/Watchface/logo_pine.png"
inkscape:export-xdpi="19.965168"
inkscape:export-ydpi="19.965168"
inkscape:label="pine_logo"
transform="translate(75.060638,-5.5438717)">
<path
id="path952"
style="fill:#0f0f0f;fill-opacity:1;stroke:none;stroke-width:0.307744px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 30.909731,115.72067 v 5.38671 l -3.631692,-1.51168 z m -6.985621,4.46108 -1.603312,4.64927 5.861591,-2.69283 z m 6.98562,10.72311 -4.478564,-2.00136 -4.478563,-2.00136 4.478563,-2.00136 4.478568,-2.00137 v 4.00273 z m -12.461069,-3.7293 5.05343,2.16104 5.053431,2.16105 -5.053431,2.16105 -5.053434,2.16104 v -4.32209 z m 12.461067,14.24725 -5.032139,-2.29945 -5.032139,-2.29944 5.032139,-2.29943 5.032144,-2.29945 v 4.59888 z m -14.618046,-4.45333 3.875033,8.81462 8.175894,-3.74728 z m 14.618058,5.77232 -4.427436,2.0899 -4.427436,2.08929 4.427436,2.0893 3.385191,1.59762 v 4.86441 h 1.042245 v -4.37214 -1.21114 -2.96805 z"
inkscape:label="left" />
<path
id="path968"
style="fill:#575757;fill-opacity:1;stroke:none;stroke-width:0.307744px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 30.909752,115.72067 v 5.38671 l 3.631691,-1.51168 z m 6.98562,4.46108 1.603312,4.64927 -5.86159,-2.69283 z m -6.985619,10.72311 4.478564,-2.00136 4.478563,-2.00136 -4.478563,-2.00136 -4.478568,-2.00136 v 4.00272 z m 12.461067,-3.72931 -5.05343,2.16105 -5.05343,2.16105 5.05343,2.16104 5.053435,2.16105 v -4.32209 z m -12.461065,14.24726 5.032139,-2.29945 5.032139,-2.29944 -5.032139,-2.29944 -5.032144,-2.29944 v 4.59888 z m 14.618045,-4.45333 -3.875033,8.81462 -8.175893,-3.74728 z m -14.618058,5.77231 4.427436,2.0899 4.427436,2.0893 -4.427436,2.0893 -3.385191,1.59763 v 4.8644 h -1.042245 v -4.37213 -1.21115 -2.96805 z"
inkscape:label="right" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,6 @@
[
{
"path": "/example-of-obsolete-file.bin",
"since": "1.11.0"
}
]

View File

@@ -251,7 +251,8 @@ void SystemTask::Work() {
case Messages::TouchWakeUp: {
if (touchHandler.GetNewTouchInfo()) {
auto gesture = touchHandler.GestureGet();
if (gesture != Pinetime::Applications::TouchEvents::None &&
if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep &&
gesture != Pinetime::Applications::TouchEvents::None &&
((gesture == Pinetime::Applications::TouchEvents::DoubleTap &&
settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) ||
(gesture == Pinetime::Applications::TouchEvents::Tap &&
@@ -280,7 +281,7 @@ void SystemTask::Work() {
}
break;
case Messages::OnNewNotification:
if (settingsController.GetNotificationStatus() == Pinetime::Controllers::Settings::Notification::ON) {
if (settingsController.GetNotificationStatus() == Pinetime::Controllers::Settings::Notification::On) {
if (state == SystemTaskState::Sleeping) {
GoToRunning();
} else {
@@ -388,7 +389,8 @@ void SystemTask::Work() {
break;
case Messages::OnNewHour:
using Pinetime::Controllers::AlarmController;
if (settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::Hours &&
if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep &&
settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::Hours &&
alarmController.State() != AlarmController::AlarmState::Alerting) {
if (state == SystemTaskState::Sleeping) {
GoToRunning();
@@ -399,7 +401,8 @@ void SystemTask::Work() {
break;
case Messages::OnNewHalfHour:
using Pinetime::Controllers::AlarmController;
if (settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::HalfHours &&
if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep &&
settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::HalfHours &&
alarmController.State() != AlarmController::AlarmState::Alerting) {
if (state == SystemTaskState::Sleeping) {
GoToRunning();
@@ -483,13 +486,13 @@ void SystemTask::UpdateMotion() {
motionController.IsSensorOk(motionSensor.IsOk());
motionController.Update(motionValues.x, motionValues.y, motionValues.z, motionValues.steps);
if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist) &&
motionController.Should_RaiseWake(state == SystemTaskState::Sleeping)) {
GoToRunning();
}
if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::Shake) &&
motionController.Should_ShakeWake(settingsController.GetShakeThreshold())) {
GoToRunning();
if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep) {
if ((settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist) &&
motionController.Should_RaiseWake(state == SystemTaskState::Sleeping)) ||
(settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::Shake) &&
motionController.Should_ShakeWake(settingsController.GetShakeThreshold()))) {
GoToRunning();
}
}
}