~aleteoryx/muditaos

92a8a78ed46d6383ca23aad83ffdb35f9b61d0a4 — Marcin Smoczyński 5 years ago 661d203 + fc5ab3a
Merge branch 'master' into stable
287 files changed, 5252 insertions(+), 2108 deletions(-)

M .github/workflows/main.yml
M .github/workflows/releases.yaml
M .gitmessage
M CMakeLists.txt
M LICENSE.md
M changelog.md
A config/GenUpdateVersionJson.cmake
A config/GenVersionHpp.cmake
M config/ProjectConfig.cmake
A config/Utils.cmake
M config/Version.cmake
A config/version.json.cmake_template
M doc/development_workflow.md
M doc/quickstart.md
A doc/static_analysis.md
M host-tools/CMakeLists.txt
M host-tools/genlittlefs/CMakeLists.txt
M host-tools/genlittlefs/mklfs.c
M image/CMakeLists.txt
M image/assets/lang/Deutsch.json
M image/assets/lang/English.json
M image/assets/lang/Espanol.json
M image/assets/lang/Francais.json
M image/assets/lang/Polski.json
A image/user/data/applications/settings/quotes.json
M module-apps/Application.cpp
M module-apps/Application.hpp
M module-apps/CMakeLists.txt
A module-apps/TopBarManager.cpp
A module-apps/TopBarManager.hpp
M module-apps/application-alarm-clock/windows/AlarmClockMainWindow.cpp
M module-apps/application-alarm-clock/windows/CustomRepeatWindow.cpp
M module-apps/application-alarm-clock/windows/NewEditAlarmWindow.cpp
M module-apps/application-antenna/windows/AlgoParamsWindow.cpp
M module-apps/application-antenna/windows/AntennaMainWindow.cpp
M module-apps/application-antenna/windows/ScanModesWindow.cpp
M module-apps/application-calculator/data/CalculatorUtility.cpp
M module-apps/application-calculator/data/CalculatorUtility.hpp
M module-apps/application-calculator/tests/CalculatorUtility_tests.cpp
M module-apps/application-calculator/widgets/CalculatorStyle.hpp
M module-apps/application-calculator/windows/CalculatorMainWindow.cpp
M module-apps/application-calculator/windows/CalculatorMainWindow.hpp
M module-apps/application-calendar/ApplicationCalendar.cpp
M module-apps/application-calendar/ApplicationCalendar.hpp
M module-apps/application-calendar/data/CalendarData.hpp
M module-apps/application-calendar/data/dateCommon.hpp
M module-apps/application-calendar/models/AllEventsModel.cpp
M module-apps/application-calendar/models/DayEventsModel.cpp
M module-apps/application-calendar/models/DayEventsModel.hpp
M module-apps/application-calendar/widgets/EventDateItem.cpp
M module-apps/application-calendar/widgets/EventDateItem.hpp
M module-apps/application-calendar/widgets/EventTimeItem.cpp
M module-apps/application-calendar/widgets/EventTimeItem.hpp
M module-apps/application-calendar/widgets/MonthBox.cpp
M module-apps/application-calendar/windows/AllEventsWindow.cpp
M module-apps/application-calendar/windows/AllEventsWindow.hpp
M module-apps/application-calendar/windows/CalendarMainWindow.cpp
M module-apps/application-calendar/windows/CustomRepeatWindow.cpp
M module-apps/application-calendar/windows/DayEventsWindow.cpp
M module-apps/application-calendar/windows/DayEventsWindow.hpp
M module-apps/application-calendar/windows/EventDetailWindow.cpp
M module-apps/application-calendar/windows/EventReminderWindow.cpp
M module-apps/application-calendar/windows/EventReminderWindow.hpp
M module-apps/application-calendar/windows/NewEditEventWindow.cpp
M module-apps/application-call/ApplicationCall.cpp
M module-apps/application-call/windows/CallWindow.cpp
M module-apps/application-call/windows/EnterNumberWindow.cpp
M module-apps/application-calllog/windows/CallLogDetailsWindow.cpp
M module-apps/application-calllog/windows/CallLogMainWindow.cpp
M module-apps/application-desktop/ApplicationDesktop.cpp
M module-apps/application-desktop/data/Style.hpp
M module-apps/application-desktop/windows/DesktopMainWindow.cpp
M module-apps/application-desktop/windows/DesktopMainWindow.hpp
M module-apps/application-desktop/windows/LockWindow.cpp
M module-apps/application-desktop/windows/LockWindow.hpp
M module-apps/application-desktop/windows/LockedInfoWindow.cpp
M module-apps/application-desktop/windows/LockedInfoWindow.hpp
M module-apps/application-desktop/windows/MenuWindow.cpp
M module-apps/application-desktop/windows/MmiPullWindow.cpp
M module-apps/application-desktop/windows/MmiPushWindow.cpp
M module-apps/application-desktop/windows/PinLockBaseWindow.cpp
M module-apps/application-desktop/windows/PinLockBaseWindow.hpp
M module-apps/application-meditation/windows/MeditationListViewWindows.cpp
M module-apps/application-meditation/windows/MeditationTimerWindow.cpp
M module-apps/application-messages/windows/MessagesMainWindow.cpp
M module-apps/application-messages/windows/NewMessage.cpp
M module-apps/application-messages/windows/SMSTemplatesWindow.cpp
M module-apps/application-messages/windows/SMSThreadViewWindow.cpp
M module-apps/application-music-player/windows/MusicPlayerAllSongsWindow.cpp
M module-apps/application-music-player/windows/MusicPlayerEmptyWindow.cpp
M module-apps/application-notes/windows/NoteEditWindow.cpp
M module-apps/application-notes/windows/NoteMainWindow.cpp
M module-apps/application-notes/windows/NotePreviewWindow.cpp
M module-apps/application-phonebook/windows/PhonebookContactDetails.cpp
M module-apps/application-phonebook/windows/PhonebookIceContacts.cpp
M module-apps/application-phonebook/windows/PhonebookMainWindow.cpp
M module-apps/application-phonebook/windows/PhonebookSearch.cpp
M module-apps/application-phonebook/windows/PhonebookSearchResults.cpp
M module-apps/application-settings-new/ApplicationSettings.cpp
M module-apps/application-settings-new/ApplicationSettings.hpp
M module-apps/application-settings-new/CMakeLists.txt
A module-apps/application-settings-new/data/ApnListData.hpp
A module-apps/application-settings-new/data/QuoteSwitchData.hpp
A module-apps/application-settings-new/data/SettingsInternals.hpp
A module-apps/application-settings-new/data/SettingsItemData.hpp
A module-apps/application-settings-new/models/ApnSettingsModel.cpp
A module-apps/application-settings-new/models/ApnSettingsModel.hpp
A module-apps/application-settings-new/models/NewApnModel.cpp
A module-apps/application-settings-new/models/NewApnModel.hpp
A module-apps/application-settings-new/models/QuotesModel.cpp
A module-apps/application-settings-new/models/QuotesModel.hpp
A module-apps/application-settings-new/models/QuotesRepository.cpp
A module-apps/application-settings-new/models/QuotesRepository.hpp
A module-apps/application-settings-new/widgets/ApnInputWidget.cpp
A module-apps/application-settings-new/widgets/ApnInputWidget.hpp
A module-apps/application-settings-new/widgets/ApnListItem.hpp
A module-apps/application-settings-new/widgets/OptionSetting.hpp
A module-apps/application-settings-new/widgets/QuoteWidget.cpp
A module-apps/application-settings-new/widgets/QuoteWidget.hpp
M module-apps/application-settings-new/widgets/SettingsStyle.hpp
A module-apps/application-settings-new/widgets/SpinBox.cpp
A module-apps/application-settings-new/widgets/SpinBox.hpp
A module-apps/application-settings-new/widgets/SpinBoxOptionSetting.cpp
D module-apps/application-settings-new/windows/APNSettingsWindow.cpp
M module-apps/application-settings-new/windows/AllDevicesWindow.cpp
A module-apps/application-settings-new/windows/ApnOptionsWindow.cpp
A module-apps/application-settings-new/windows/ApnOptionsWindow.hpp
A module-apps/application-settings-new/windows/ApnSettingsWindow.cpp
R module-apps/application-settings-new/windows/{APNSettingsWindow => ApnSettingsWindow}.hpp
M module-apps/application-settings-new/windows/AppsAndToolsWindow.cpp
M module-apps/application-settings-new/windows/BaseSettingsWindow.cpp
M module-apps/application-settings-new/windows/BaseSettingsWindow.hpp
M module-apps/application-settings-new/windows/BluetoothWindow.cpp
M module-apps/application-settings-new/windows/ChangePasscodeWindow.cpp
M module-apps/application-settings-new/windows/ChangePasscodeWindow.hpp
M module-apps/application-settings-new/windows/DisplayLightWindow.cpp
M module-apps/application-settings-new/windows/DisplayLightWindow.hpp
M module-apps/application-settings-new/windows/MessagesWindow.cpp
M module-apps/application-settings-new/windows/NetworkWindow.cpp
A module-apps/application-settings-new/windows/NewApnWindow.cpp
A module-apps/application-settings-new/windows/NewApnWindow.hpp
M module-apps/application-settings-new/windows/NightshiftWindow.cpp
M module-apps/application-settings-new/windows/PhoneNameWindow.cpp
M module-apps/application-settings-new/windows/QuotesAddWindow.cpp
M module-apps/application-settings-new/windows/QuotesAddWindow.hpp
M module-apps/application-settings-new/windows/QuotesMainWindow.cpp
M module-apps/application-settings-new/windows/QuotesMainWindow.hpp
A module-apps/application-settings-new/windows/QuotesOptionsWindow.cpp
A module-apps/application-settings-new/windows/QuotesOptionsWindow.hpp
A module-apps/application-settings-new/windows/SystemMainWindow.cpp
A module-apps/application-settings-new/windows/SystemMainWindow.hpp
M module-apps/application-settings/ApplicationSettings.cpp
M module-apps/application-settings/windows/BtScanWindow.cpp
M module-apps/application-settings/windows/BtWindow.cpp
M module-apps/application-settings/windows/CellularPassthroughWindow.cpp
M module-apps/application-settings/windows/CellularPassthroughWindow.hpp
M module-apps/application-settings/windows/DateTimeWindow.cpp
M module-apps/application-settings/windows/EinkModeWindow.cpp
M module-apps/application-settings/windows/FotaWindow.cpp
M module-apps/application-settings/windows/Info.cpp
M module-apps/application-settings/windows/LanguageWindow.cpp
M module-apps/application-settings/windows/SimSelectWindow.hpp
M module-apps/application-settings/windows/TestMessageWindow.cpp
M module-apps/application-special-input/windows/SpecialInputMainWindow.cpp
M module-apps/options/type/OptionSetting.hpp
M module-apps/widgets/BarGraph.cpp
M module-apps/widgets/BarGraph.hpp
M module-apps/windows/AppWindow.cpp
M module-apps/windows/AppWindow.hpp
M module-apps/windows/Dialog.cpp
M module-apps/windows/OptionWindow.cpp
M module-apps/windows/OptionWindow.hpp
M module-audio/Audio/StreamQueuedEventsListener.cpp
M module-audio/Audio/StreamQueuedEventsListener.hpp
M module-bsp/board/linux/battery-charger/battery_charger.cpp
M module-bsp/board/linux/usb_cdc/usb_cdc.cpp
A module-bsp/board/rt1051/bsp/battery-charger/MAX77818.hpp
M module-bsp/board/rt1051/bsp/battery-charger/battery_charger.cpp
M module-bsp/board/rt1051/common/irq/irq_gpio.cpp
M module-bsp/bsp/battery-charger/battery_charger.hpp
M module-db/Common/Query.cpp
M module-db/Common/Query.hpp
M module-db/Interface/AlarmsRecord.hpp
M module-db/Interface/EventsRecord.cpp
M module-db/Interface/EventsRecord.hpp
M module-db/Tables/AlarmsTable.cpp
M module-db/Tables/AlarmsTable.hpp
M module-db/Tables/EventsTable.cpp
M module-db/Tables/EventsTable.hpp
M module-db/queries/calendar/QueryEventsGetFiltered.cpp
M module-db/queries/calendar/QueryEventsGetFiltered.hpp
M module-db/queries/calendar/QueryEventsSelectFirstUpcoming.cpp
M module-db/queries/calendar/QueryEventsSelectFirstUpcoming.hpp
M module-db/tests/AlarmsRecord_tests.cpp
M module-db/tests/AlarmsTable_tests.cpp
M module-db/tests/EventsRecord_tests.cpp
M module-db/tests/EventsTable_tests.cpp
M module-db/tests/QueryInterface.cpp
M module-gui/gui/dom/Item2JsonSerializingVisitor.cpp
M module-gui/gui/dom/Item2JsonSerializingVisitor.hpp
M module-gui/gui/widgets/BoxLayout.cpp
M module-gui/gui/widgets/GridLayout.cpp
M module-gui/gui/widgets/GridLayout.hpp
M module-gui/gui/widgets/Item.hpp
M module-gui/gui/widgets/ProgressBar.cpp
M module-gui/gui/widgets/ProgressBar.hpp
M module-gui/gui/widgets/Style.hpp
M module-gui/gui/widgets/TopBar.cpp
M module-gui/gui/widgets/TopBar.hpp
M module-gui/gui/widgets/visitor/GuiVisitor.hpp
M module-gui/test/test-google/test-gui-gridlayout.cpp
M module-gui/test/test-google/test-gui-visitor-call.cpp
M module-services/service-appmgr/model/ApplicationManager.cpp
M module-services/service-cellular/CellularRequestHandler.cpp
M module-services/service-cellular/CellularUrcHandler.cpp
M module-services/service-cellular/CellularUrcHandler.hpp
M module-services/service-cellular/ServiceCellular.cpp
M module-services/service-cellular/service-cellular/CellularRequestHandler.hpp
M module-services/service-cellular/service-cellular/PacketDataTypes.hpp
M module-services/service-db/DBServiceAPI.cpp
M module-services/service-db/agents/settings/Settings.cpp
M module-services/service-db/agents/settings/SettingsAgent.cpp
M module-services/service-db/agents/settings/SettingsAgent.hpp
M module-services/service-db/agents/settings/SystemSettings.hpp
M module-services/service-db/service-db/Settings.hpp
M module-services/service-db/service-db/SettingsMessages.hpp
A module-services/service-db/service-db/SettingsScope.hpp
M module-services/service-db/test/test-service-db-settings-messages.cpp
M module-services/service-db/test/test-service-db-settings-testservices.hpp
M module-services/service-desktop/DesktopMessages.cpp
M module-services/service-desktop/ServiceDesktop.cpp
M module-services/service-desktop/WorkerDesktop.cpp
M module-services/service-desktop/endpoints/EndpointFactory.hpp
M module-services/service-desktop/endpoints/backup/BackupEndpoint.cpp
M module-services/service-desktop/endpoints/backup/BackupEndpoint.hpp
M module-services/service-desktop/endpoints/calendarEvents/CalendarEventsEndpoint.hpp
M module-services/service-desktop/endpoints/calllog/CalllogEndpoint.hpp
M module-services/service-desktop/endpoints/contacts/ContactsEndpoint.hpp
M module-services/service-desktop/endpoints/developerMode/DeveloperModeEndpoint.hpp
M module-services/service-desktop/endpoints/deviceInfo/DeviceInfoEndpoint.cpp
M module-services/service-desktop/endpoints/deviceInfo/DeviceInfoEndpoint.hpp
M module-services/service-desktop/endpoints/factoryReset/FactoryResetEndpoint.cpp
M module-services/service-desktop/endpoints/factoryReset/FactoryResetEndpoint.hpp
M module-services/service-desktop/endpoints/filesystem/FilesystemEndpoint.cpp
M module-services/service-desktop/endpoints/filesystem/FilesystemEndpoint.hpp
M module-services/service-desktop/endpoints/messages/MessagesEndpoint.hpp
M module-services/service-desktop/endpoints/restore/RestoreEndpoint.cpp
M module-services/service-desktop/endpoints/restore/RestoreEndpoint.hpp
M module-services/service-desktop/endpoints/update/UpdateEndpoint.cpp
M module-services/service-desktop/endpoints/update/UpdateEndpoint.hpp
M module-services/service-desktop/parser/MessageHandler.cpp
M module-services/service-desktop/parser/MessageHandler.hpp
M module-services/service-desktop/parser/ParserFSM.cpp
M module-services/service-desktop/parser/ParserFSM.hpp
M module-services/service-desktop/service-desktop/DesktopMessages.hpp
M module-services/service-desktop/tests/unittest.cpp
M module-services/service-eink/EinkDisplay.cpp
M module-services/service-eink/board/linux/renderer/CMakeLists.txt
M module-services/service-evtmgr/CMakeLists.txt
M module-services/service-evtmgr/EventManager.cpp
M module-services/service-evtmgr/WorkerEvent.cpp
M module-services/service-evtmgr/doc/screen_light_control.md
M module-services/service-evtmgr/screen-light-control/ControlFunctions.cpp
M module-services/service-evtmgr/screen-light-control/ControlFunctions.hpp
M module-services/service-evtmgr/screen-light-control/ScreenLightControl.cpp
M module-services/service-evtmgr/screen-light-control/ScreenLightControl.hpp
M module-services/service-evtmgr/service-evtmgr/EVMessages.hpp
M module-services/service-evtmgr/service-evtmgr/EventManager.hpp
A module-services/service-evtmgr/service-evtmgr/ScreenLightControlMessage.hpp
M module-services/service-evtmgr/tests/test-ScreenLightControlFunctions.cpp
M module-services/service-fota/FotaUrcHandler.cpp
M module-services/service-fota/FotaUrcHandler.hpp
M module-services/service-time/service-time/CalendarTimeEvents.hpp
M module-services/service-time/timeEvents/CalendarTimeEvents.cpp
M module-sys/SystemManager/SystemManager.cpp
M module-sys/SystemManager/SystemManager.hpp
M module-utils/Utils.hpp
M module-utils/ical/ParserICS.cpp
M module-utils/ical/ParserICS.hpp
M module-utils/time/TimeRangeParser.cpp
M module-utils/time/TimeRangeParser.hpp
M module-utils/time/time_conversion.cpp
M module-utils/time/time_locale.hpp
M source/MessageType.hpp
M tools/check_commit_messages.py
A tools/clang-tidy.cmake
M tools/download_asset.py
M .github/workflows/main.yml => .github/workflows/main.yml +0 -6
@@ 20,12 20,6 @@ jobs:
          fetch-depth: 0
      - name: check commit messages
        run: ./tools/check_commit_messages.py
  build:
    if: github.event.pull_request.draft == false
    runs-on: self-hosted
    steps:
      - name: build
        run: echo "Placeholder for old CI scripts"
  check_copyright_and_style:
    name: check copyright and style
    if: github.event.pull_request.draft == false

M .github/workflows/releases.yaml => .github/workflows/releases.yaml +21 -6
@@ 27,13 27,17 @@ jobs:
        popd
    - name: "Build and package for RT1051"
      id: build_release_package 
      env:
        ASSETS_LOGIN: ${{ secrets.ASSETS_LOGIN }}
        ASSETS_TOKEN: ${{ secrets.ASSETS_TOKEN }}
      run: |
        ./configure.sh rt1051 RelWithDebInfo && \
        pushd build-rt1051-RelWithDebInfo && \
        export JOBS=${JOBS:-`nproc`} && \
        echo "JOBS=${JOBS}" && \
        make -j ${JOBS} && \
        make -j ${JOBS}  package && \
        make package-update VERBOSE=1 && \
        make package-standalone && \
        popd && \
        ./print_last_changes.sh && \
        uptime


@@ 48,15 52,26 @@ jobs:
        draft: true
        prerelease: true
        body: ${{steps.build_release_package.outputs.release_notes }}
    - name: Upload Release Package
      id: upload-release-package
    - name: Upload Standalone Package
      id: upload-stanalone-package
      uses: actions/upload-release-asset@v1.0.2
      env:
        GITHUB_TOKEN: ${{ secrets.GitHub_PAT }}
      with:
        upload_url: ${{ steps.create_release.outputs.upload_url }}
        # here we have to use relative path with starting "./"
        asset_path: ./${{ steps.build_release_package.outputs.package_path }}/${{ steps.build_release_package.outputs.package-standalone }}
        asset_name: ${{ steps.build_release_package.outputs.package-standalone }}
        asset_content_type: ${{ steps.build_release_package.outputs.standalone-mime_type }}
    - name: Upload Update Package
      id: upload-update-package
      uses: actions/upload-release-asset@v1.0.2
      env:
        GITHUB_TOKEN: ${{ secrets.GitHub_PAT }}
      with:
        upload_url: ${{ steps.create_release.outputs.upload_url }}
        # here we have to use relative path with starting "./"
        asset_path: ./${{ steps.build_release_package.outputs.package_path }}/${{steps.build_release_package.outputs.package}}
        asset_name: ${{ steps.build_release_package.outputs.package }}
        asset_content_type: ${{ steps.build_release_package.outputs.mime_type }}
        asset_path: ./${{ steps.build_release_package.outputs.package_path }}/${{ steps.build_release_package.outputs.package-update }}
        asset_name: ${{ steps.build_release_package.outputs.package-update }}
        asset_content_type: ${{ steps.build_release_package.outputs.update-mime_type }}


M .gitmessage => .gitmessage +1 -3
@@ 1,7 1,5 @@
# Commit subject: [JIRA-TICKET] <Add/Change/Fix> changes summary, don't end with a period
# Commit subject: [JIRA-TICKET] Changes summary, don't end with a period
# No more than 72 chars. ########################### 72 chars is here: #
<Title>
# Remember blank line between title and commit message.

# Commit message: Explain *what* and *why* (not *how*).
# Wrap at 72 chars. ################################### which is here: #

M CMakeLists.txt => CMakeLists.txt +138 -28
@@ 14,6 14,7 @@ include(ModuleConfig)
include(module-lwip/lwip-includes.cmake)
include(SerialPort)
include(CopyGdbInit)
include(Utils)

message("PROJECT_TARGET: ${PROJECT_TARGET}")
message("TARGET_SOURCES: ${TARGET_SOURCES}")


@@ 218,7 219,14 @@ if (${PROJECT_TARGET} STREQUAL "TARGET_Linux")
		DEPENDS ${FAT_IMAGE}
	)
	add_dependencies(check ${FAT_IMAGE}-target)
    install(TARGETS ${CMAKE_PROJECT_NAME} DESTINATION "./")
    multicomp_install(
        TARGETS ${CMAKE_PROJECT_NAME}
        DESTINATION "./"
        COMPONENTS Standalone Update
        )
    set(CPACK_SYSTEM_NAME "Linux")
    # only allow the standalone package in Linux config
    set(CPACK_COMPONENTS_ALL Standalone)
endif()




@@ 249,14 257,63 @@ if (${PROJECT_TARGET} STREQUAL "TARGET_RT1051")
        ${HEX_FILE}-target ALL
        DEPENDS ${CMAKE_BINARY_DIR}/${HEX_FILE}
        )
    install(FILES ${CMAKE_BINARY_DIR}/${BIN_FILE}

    multicomp_install(FILES ${CMAKE_BINARY_DIR}/${BIN_FILE}
        DESTINATION "./"
        PERMISSIONS
            OWNER_READ OWNER_WRITE OWNER_EXECUTE
            GROUP_READ GROUP_EXECUTE
            WORLD_READ WORLD_EXECUTE
        COMPONENTS Standalone Update
        )

    # download the bootloader
    set(ECOBOOT_FILE ${CMAKE_BINARY_DIR}/ecoboot.bin)
    set(ECOBOOT_DOWNLOAD_LOG ${CMAKE_BINARY_DIR}/download_info.txt)

    if(DEFINED ENV{ASSETS_LOGIN} AND DEFINED ENV{ASSETS_TOKEN})
        message("ecooboot download with tokens")
        add_custom_command(OUTPUT ${ECOBOOT_FILE}
            COMMAND ${CMAKE_SOURCE_DIR}/tools/download_asset.py
            -l $ENV{ASSETS_LOGIN}
            -t $ENV{ASSETS_TOKEN}
            -w ${CMAKE_BINARY_DIR} ecoboot download
            > ${ECOBOOT_DOWNLOAD_LOG}
            COMMENT "Downloading ecoboot.bin"
            BYPRODUCTS ${ECOBOOT_FILE} ${ECOBOOT_DOWNLOAD_LOG}
            )
    else()
        message("ecoboot download with git")
        add_custom_command(OUTPUT ${ECOBOOT_FILE}
            COMMAND ${CMAKE_SOURCE_DIR}/tools/download_asset.py
            -w ${CMAKE_BINARY_DIR} ecoboot download
            > ${ECOBOOT_DOWNLOAD_LOG}
            COMMENT "Downloading ecoboot.bin"
            BYPRODUCTS ${ECOBOOT_FILE} ${ECOBOOT_DOWNLOAD_LOG}
            )
    endif()

    add_custom_target(ecoboot.bin DEPENDS ${ECOBOOT_FILE})

    # generate version.json file (runs CMake script at build time)
    set(VERSION_JSON ${CMAKE_BINARY_DIR}/version.json)
    add_custom_command(OUTPUT ${VERSION_JSON}
        COMMAND ${CMAKE_COMMAND}
        -DSRC_DIR=${CMAKE_SOURCE_DIR}
        -DECOBOOT_DOWNLOAD_LOG=${ECOBOOT_DOWNLOAD_LOG}
        -B ${CMAKE_BINARY_DIR}
        -P ${CMAKE_SOURCE_DIR}/config/GenUpdateVersionJson.cmake
        DEPENDS ecoboot.bin ${ECOBOOT_DOWNLOAD_LOG}
        BYPRODUCTS ${VERSION_JSON}
        )
    add_custom_target(version.json DEPENDS ${VERSION_JSON})

    multicomp_install(PROGRAMS ${ECOBOOT_FILE} DESTINATION "./" COMPONENTS Standalone Update)
    multicomp_install(FILES ${VERSION_JSON} DESTINATION "./" COMPONENTS Standalone Update)

    set(CPACK_SYSTEM_NAME "RT1051")
    # allow both standalone and update packages in RT1051 config
    set(CPACK_COMPONENTS_ALL Standalone Update)
endif()

if (${CMAKE_BUILD_TYPE} STREQUAL "Release")


@@ 265,8 322,10 @@ if (${CMAKE_BUILD_TYPE} STREQUAL "Release")
        )
endif()

install(FILES ${PROJECT_SOURCE_DIR}/changelog.md
install(
    FILES ${PROJECT_SOURCE_DIR}/changelog.md
    DESTINATION "./"
    COMPONENT Standalone
    )

if (${CMAKE_BUILD_TYPE} STREQUAL "RelWithDebInfo")


@@ 280,11 339,6 @@ if (${CMAKE_BUILD_TYPE} STREQUAL "RelWithDebInfo")
        )
endif()

add_custom_target(ecoboot.bin 
    COMMAND ${CMAKE_SOURCE_DIR}/tools/download_asset.py -w ${CMAKE_BINARY_DIR}/update ecoboot download
    BYPRODUCTS update/ecoboot.bin
    )

message_serial_status()

option (BUILD_DOC_WITH_ALL "Build documentation" OFF)


@@ 321,39 375,95 @@ else ()
endif ()

message("SRC DIR: ${CMAKE_SOURCE_DIR}")

include(Version)
configure_file(
    ${SRC_DIR}/source/version.hpp.template
    ${CMAKE_BINARY_DIR}/source/version.hpp
    )
add_custom_target(
    version ALL
    COMMAND
        ${CMAKE_COMMAND} -DSRC_DIR=${CMAKE_SOURCE_DIR} -B ${CMAKE_BINARY_DIR}  -P ${CMAKE_SOURCE_DIR}/config/Version.cmake
    COMMAND ${CMAKE_COMMAND}
    -DSRC_DIR=${CMAKE_SOURCE_DIR}
    -B ${CMAKE_BINARY_DIR}
    -P ${CMAKE_SOURCE_DIR}/config/GenVersionHpp.cmake
    COMMENT
        "Generationg version info"
        "Generating version info"
    )

add_dependencies(${PROJECT_NAME} version)

set(CPACK_PACKAGE_VENDOR "Mudita")
set(CPACK_PACKAGE_NAME "PurePhone")
set(CPACK_PACKAGE_HOMEPAGE_URL "https://mudita.com/products/pure/")
if (${PROJECT_TARGET} STREQUAL "TARGET_RT1051")
    set(CPACK_GENERATOR "ZIP")
    set(PACKAGE_EXTENSION ".zip")
    set(PACKAGE_MIME "application/zip")
else()
    set(CPACK_GENERATOR "TGZ")
    set(PACKAGE_EXTENSION ".tar.gz")
    set(PACKAGE_MIME "application/x-compressed-tar")
endif()
set(CPACK_TOPLEVEL_TAG ${CPACK_SYSTEM_NAME})
# the CPACK_PACKAGE_FILE_NAME variable will be reset after include(CPack) hence a copy
set(PACKAGE_COMMON_NAME ${CPACK_PACKAGE_NAME}-${CMAKE_PROJECT_VERSION}-${CPACK_TOPLEVEL_TAG})
set(CPACK_PACKAGE_FILE_NAME ${PACKAGE_COMMON_NAME})
# setting this will CPack prevent from additing the default 'package' target
set(CPACK_OUTPUT_CONFIG_FILE ${CMAKE_BINARY_DIR}/PackageConfig.cmake)
set(CPACK_GENERATOR "External")
set(CPACK_COMPONENTS_GROUPING IGNORE)
set(CPACK_EXTERNAL_ENABLE_STAGING TRUE)
set(PACKAGE_STAGING_DIRECTORY ${CMAKE_BINARY_DIR}/_CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME})

include(CPack)

if (NOT "$ENV{GITHUB_WORKSPACE}" STREQUAL "")
    set(PACKAGE_FILE ${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CPACK_SYSTEM_NAME}${PACKAGE_EXTENSION})

    message("set-output name=package::${PACKAGE_FILE}")
    message("::set-output name=package::${PACKAGE_FILE}")
add_custom_target(package-standalone-staged
    COMMAND ${CMAKE_CPACK_COMMAND}
    -C $<CONFIGURATION>
    --config ${CPACK_OUTPUT_CONFIG_FILE}
    )

    message("set-output name=mime_type::${PACKAGE_MIME}")
    message("::set-output name=mime_type::${PACKAGE_MIME}")
if (${PROJECT_TARGET} STREQUAL "TARGET_RT1051")
    set(PACKAGE_STANDALONE_FILE_NAME ${PACKAGE_COMMON_NAME}-Standalone.zip)
    set(PACKAGE_STANDALONE_MIME "application/zip")
    add_custom_target(package-update-staged
        COMMAND ${CMAKE_CPACK_COMMAND}
        -C $<CONFIGURATION>
        --config ${CPACK_OUTPUT_CONFIG_FILE}
        DEPENDS ecoboot.bin version.json
    )
    add_custom_target(package-standalone
        COMMAND zip -rq ${CMAKE_BINARY_DIR}/${PACKAGE_STANDALONE_FILE_NAME} "."
        WORKING_DIRECTORY ${PACKAGE_STAGING_DIRECTORY}/Standalone
        DEPENDS ${ECOBOOT_FILE} package-standalone-staged  PurePhone
        )
    set(UPDATE_STAGING_DIRECTORY ${PACKAGE_STAGING_DIRECTORY}/Update)
    add_custom_target(package-update-checksums
        COMMAND rhash
        -u checksums.txt
        -r .
        WORKING_DIRECTORY ${UPDATE_STAGING_DIRECTORY}
        DEPENDS package-update-staged
        )
    set(PACKAGE_UPDATE_FILE_NAME ${PACKAGE_COMMON_NAME}-Update.tar)
    set(PACKAGE_UPDATE_MIME "application/x-tar")
    add_custom_target(package-update
        COMMAND tar
        -cf ${CMAKE_BINARY_DIR}/${PACKAGE_UPDATE_FILE_NAME}
        -C ${PACKAGE_STAGING_DIRECTORY}/Update "."
        DEPENDS ecoboot.bin version.json PurePhone package-update-staged package-update-checksums
        )
elseif (${PROJECT_TARGET} STREQUAL "TARGET_Linux")
    set(PACKAGE_STANDALONE_FILE_NAME ${PACKAGE_COMMON_NAME}-Standalone.tar.gz)
    set(PACKAGE_STANDALONE_MIME "application/x-compressed-tar")
    add_custom_target(package-standalone
        COMMAND tar
        -czf ${CMAKE_BINARY_DIR}/${PACKAGE_STANDALONE_FILE_NAME}
        -C ${PACKAGE_STAGING_DIRECTORY}/Standalone "."
        DEPENDS package-standalone-staged
        )
endif()

if (NOT "$ENV{GITHUB_WORKSPACE}" STREQUAL "")
    message("set-output name=package-standalone::${PACKAGE_STANDALONE_FILE_NAME}")
    message("::set-output name=package-standalone::${PACKAGE_STANDALONE_FILE_NAME}")
    message("set-output name=standalone-mime_type::${PACKAGE_STANDALONE_MIME}")
    message("::set-output name=standalone-mime_type::${PACKAGE_STANDALONE_MIME}")

    message("set-output name=package-update::${PACKAGE_UPDATE_FILE_NAME}")
    message("::set-output name=package-update::${PACKAGE_UPDATE_FILE_NAME}")
    message("set-output name=update-mime_type::${PACKAGE_UPDATE_MIME}")
    message("::set-output name=update-mime_type::${PACKAGE_UPDATE_MIME}")

endif()

M LICENSE.md => LICENSE.md +2 -0
@@ 3,6 3,8 @@
MuditaOS – https://github.com/mudita/MuditaOS
Copyright (c) 2017-2021, Mudita Sp. z o.o. All rights reserved.

MuditaOS is licensed under GNU GPLv3.

## Sources of Intellectual Property Included in MuditaOS

Where not otherwise indicated, all MuditaOS content is authored by Mudita engineers and consists of Mudita-owned intellectual property. In some specific instances, MuditaOS will incorporate work done by developers outside of Mudita with their expressed permission.

M changelog.md => changelog.md +3 -1
@@ 29,7 29,9 @@
### Added

* Add hardware in the loop tests.
* Add empty APN settings window.
* Add APN settings window.
* Add New/Edit APN window
* Add APN options window

### Changed


A config/GenUpdateVersionJson.cmake => config/GenUpdateVersionJson.cmake +21 -0
@@ 0,0 1,21 @@
# This script generates the version.json file which contains project
# and bootloader version information for update packages . It is meant to be run
# at build time by running CMake as a target.

list(APPEND CMAKE_MODULE_PATH "${SRC_DIR}/config")
include(Version)

set(BOOTLOADER_INCLUDED "true")
set(BOOTLOADER_FILENAME "ecoboot.bin")
execute_process(
    COMMAND grep "release:" "${ECOBOOT_DOWNLOAD_LOG}"
    COMMAND awk "{print $2}"
    OUTPUT_VARIABLE BOOTLOADER_VERSION
    OUTPUT_STRIP_TRAILING_WHITESPACE
)

configure_file(
    ${SRC_DIR}/config/version.json.cmake_template
    ${CMAKE_BINARY_DIR}/version.json
    @ONLY
    )

A config/GenVersionHpp.cmake => config/GenVersionHpp.cmake +14 -0
@@ 0,0 1,14 @@
# This script generates the source/version.hpp containing project version
# information. It is meant to be run at build time by running CMake as a target.

list(APPEND CMAKE_MODULE_PATH "${SRC_DIR}/config")
include(Version)

configure_file(
    ${SRC_DIR}/source/version.hpp.template
    ${CMAKE_BINARY_DIR}/source/version.hpp
    )

message("GIT_REV: ${GIT_REV}")
message("GIT_TAG: ${GIT_TAG}")
message("Version: ${CMAKE_PROJECT_VERSION}")

M config/ProjectConfig.cmake => config/ProjectConfig.cmake +12 -1
@@ 26,15 26,26 @@ else()
    set (LOG_LUART_ENABLED 0 CACHE INTERNAL "")
endif()

# add Mudita USB Vendor/Product IDs
option(MUDITA_USB_ID "Enables using Mudita registered USB Vendor ID and Pure Phone USB Product ID" OFF)
if (MUDITA_USB_ID)
    set (USB_DEVICE_VENDOR_ID  0x3310 CACHE INTERNAL "Sets USB_DEVICE_VENDOR_ID to Mudita Vendor ID")
    set (USB_DEVICE_PRODUCT_ID 0x0100 CACHE INTERNAL "Sets USB_DEVICE_PRODUCT_ID to Mudita Pure Product ID")
else()
    set (USB_DEVICE_VENDOR_ID  0x045E CACHE INTERNAL "Sets USB_DEVICE_VENDOR_ID to Microsoft Vendor ID")
    set (USB_DEVICE_PRODUCT_ID 0x0622 CACHE INTERNAL "Sets USB_DEVICE_PRODUCT_ID to Windows MTP Simulator Product ID")
endif()

#Config options described in README.md
set(PROJECT_CONFIG_DEFINITIONS

        LOG_USE_COLOR=${LOG_USE_COLOR}
        LOG_REDIRECT=${LOG_REDIRECT}
        SYSTEM_VIEW_ENABLED=${SYSTEM_VIEW_ENABLED}
        USBCDC_ECHO_ENABLED=${USBCDC_ECHO_ENABLED}
        LOG_LUART_ENABLED=${LOG_LUART_ENABLED}
        PROJECT_CONFIG_USER_DYNMEM_SIZE=9*1024*1024
        USB_DEVICE_VENDOR_ID=${USB_DEVICE_VENDOR_ID}
        USB_DEVICE_PRODUCT_ID=${USB_DEVICE_PRODUCT_ID}
        CACHE INTERNAL ""
        )


A config/Utils.cmake => config/Utils.cmake +13 -0
@@ 0,0 1,13 @@
# An equivalent of install() which allows to declare multiple components using
# a custom 'COMPONENTS' clause. This clause must be the last on the
# argument list. The original 'COMPONENT' from install() clause must not appear
# on the argument list.  
function(multicomp_install)
    list(FIND ARGN "COMPONENTS" CLAUSE_INDEX)
    list(SUBLIST ARGN 0 ${CLAUSE_INDEX} INSTALL_ARGN)
    math(EXPR COMPS_INDEX "${CLAUSE_INDEX}+1")
    list(SUBLIST ARGN ${COMPS_INDEX} ${ARGC} COMPONENTS)
    foreach(COMP IN LISTS COMPONENTS)
        install(${INSTALL_ARGN} COMPONENT ${COMP})
    endforeach()
endfunction()

M config/Version.cmake => config/Version.cmake +34 -22
@@ 1,9 1,8 @@
# from: https://www.mattkeeter.com/blog/2018-01-06-versioning/
# from: https://www.mattkeeter.com/blog/2018-01-06-versioning/ (modified)

set(VERSION_HEADER "${CMAKE_BINARY_DIR}/source/version.hpp")

execute_process(COMMAND git log --pretty=format:'%h' -n 1
execute_process(COMMAND git rev-parse --short HEAD
                OUTPUT_VARIABLE GIT_REV
                OUTPUT_STRIP_TRAILING_WHITESPACE
                ERROR_QUIET)

if ( NOT SRC_DIR )


@@ 21,38 20,51 @@ else()
    execute_process(
        COMMAND bash -c "git diff --quiet --exit-code || echo +"
        OUTPUT_VARIABLE GIT_DIFF
        OUTPUT_STRIP_TRAILING_WHITESPACE
        WORKING_DIRECTORY ${SRC_DIR}
        )
    execute_process(
        COMMAND git describe --tags
        OUTPUT_VARIABLE GIT_TAG ERROR_QUIET RESULT_VARIABLE ret
        RESULT_VARIABLE ret
        OUTPUT_VARIABLE GIT_TAG  
        OUTPUT_STRIP_TRAILING_WHITESPACE
        WORKING_DIRECTORY ${SRC_DIR}
        ERROR_QUIET
        )
        if(NOT ret EQUAL "0")
            set(GIT_TAG "none")
        endif()
    execute_process(
        COMMAND git rev-parse --abbrev-ref HEAD
        OUTPUT_VARIABLE GIT_BRANCH)

    string(STRIP "${GIT_REV}" GIT_REV)
    string(SUBSTRING "${GIT_REV}" 1 7 GIT_REV)
    string(STRIP "${GIT_DIFF}" GIT_DIFF)
    string(STRIP "${GIT_TAG}" GIT_TAG)
    string(STRIP "${GIT_BRANCH}" GIT_BRANCH)
        OUTPUT_VARIABLE GIT_BRANCH
        OUTPUT_STRIP_TRAILING_WHITESPACE
        )
    execute_process(
        COMMAND uname -r
        OUTPUT_VARIABLE BUILD_HOST
        OUTPUT_STRIP_TRAILING_WHITESPACE
        )
    execute_process(
        COMMAND git config user.name
        OUTPUT_VARIABLE BUILD_USER
        OUTPUT_STRIP_TRAILING_WHITESPACE
        )
    execute_process(
        COMMAND date +%F-%T
        OUTPUT_VARIABLE BUILD_DATE
        OUTPUT_STRIP_TRAILING_WHITESPACE
        )
    execute_process(
        COMMAND grep tskKERNEL_VERSION_NUMBER ${SRC_DIR}/module-os/FreeRTOS/include/task.h
        COMMAND awk "{print $3}"
        COMMAND tr -d "\""
        OUTPUT_VARIABLE KERNEL_VERSION
        OUTPUT_STRIP_TRAILING_WHITESPACE
        )
endif()
message("GIT_REV: ${GIT_REV}")
message("GIT_TAG: ${GIT_TAG}")

string(REGEX MATCH "release-([0-9]*).([0-9]*).([0-9]*)" VERSION_RAW ${GIT_TAG})

set(CMAKE_PROJECT_VERSION_MAJOR "${CMAKE_MATCH_1}")
set(CMAKE_PROJECT_VERSION_MINOR "${CMAKE_MATCH_2}")
set(CMAKE_PROJECT_VERSION_PATCH "${CMAKE_MATCH_3}")

message("Vession: ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH}")

configure_file(
    ${SRC_DIR}/source/version.hpp.template
    ${CMAKE_BINARY_DIR}/source/version.hpp
    )
set(CMAKE_PROJECT_VERSION "${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH}")

A config/version.json.cmake_template => config/version.json.cmake_template +29 -0
@@ 0,0 1,29 @@
{
	"git":
	{
		"git_branch": "@GIT_BRANCH@",
		"git_commit": "@GIT_REV@",
		"git_tag": "@GIT_TAG@"
	},
	"misc":
	{
		"codename": "@VERSION_CODENAME@",
		"kernel": "@KERNEL_VERSION@",
		"buildon": "@BUILD_HOST@",
		"builddate": "@BUILD_DATE@",
		"builduser": "@BUILD_USER@"
	},
	"version":
	{
		"major": "@CMAKE_PROJECT_VERSION_MAJOR@",
		"minor": "@CMAKE_PROJECT_VERSION_MINOR@",
		"patch": "@CMAKE_PROJECT_VERSION_PATCH@",
		"string": "@CMAKE_PROJECT_VERSION@"
	},
	"bootloader":
	{
		"included": "@BOOTLOADER_INCLUDED@",
		"version": "@BOOTLOADER_VERSION@",
		"filename": "@BOOTLOADER_FILENAME@"
	}
}

M doc/development_workflow.md => doc/development_workflow.md +10 -9
@@ 15,18 15,19 @@ Each commit that makes it from your branch or fork into the master branch must h
If you're part of the MuditaOS core development team, your commit's title *must* start with a Jira ticket number in square brackets e.g. `[EGD-5555]`. 

Commits from the community will be accompanied by a relevant Jira ticket number during the merge. Don't add commits that are out of the scope of the Jira issue you are working on.
You should have exactly one commit in a single PR.

Your commit's subject line should be a single sentence describing what you are changing using present simple tense and an imperative mood. Please follow these rules:

- It must start with one of the following verbs: "Add", "Change" or "Fix", depending on whether you are adding a new feature, changing its behavior, or fixing it. This sentence will be a part of the project changelog, so please ensure it will be clear to the non-technical readers. 
- It must start with a verb. This sentence will be a part of the project changelog, so please ensure it will be clear to the non-technical readers. 
- If you are adding a new feature start with "Add"; start with "Fix" if you are fixing one.
- Don't use proper names such as names of classes or functions. 
- Try to be as concise as possible in the limit of 72 characters (including the Jira ticket number - 11 characters). 
- Don't end the subject line with a period. 

Then, in the commit message, you must include a short description of what the commit is changing in the project. You should be clear about
your motivation to do the change and how it influences the project.

If it's impossible to provide any of the above information, then your commit is likely excessive or redundant and should be squashed with another commit.
Focus more on *why* than *how*.

An example of a correctly formatted commit:
```


@@ 50,13 51,13 @@ You can add a commit template and hook that will help with proper defining both 

Before submitting a Pull Request please go through some basic checks:

- test your changes on both Linux and RT1051 platforms (please pay special attention to the things you might break unintentionally, e.g. when working on calling funcionality, check call log too)
- [include changelog description](changelog_howto.md) (if applicable),
- test your changes on both Linux and RT1051 platforms (please pay special attention to the things you might break unintentionally, e.g. when working on calling, check call log too,
- run unit tests (`make check`),
- [run static analysis](static_analysis.md)
- check if your code formatting complies with [`.clang-format`](../clang-format),
- whenever you add a third party software to MuditaOS source code, please make sure that the software component is added to a dedicated [section in `LICENSE.md` file on MuditaOS GitHub repository](../LICENSE.md) with a link to the text of the license where applicable.
- whenever you add third-party software to MuditaOS source code, please make sure that the software component is added to a dedicated [section in `LICENSE.md` file on MuditaOS GitHub repository](../LICENSE.md) with a link to the text of the license where applicable.

As a part of our continuous integration proccess we will be soon introducing our own [test harness](../test/README.md).
As a part of our continuous integration process we will be soon introducing our own [test harness](../test/README.md).

## Submit a Pull Request



@@ 78,7 79,7 @@ During a PR review, team members will ask you questions regarding your solution.

## PR review - act on feedback

Add changes to your PR that are requested by reviewers and push the feature branch once again. Update comments requesting changes with a simple `Done`. Don't resolve discussion on your own, it's the reviewer's responsibility to do so.
Add changes to your PR that are requested by reviewers and push the feature branch once again. Update comments requesting changes with a simple `Done`. Don't resolve a discussion on your own, it's the reviewer's responsibility to do so.

## Merge to `master` branch



@@ 110,7 111,7 @@ git rebase origin/master  # update branch you are at to origin/master

`Rebase` changes your commit history (moves them on top). This means two things:

 - when you did a lot of changes in a lot of places - either `git push` your branch on server, or make its copy
 - when you did a lot of changes in a lot of places - either `git push` your branch to the server, or make its copy
 - when you're happy of `git rebase` results - you'll need to push your branch with force to server - since you've changed its history (updated it) 

A minimal set of commands:

M doc/quickstart.md => doc/quickstart.md +3 -3
@@ 148,14 148,14 @@ To fix the style for Pull Request CI:

### Commit message template

To add commit message template use this command:
To add a commit message template use this command:

```bash
git config commit.template .gitmessage
```

This way each time you add new commit you will see template that will help
you with proper message format. More about that in (Development Workflow)[./doc/development_workflow.md#commit-changes]
This way each time you add a new commit you will see the template that will help
you with the proper message format. More about that in (Development Workflow)[./doc/development_workflow.md#commit-changes]

### Commit message hook
This hooks automatically converts your branch name to commit title

A doc/static_analysis.md => doc/static_analysis.md +31 -0
@@ 0,0 1,31 @@
# Static code analysis

The Static code analysis is a method of debugging that is done by examining the source code without executing the program.

Before submitting the Pull Request a developer should run static code analyzer tool and make sure that his code complies with the Coding Standards.

## Clang-tidy

The clang-tidy is a clang-based C++ “linter” tool. Its purpose is to provide an extensible framework for diagnosing and fixing typical programming errors, like style violations, interface misuse, or bugs that can be deduced via static analysis.

### Install clang-tidy

#### Linux Ubuntu

The clang-tidy tool is available from the APT repository.

`$ sudo apt install clang-tidy`

### Run clang-tidy

If `run-clang-tidy` program is installed, a CMake target called `clang-tidy` is available.

In order to run `clang-tidy` analyzer on the MuditaOS repository, follow the steps:
```
$ cd <path/to/MuditaOS>
$ ./configure.sh <platform> <build_type>
$ cd <path/to/build/dir>
$ make clang-tidy
```

The results of the analysis are available under `$(pwd)/StaticAnalysis` directory.

M host-tools/CMakeLists.txt => host-tools/CMakeLists.txt +11 -2
@@ 6,9 6,18 @@ if (CMAKE_CROSSCOMPILING)
        COMMAND ${CMAKE_COMMAND}
        -DCMAKE_BUILD_TYPE:STRING="Release"
        -DCMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE:PATH="${CMAKE_BINARY_DIR}"
        -B"build"
        -B"lfsfuse"
        -H"${CMAKE_SOURCE_DIR}/host-tools/littlefs-fuse"
        COMMAND ${CMAKE_COMMAND} --build build --config Release
        COMMAND ${CMAKE_COMMAND} --build lfsfuse --config Release
    )
    add_custom_target(
        genlittlefs ALL
        COMMAND ${CMAKE_COMMAND}
        -DCMAKE_BUILD_TYPE:STRING="Release"
        -DCMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE:PATH="${CMAKE_BINARY_DIR}"
        -B"genlittlefs"
        -H"${CMAKE_SOURCE_DIR}/host-tools/genlittlefs"
        COMMAND ${CMAKE_COMMAND} --build genlittlefs --config Release
    )
else()
    set(_genlittlefs "${CMAKE_BINARY_DIR}/genlittlefs${CMAKE_EXECUTABLE_SUFFIX}")

M host-tools/genlittlefs/CMakeLists.txt => host-tools/genlittlefs/CMakeLists.txt +7 -0
@@ 5,6 5,13 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake" ${CMAKE_MODULE_PATH})

find_package(BLKID REQUIRED)

# only add LittleFS subdirectory during a standalone config of genlittlefs
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
    add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../module-vfs/thirdparty/lfsfs
        ${CMAKE_CURRENT_BINARY_DIR}/lfsfs EXCLUDE_FROM_ALL
    )
endif()

set(GENLITTLEFS_SRCS
    mklfs.c
    parse_partitions.c

M host-tools/genlittlefs/mklfs.c => host-tools/genlittlefs/mklfs.c +2 -2
@@ 186,7 186,7 @@ static int add_to_lfs(lfs_t *lfs, const char *dir, struct lfs_info_summary *summ
        tgt_dir[0] = '/';
        strcpy(tgt_dir + 1, sep_ptr + 1);
    }
    int err;
    int err = 0;
    if (is_dir) {
        err = create_dir_in_lfs(lfs, tgt_dir, verbose);
        if (err) {


@@ 240,7 240,7 @@ static void configure_lfs_params(struct lfs_config *lfsc, const struct littlefs_
int main(int argc, char **argv)
{

    int err;
    int err = 0;
    struct littlefs_opts lopts;
    struct lfs_config cfg;
    struct lfs_info_summary prog_summary;

M image/CMakeLists.txt => image/CMakeLists.txt +12 -3
@@ 1,4 1,6 @@
set(ASSETS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
include(Utils)

set(ASSETS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(ASSETS_DEST_DIR "${CMAKE_BINARY_DIR}")

file (GLOB_RECURSE ASSETS_LIST


@@ 16,10 18,17 @@ foreach(ASSET ${ASSETS_LIST})

    if(dir)
        set(destdir "${ASSETS_DEST_DIR}/${dir}")
        install(FILES ${ASSET} DESTINATION ${dir})
        multicomp_install(
            FILES ${ASSET}
            DESTINATION ${dir}
            COMPONENTS Standalone Update
            )
    else()
        set(destdir "${ASSETS_DEST_DIR}")
        install(FILES ${ASSET} DESTINATION "./" )
        multicomp_install(
            FILES ${ASSET}
            DESTINATION "./"
            COMPONENTS Standalone Update)
    endif()

    set(outfile "${destdir}/${filename}")

M image/assets/lang/Deutsch.json => image/assets/lang/Deutsch.json +1 -0
@@ 38,6 38,7 @@
  "common_yesterday": "Yesterday",
  "common_today": "Today",
  "locale_12hour_min": "%I:%M %p",
  "locale_12hour_min_short": "%I:%M",
  "locale_24hour_min": "%H:%M",
  "locale_date_full": "%m/%d/%y",
  "locale_date_short": "%d/%m",

M image/assets/lang/English.json => image/assets/lang/English.json +25 -4
@@ 62,6 62,7 @@
  "common_search": "SEARCH",
  "common_empty_list": "Default Info: No elements on list.",
  "locale_12hour_min": "%I:%M %p",
  "locale_12hour_min_short": "%I:%M",
  "locale_24hour_min": "%H:%M",
  "locale_date_full": "%m/%d/%y",
  "locale_date_short": "%d/%m",


@@ 299,12 300,17 @@
  "app_settings_display_input_language": "Input language",
  "app_settings_display_locked_screen_autolock": "Autolock",
  "app_settings_display_locked_screen_wallpaper": "Wallpaper",
  "app_settings_display_locked_screen_quotes": "Quotes",
  "app_settings_display_locked_screen_new_quote": "New quote",
  "app_settings_display_wallpaper_logo": "Mudita logo",
  "app_settings_display_wallpaper_clock": "Clock",
  "app_settings_display_wallpaper_quotes": "Quotes",
  "app_settings_display_wallpaper_select_quotes": "Select Quotes",
  "app_settings_display_wallpaper_quotes_options": "Options",
  "app_settings_display_wallpaper_quotes_edit": "Edit quote",
  "app_settings_display_wallpaper_quotes_delete": "Delete quote",
  "app_settings_display_wallpaper_quotes_new": "New quote",
  "app_settings_display_wallpaper_quotes_select": "Select quotes",
  "app_settings_display_wallpaper_quotes_delete_confirmation": "Delete quote?",
  "app_settings_display_wallpaper_quotes_quote": "Quote text",
  "app_settings_display_wallpaper_quotes_author": "Quote author",
  "app_settings_system": "System",
  "app_settings_apps_tools": "Apps and tools",
  "app_settings_apps_messages": "Messages",


@@ 328,6 334,9 @@
  "app_settings_phone_modes": "Phone Modes",
  "app_settings_security": "Security",
  "app_settings_language": "Language",
  "app_settings_factory_reset": "Factory reset",
  "app_settings_about_your_pure": "About your Pure",
  "app_settings_certification": "Certification",
  "app_settings_about": "About Mudita Pure",
  "app_settings_title_languages": "Language Selection",
  "app_settings_language_english": "English",


@@ 343,7 352,6 @@
  "app_settings_network_sim_none": "No Sim",
  "app_settings_network_voice_over_lte" : "VoLTE (experimental)",
  "app_settings_network_apn_settings" : "APN settings",
  "app_settings_network_apn_settings_no_apns" : "<text align='center' color='9'>No APNs yet.<p>Press <b>left arrow</b> to add new.</p></text>",
  "app_settings_toggle_on": "ON",
  "app_settings_toggle_off": "OFF",
  "app_settings_security_lock_screen_passcode": "Lock screen passcode",


@@ 354,6 362,19 @@
  "app_settings_security_wrong_passcode": "Wrong passcode!",
  "app_settings_security_passcode_changed_successfully": "Passcode changed successfully!",
  "app_settings_security_passcode_disabled": "Passcode disabled!",
  "app_settings_apn_settings_no_apns" : "<text align='center' color='9'>No APNs yet.<p>Press <b>left arrow</b> to add new.</p></text>",
  "app_settings_apn_options" : "Options",
  "app_settings_apn_options_delete" : "Delete",
  "app_settings_apn_options_edit" : "Edit",
  "app_settings_apn_options_set_as_default" : "Set as default",
  "app_settings_new_edit_apn": "New/Edit APN",
  "app_settings_apn_name": "Name",
  "app_settings_apn_APN": "APN",
  "app_settings_apn_username": "UserName",
  "app_settings_apn_password": "Password",
  "app_settings_apn_authtype": "Authentication type",
  "app_settings_apn_apntype": "APN Type",
  "app_settings_apn_apnprotocol" : "APN Protocol",
  "app_phonebook_title_main": "Contacts",
  "app_phonebook_search_win_contacts": "Contacts",
  "common_search_uc": "Search",

M image/assets/lang/Espanol.json => image/assets/lang/Espanol.json +1 -0
@@ 38,6 38,7 @@
  "common_yesterday": "Yesterday",
  "common_today": "Today",
  "locale_12hour_min": "%I:%M %p",
  "locale_12hour_min_short": "%I:%M",
  "locale_24hour_min": "%H:%M",
  "locale_date_full": "%m/%d/%y",
  "locale_date_short": "%d/%m",

M image/assets/lang/Francais.json => image/assets/lang/Francais.json +1 -0
@@ 38,6 38,7 @@
  "common_yesterday": "Yesterday",
  "common_today": "Today",
  "locale_12hour_min": "%I:%M %p",
  "locale_12hour_min_short": "%I:%M",
  "locale_24hour_min": "%H:%M",
  "locale_date_full": "%m/%d/%y",
  "locale_date_short": "%d/%m",

M image/assets/lang/Polski.json => image/assets/lang/Polski.json +1 -0
@@ 38,6 38,7 @@
  "common_yesterday": "wczoraj",
  "common_today": "dzisiaj",
  "locale_12hour_min": "%I:%M",
  "locale_12hour_min_short": "%I:%M",
  "locale_24hour_min": "%H:%M",
  "locale_date_full": "%d.%m.%y",
  "locale_date_short": "%d.%m",

A image/user/data/applications/settings/quotes.json => image/user/data/applications/settings/quotes.json +27 -0
@@ 0,0 1,27 @@
[
  {
    "lang":"english",
    "author": "Buddha",
    "quote": "Do not dwell in the past, do not dream of the future, concentrate the mind on the present moment."
  },
  {
    "lang":"english",
    "author": "Tara Brach",
    "quote": "The only way to live is by accepting each minute as an unrepeatable miracle."
  },
  {
    "lang":"english",
    "author": "Richar Bach",
    "quote": "The simplest things are often the truest"
  },
  {
    "lang":"english",
    "author": "Eckhart Tolle",
    "quote": "Always say yes to the present moment. Say yes to life."
  },
  {
    "lang":"english",
    "author": "Naomi Judd",
    "quote": "Slow down, simplify and be kind"
  }
]

M module-apps/Application.cpp => module-apps/Application.cpp +38 -28
@@ 2,31 2,31 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "Application.hpp"
#include "Common.hpp"                                    // for RefreshModes
#include "GuiTimer.hpp"                                  // for GuiTimer
#include "Item.hpp"                                      // for Item
#include "MessageType.hpp"                               // for MessageType
#include "Service/Timer.hpp"                             // for Timer
#include "Timer.hpp"                                     // for Timer
#include "Translator.hpp"                                // for KeyInputSim...
#include "common_data/EventStore.hpp"                    // for Battery
#include "common_data/RawKey.hpp"                        // for RawKey, key...
#include "gui/input/InputEvent.hpp"                      // for InputEvent
#include "log/debug.hpp"                                 // for DEBUG_APPLI...
#include "log/log.hpp"                                   // for LOG_INFO
#include "messages/AppMessage.hpp"                       // for AppSwitchMe...
#include "service-appmgr/Controller.hpp"                 // for Controller
#include "Common.hpp"                    // for RefreshModes
#include "GuiTimer.hpp"                  // for GuiTimer
#include "Item.hpp"                      // for Item
#include "MessageType.hpp"               // for MessageType
#include "Service/Timer.hpp"             // for Timer
#include "Timer.hpp"                     // for Timer
#include "Translator.hpp"                // for KeyInputSim...
#include "common_data/EventStore.hpp"    // for Battery
#include "common_data/RawKey.hpp"        // for RawKey, key...
#include "gui/input/InputEvent.hpp"      // for InputEvent
#include "log/debug.hpp"                 // for DEBUG_APPLI...
#include "log/log.hpp"                   // for LOG_INFO
#include "messages/AppMessage.hpp"       // for AppSwitchMe...
#include "service-appmgr/Controller.hpp" // for Controller
#include <service-cellular/CellularMessage.hpp>
#include <service-evtmgr/BatteryMessages.hpp>
#include <service-evtmgr/Constants.hpp>
#include <service-evtmgr/EVMessages.hpp>
#include "service-gui/messages/DrawMessage.hpp"          // for DrawMessage
#include "task.h"                                        // for xTaskGetTic...
#include "windows/AppWindow.hpp"                         // for AppWindow
#include <Text.hpp>                                      // for Text
#include <algorithm>                                     // for find
#include <iterator>                                      // for distance, next
#include <type_traits>                                   // for add_const<>...
#include "service-gui/messages/DrawMessage.hpp" // for DrawMessage
#include "task.h"                               // for xTaskGetTic...
#include "windows/AppWindow.hpp"                // for AppWindow
#include <Text.hpp>                             // for Text
#include <algorithm>                            // for find
#include <iterator>                             // for distance, next
#include <type_traits>                          // for add_const<>...
#include <WindowsFactory.hpp>
#include <service-gui/Common.hpp>
#include <module-utils/Utils.hpp>


@@ 70,10 70,12 @@ namespace app
                             uint32_t stackDepth,
                             sys::ServicePriority priority)
        : Service(std::move(name), std::move(parent), stackDepth, priority),
          default_window(gui::name::window::main_window), windowsStack(this), startInBackground{startInBackground},
          callbackStorage{std::make_unique<CallbackStorage>()}, settings(std::make_unique<settings::Settings>(this))
          default_window(gui::name::window::main_window), windowsStack(this),
          keyTranslator{std::make_unique<gui::KeyInputSimpleTranslation>()}, startInBackground{startInBackground},
          callbackStorage{std::make_unique<CallbackStorage>()}, topBarManager{std::make_unique<TopBarManager>()},
          settings(std::make_unique<settings::Settings>(this))
    {
        keyTranslator = std::make_unique<gui::KeyInputSimpleTranslation>();
        topBarManager->enableIndicators({gui::top_bar::Indicator::Time});
        busChannels.push_back(sys::BusChannels::ServiceCellularNotifications);

        longPressTimer = std::make_unique<sys::Timer>("LongPress", this, key_timer_ms);


@@ 82,13 84,16 @@ namespace app
        connect(typeid(AppRefreshMessage),
                [this](sys::Message *msg) -> sys::MessagePointer { return handleAppRefresh(msg); });

        settings->registerValueChange(settings::SystemProperties::timeFormat12,
                                      [this](std::string value) { timeFormatChanged(value); });
        settings->registerValueChange(
            settings::SystemProperties::timeFormat12,
            [this](std::string value) { timeFormatChanged(value); },
            settings::SettingsScope::Global);
    }

    Application::~Application() noexcept
    {
        windowsStack.windows.clear();
        settings->unregisterValueChange();
    }

    Application::State Application::getState()


@@ 104,7 109,6 @@ namespace app
        state = st;
    }


    void Application::longPressTimerCallback()
    {
        // TODO if(check widget type long press trigger)


@@ 497,7 501,8 @@ namespace app

        settings->registerValueChange(
            settings::SystemProperties::lockScreenPasscodeIsOn,
            [this](const std::string &value) { setLockScreenPasscodeOn(utils::getNumericValue<bool>(value)); });
            [this](const std::string &value) { setLockScreenPasscodeOn(utils::getNumericValue<bool>(value)); },
            settings::SettingsScope::Global);
        return sys::ReturnCodes::Success;
    }



@@ 694,6 699,11 @@ namespace app
        item->attachTimer(std::move(timer));
    }

    const gui::top_bar::Configuration &Application::getTopBarConfiguration() const noexcept
    {
        return topBarManager->getConfiguration();
    }

    void Application::addActionReceiver(manager::actions::ActionId actionId, OnActionReceived &&callback)
    {
        receivers.insert_or_assign(actionId, std::move(callback));

M module-apps/Application.hpp => module-apps/Application.hpp +4 -0
@@ 25,6 25,7 @@
#include <string>                                       // for string
#include <utility>                                      // for move, pair
#include <vector>                                       // for vector
#include "TopBarManager.hpp"
#include "WindowsFactory.hpp"
#include "WindowsStack.hpp"



@@ 369,6 370,8 @@ namespace app

        void addActionReceiver(manager::actions::ActionId actionId, OnActionReceived &&callback);

        std::unique_ptr<TopBarManager> topBarManager;

        /// application's settings
        std::unique_ptr<settings::Settings> settings;
        virtual void timeFormatChanged(std::string value);


@@ 378,6 381,7 @@ namespace app
        bool isTimeFormat12() const noexcept;
        void setLockScreenPasscodeOn(bool screenPasscodeOn) noexcept;
        bool isLockScreenPasscodeOn() const noexcept;
        const gui::top_bar::Configuration &getTopBarConfiguration() const noexcept;
    };

    /// Parameter pack used by application launch action.

M module-apps/CMakeLists.txt => module-apps/CMakeLists.txt +1 -0
@@ 15,6 15,7 @@ set( SOURCES
    "Application.cpp"
    "GuiTimer.cpp"
    "WindowsFactory.cpp"
    "TopBarManager.cpp"
    "AsyncTask.cpp"
    "CallbackStorage.cpp"
    "windows/AppWindow.cpp"

A module-apps/TopBarManager.cpp => module-apps/TopBarManager.cpp +17 -0
@@ 0,0 1,17 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "TopBarManager.hpp"

namespace app
{
    void TopBarManager::enableIndicators(const gui::top_bar::Indicators &indicators)
    {
        topBarConfiguration.enable(indicators);
    }

    auto TopBarManager::getConfiguration() const noexcept -> const gui::top_bar::Configuration &
    {
        return topBarConfiguration;
    }
} // namespace app

A module-apps/TopBarManager.hpp => module-apps/TopBarManager.hpp +19 -0
@@ 0,0 1,19 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <TopBar.hpp>

namespace app
{
    class TopBarManager
    {
      public:
        void enableIndicators(const gui::top_bar::Indicators &indicators);
        [[nodiscard]] auto getConfiguration() const noexcept -> const gui::top_bar::Configuration &;

      private:
        gui::top_bar::Configuration topBarConfiguration;
    };
} // namespace app

M module-apps/application-alarm-clock/windows/AlarmClockMainWindow.cpp => module-apps/application-alarm-clock/windows/AlarmClockMainWindow.cpp +0 -1
@@ 32,7 32,6 @@ namespace app::alarmClock
    {
        AppWindow::buildInterface();

        topBar->setActive(gui::TopBar::Elements::TIME, true);
        bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
        bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
        bottomBar->setText(gui::BottomBar::Side::CENTER, utils::localize.get(style::strings::common::Switch));

M module-apps/application-alarm-clock/windows/CustomRepeatWindow.cpp => module-apps/application-alarm-clock/windows/CustomRepeatWindow.cpp +0 -3
@@ 18,9 18,6 @@ namespace app::alarmClock
    {
        AppWindow::buildInterface();

        topBar->setActive(gui::TopBar::Elements::TIME, true);
        topBar->setActive(gui::TopBar::Elements::SIM, false);
        topBar->setActive(gui::TopBar::Elements::NETWORK_ACCESS_TECHNOLOGY, false);
        bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
        bottomBar->setActive(gui::BottomBar::Side::CENTER, true);
        bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

M module-apps/application-alarm-clock/windows/NewEditAlarmWindow.cpp => module-apps/application-alarm-clock/windows/NewEditAlarmWindow.cpp +0 -1
@@ 21,7 21,6 @@ namespace app::alarmClock
    {
        AppWindow::buildInterface();

        topBar->setActive(gui::TopBar::Elements::TIME, true);
        bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
        bottomBar->setActive(gui::BottomBar::Side::CENTER, true);
        bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

M module-apps/application-antenna/windows/AlgoParamsWindow.cpp => module-apps/application-antenna/windows/AlgoParamsWindow.cpp +0 -4
@@ 39,10 39,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::open));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::TIME, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        setTitle(utils::localize.get("app_desktop_tools_antenna"));

        lowBandBox  = new gui::VBox(this,

M module-apps/application-antenna/windows/AntennaMainWindow.cpp => module-apps/application-antenna/windows/AntennaMainWindow.cpp +0 -4
@@ 48,10 48,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::open));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::TIME, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        setTitle(utils::localize.get("app_desktop_tools_antenna"));

        for (auto title : titlesText) {

M module-apps/application-antenna/windows/ScanModesWindow.cpp => module-apps/application-antenna/windows/ScanModesWindow.cpp +0 -4
@@ 37,10 37,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::open));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::TIME, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        setTitle(utils::localize.get("app_desktop_tools_antenna"));

        modeButtonParams.insert(std::pair<uint32_t, std::string>(scanModes::Auto, "AUTO"));

M module-apps/application-calculator/data/CalculatorUtility.cpp => module-apps/application-calculator/data/CalculatorUtility.cpp +70 -0
@@ 15,6 15,9 @@ Result Calculator::calculate(std::string source)
    double result = te_interp(source.c_str(), &error);
    if (error == 0 && !std::isinf(result) && !std::isnan(result)) {
        auto output = utils::to_string(result);
        if (output.length() > CalculatorConstants::maxStringLength) {
            output = getValueThatFitsOnScreen(result);
        }
        if (utils::localize.get("app_calculator_decimal_separator") == style::calculator::symbols::strings::comma) {
            output.replace(output.find(style::calculator::symbols::strings::full_stop),
                           std::size(std::string_view(style::calculator::symbols::strings::full_stop)),


@@ 48,3 51,70 @@ std::string Calculator::replaceAllOccurrences(std::string input, const std::stri
    }
    return input;
}

std::string Calculator::getValueThatFitsOnScreen(double result)
{
    auto base   = static_cast<long long>(result);
    auto length = utils::to_string(base).length();
    if (base < 0) {
        length -= 1;
    }
    if (length > CalculatorConstants::expLength + 1) {
        return convertToNumberWithPositiveExponent(result, length - 1);
    }
    else if (length == CalculatorConstants::expLength + 1) {
        if (result < 0) {
            return utils::to_string(getCoefficient(result, CalculatorConstants::veryLowPrecision));
        }
        return utils::to_string(getCoefficient(result, CalculatorConstants::lowPrecision));
    }
    else if (length == 1 && result < -1) {
        return utils::to_string(getCoefficient(result, CalculatorConstants::lowPrecision));
    }
    else if (result > 1) {
        return utils::to_string(getCoefficient(result, CalculatorConstants::precision));
    }
    else {
        return convertToNumberWithNegativeExponent(result, base);
    }
}

std::string Calculator::convertToNumberWithPositiveExponent(double result, uint32_t exponent)
{
    result /= pow(10, exponent);
    auto exponentLength = utils::to_string(exponent).length();
    auto decimalPlace   = CalculatorConstants::precision - exponentLength - CalculatorConstants::expLength;
    if (result < 0) {
        decimalPlace -= 1;
    }
    return utils::to_string(getCoefficient(result, decimalPlace)) + "e" + utils::to_string(exponent);
}

std::string Calculator::convertToNumberWithNegativeExponent(double result, long long base)
{
    double frac = (result - base) * pow(10, CalculatorConstants::highPrecision);
    if (result < 0) {
        frac *= -1;
    }
    auto fractionalPart = static_cast<unsigned long int>(round(frac));
    auto fracLength     = utils::to_string(fractionalPart).length();
    auto exponent       = CalculatorConstants::highPrecision - fracLength + 1;
    if (exponent > CalculatorConstants::minusExpLength + 1) {
        result *= pow(10, exponent);
        auto exponentLength = utils::to_string(exponent).length();
        auto decimalPlace   = CalculatorConstants::precision - exponentLength - CalculatorConstants::minusExpLength;
        if (result < 0) {
            decimalPlace -= 1;
        }
        return utils::to_string(getCoefficient(result, decimalPlace)) + "e-" + utils::to_string(exponent);
    }
    else if (result < 0) {
        return utils::to_string(getCoefficient(result, CalculatorConstants::lowPrecision));
    }
    return utils::to_string(getCoefficient(result, CalculatorConstants::precision));
}

long double Calculator::getCoefficient(double result, uint32_t precision)
{
    return std::roundl(result * pow(10, precision)) / pow(10, precision);
}

M module-apps/application-calculator/data/CalculatorUtility.hpp => module-apps/application-calculator/data/CalculatorUtility.hpp +15 -0
@@ 4,6 4,17 @@
#pragma once
#include <string>

namespace CalculatorConstants
{
    inline constexpr auto veryLowPrecision = 4;
    inline constexpr auto lowPrecision     = 5;
    inline constexpr auto precision        = 6;
    inline constexpr auto highPrecision    = 8;
    inline constexpr auto expLength        = 1;
    inline constexpr auto minusExpLength   = 2;
    inline constexpr auto maxStringLength  = 7;
} // namespace CalculatorConstants

struct Result
{
    std::string equation;


@@ 18,6 29,10 @@ class Calculator
    /// @return: new string with replaced all occurrences of given string to the new one in whole input
    std::string replaceAllOccurrences(std::string input, const std::string &from, const std::string &to);
    std::string prepareEquationForParser(std::string input);
    std::string getValueThatFitsOnScreen(double result);
    long double getCoefficient(double result, uint32_t precision);
    std::string convertToNumberWithPositiveExponent(double result, uint32_t exponent);
    std::string convertToNumberWithNegativeExponent(double result, long long base);

  public:
    Result calculate(std::string source);

M module-apps/application-calculator/tests/CalculatorUtility_tests.cpp => module-apps/application-calculator/tests/CalculatorUtility_tests.cpp +47 -0
@@ 103,4 103,51 @@ TEST_CASE("Calculator utilities")
        REQUIRE(result.equation == "1.79769e+308*2");
        REQUIRE(result.isError);
    }

    SECTION("Round to fit in screen")
    {
        auto result = calculator.calculate("1.1234512345");
        REQUIRE(result.value == "1.123451");
        REQUIRE(!result.isError);

        result = calculator.calculate("0.0567891");
        REQUIRE(result.value == "0.056789");
        REQUIRE(!result.isError);

        result = calculator.calculate("-0.056789");
        REQUIRE(result.value == "-0.05679");
        REQUIRE(!result.isError);

        result = calculator.calculate("15.556789");
        REQUIRE(result.value == "15.55679");
        REQUIRE(!result.isError);
    }

    SECTION("Change to scientific notation (number > 0)")
    {
        auto result = calculator.calculate("12345.55555");
        REQUIRE(result.value == "1.2346e4");
        REQUIRE(!result.isError);
    }

    SECTION("Change to scientific notation (number < 0)")
    {
        auto result = calculator.calculate("-12345.55555");
        REQUIRE(result.value == "-1.235e4");
        REQUIRE(!result.isError);
    }

    SECTION("Change to scientific notation (0 < number < 1)")
    {
        auto result = calculator.calculate("0.000456712");
        REQUIRE(result.value == "4.567e-4");
        REQUIRE(!result.isError);
    }

    SECTION("Change to scientific notation (-1 < number < 0)")
    {
        auto result = calculator.calculate("-0.000456712");
        REQUIRE(result.value == "-4.57e-4");
        REQUIRE(!result.isError);
    }
}

M module-apps/application-calculator/widgets/CalculatorStyle.hpp => module-apps/application-calculator/widgets/CalculatorStyle.hpp +1 -0
@@ 34,6 34,7 @@ namespace style::calculator
            inline constexpr auto full_stop      = 0x002E;
            inline constexpr auto comma          = 0x002C;
            inline constexpr auto equals         = 0x003D;
            inline constexpr auto zero           = 0x0030;
        } // namespace codes

        namespace strings

M module-apps/application-calculator/windows/CalculatorMainWindow.cpp => module-apps/application-calculator/windows/CalculatorMainWindow.cpp +42 -7
@@ 63,8 63,15 @@ namespace gui
            if (!event.isShortPress()) {
                return false;
            }
            if (event.is(gui::KeyCode::KEY_0) && mathOperationInput->getText() == "0") {
                return true;
            }
            auto lastChar         = mathOperationInput->getText()[mathOperationInput->getText().length() - 1];
            bool lastCharIsSymbol = isSymbol(lastChar);
            if (lastChar == style::calculator::symbols::codes::zero && isSymbol(getPenultimate()) &&
                !isDecimalSeparator(getPenultimate()) && event.is(gui::KeyCode::KEY_0)) {
                return true;
            }
            if (event.keyCode == gui::KeyCode::KEY_UP) {
                writeEquation(lastCharIsSymbol, style::calculator::symbols::strings::plus);
                return true;


@@ 89,6 96,15 @@ namespace gui
                }
                return true;
            }
            if (lastChar == style::calculator::symbols::codes::zero && isSymbol(getPenultimate()) &&
                !isDecimalSeparator(getPenultimate()) && !event.is(gui::KeyCode::KEY_0) &&
                !event.is(gui::KeyCode::KEY_PND) && !event.is(gui::KeyCode::KEY_ENTER)) {
                mathOperationInput->removeChar();
                return false;
            }
            if (!event.is(gui::KeyCode::KEY_0) && mathOperationInput->getText() == "0") {
                mathOperationInput->clear();
            }
            return false;
        };
    }


@@ 103,21 119,36 @@ namespace gui
               character == style::calculator::symbols::codes::full_stop;
    }

    bool CalculatorMainWindow::isDecimalSeparator(uint32_t character)
    {
        return character == style::calculator::symbols::codes::comma ||
               character == style::calculator::symbols::codes::full_stop;
    }

    uint32_t CalculatorMainWindow::getPenultimate()
    {
        if (mathOperationInput->getText().length() > 1) {
            return mathOperationInput->getText()[mathOperationInput->getText().length() - 2];
        }
        return 0;
    }

    void CalculatorMainWindow::writeEquation(bool lastCharIsSymbol, const UTF8 &symbol)
    {
        if (!mathOperationInput->getText().empty()) {

            if (lastCharIsSymbol && symbol != style::calculator::symbols::strings::minus) {
                mathOperationInput->setRichText(
                    std::string(mathOperationInput->getText()).erase(mathOperationInput->getText().length() - 1) +
                    symbol.c_str());
                if (!isSymbol(getPenultimate()) && mathOperationInput->getText().length() > 1) {
                    mathOperationInput->removeChar();
                    mathOperationInput->addText(symbol);
                }
            }
            else {
                mathOperationInput->setRichText(mathOperationInput->getText() + symbol);
                mathOperationInput->addText(symbol);
            }
        }
        else if (symbol == style::calculator::symbols::strings::minus) {
            mathOperationInput->setRichText(mathOperationInput->getText() + symbol);
            mathOperationInput->addText(symbol);
        }
    }



@@ 126,7 157,11 @@ namespace gui
        if (!mathOperationInput->getText().empty()) {
            std::vector<int> symbolsIndexes;
            auto input = std::string(mathOperationInput->getText()).erase(mathOperationInput->getText().length() - 1);
            symbolsIndexes.push_back(input.find_last_of(style::calculator::symbols::strings::minus));
            auto exponentIndex = input.find_last_of('e');
            auto minusIndex    = input.find_last_of(style::calculator::symbols::strings::minus);
            if (minusIndex != exponentIndex + 1) {
                symbolsIndexes.push_back(minusIndex);
            }
            symbolsIndexes.push_back(input.find_last_of(style::calculator::symbols::strings::plus));
            symbolsIndexes.push_back(input.find_last_of(style::calculator::symbols::strings::division));
            symbolsIndexes.push_back(input.find_last_of(style::calculator::symbols::strings::multiplication));


@@ 156,7 191,7 @@ namespace gui

        if (inputEvent.keyCode == gui::KeyCode::KEY_ENTER) {
            auto result = Calculator().calculate(std::string(mathOperationInput->getText()));
            mathOperationInput->setRichText(result.value);
            mathOperationInput->setText(result.value);
            clearInput = result.isError;
            return true;
        }

M module-apps/application-calculator/windows/CalculatorMainWindow.hpp => module-apps/application-calculator/windows/CalculatorMainWindow.hpp +2 -0
@@ 22,6 22,8 @@ namespace gui
        void applyInputCallback();
        bool isPreviousNumberDecimal();
        bool isSymbol(uint32_t character);
        bool isDecimalSeparator(uint32_t character);
        uint32_t getPenultimate();

      public:
        CalculatorMainWindow(app::Application *app, std::string name);

M module-apps/application-calendar/ApplicationCalendar.cpp => module-apps/application-calendar/ApplicationCalendar.cpp +1 -1
@@ 147,7 147,7 @@ namespace app
    void ApplicationCalendar::destroyUserInterface()
    {}

    void ApplicationCalendar::switchToNoEventsWindow(const std::string &title, const TimePoint &dateFilter)
    void ApplicationCalendar::switchToNoEventsWindow(const std::string &title, const calendar::TimePoint &dateFilter)
    {
        if (equivalentWindow == EquivalentWindow::DayEventsWindow) {
            popToWindow(gui::name::window::main_window);

M module-apps/application-calendar/ApplicationCalendar.hpp => module-apps/application-calendar/ApplicationCalendar.hpp +2 -1
@@ 55,7 55,8 @@ namespace app
        }
        void createUserInterface() override;
        void destroyUserInterface() override;
        void switchToNoEventsWindow(const std::string &title = "", const TimePoint &dateFilter = TimePoint());
        void switchToNoEventsWindow(const std::string &title              = "",
                                    const calendar::TimePoint &dateFilter = calendar::TimePoint());

        static const std::map<Reminder, const char *> reminderOptions;
        static const std::map<Repeat, const char *> repeatOptions;

M module-apps/application-calendar/data/CalendarData.hpp => module-apps/application-calendar/data/CalendarData.hpp +3 -3
@@ 42,7 42,7 @@ class DayMonthData : public gui::SwitchData
{
  protected:
    std::string dayMonth;
    TimePoint dateFilter;
    calendar::TimePoint dateFilter;

  public:
    DayMonthData()          = default;


@@ 52,12 52,12 @@ class DayMonthData : public gui::SwitchData
        return dayMonth;
    };

    TimePoint getDateFilter()
    calendar::TimePoint getDateFilter()
    {
        return dateFilter;
    };

    virtual void setData(std::string dayMonthText, const TimePoint &dateNumb)
    virtual void setData(std::string dayMonthText, const calendar::TimePoint &dateNumb)
    {
        dayMonth   = dayMonthText;
        dateFilter = dateNumb;

M module-apps/application-calendar/data/dateCommon.hpp => module-apps/application-calendar/data/dateCommon.hpp +35 -35
@@ 9,13 9,13 @@
#include <Utils.hpp>
#include <random>

using namespace std::chrono;
using namespace std::chrono_literals;

using Clock            = system_clock;
using TimePoint        = time_point<Clock>;
using YearMonthDay     = date::year_month_day;
using YearMonthDayLast = date::year_month_day_last;
namespace calendar
{
    using Clock            = std::chrono::system_clock;
    using TimePoint        = std::chrono::time_point<Clock>;
    using YearMonthDay     = date::year_month_day;
    using YearMonthDayLast = date::year_month_day_last;
} // namespace calendar

inline constexpr auto max_month_day = 48;



@@ 43,7 43,7 @@ enum class Repeat
    yearly
};

inline constexpr TimePoint TIME_POINT_INVALID = date::sys_days{date::January / 1 / 1970};
inline constexpr calendar::TimePoint TIME_POINT_INVALID = date::sys_days{date::January / 1 / 1970};
inline constexpr uint32_t yearDigitsNumb = 4, monthDigitsNumb = 2, dayDigitsNumb = 2, HourDigitsNumb = 2,
                          MinDigitsNumb = 2, SecDigitsNumb = 2;



@@ 88,34 88,34 @@ inline time_t GetAsUTCTime(int year, int month, int day, int hour = 0, int minut
    return basetime + GetDiffLocalWithUTCTime();
}

inline TimePoint TimePointFromTimeT(const time_t &time)
inline calendar::TimePoint TimePointFromTimeT(const time_t &time)
{
    return system_clock::from_time_t(time);
    return std::chrono::system_clock::from_time_t(time);
}

inline time_t TimePointToTimeT(const TimePoint &tp)
inline time_t TimePointToTimeT(const calendar::TimePoint &tp)
{
    return system_clock::to_time_t(tp);
    return std::chrono::system_clock::to_time_t(tp);
}

inline TimePoint TimePointNow()
inline calendar::TimePoint TimePointNow()
{
    utils::time::Timestamp timestamp;
    return TimePointFromTimeT(timestamp.getTime());
}

inline std::string TimePointToString(const TimePoint &tp)
inline std::string TimePointToString(const calendar::TimePoint &tp)
{
    return date::format("%F %T", time_point_cast<seconds>(tp));
    return date::format("%F %T", std::chrono::time_point_cast<std::chrono::seconds>(tp));
}

inline auto TimePointToHourMinSec(const TimePoint &tp)
inline auto TimePointToHourMinSec(const calendar::TimePoint &tp)
{
    auto dp = date::floor<date::days>(tp);
    return date::make_time(tp - dp);
}

inline uint32_t TimePointToHour24H(const TimePoint &tp)
inline uint32_t TimePointToHour24H(const calendar::TimePoint &tp)
{
    auto time = TimePointToTimeT(tp);
    utils::time::Timestamp timestamp(time);


@@ 123,7 123,7 @@ inline uint32_t TimePointToHour24H(const TimePoint &tp)
    return hour;
}

inline uint32_t TimePointToMinutes(const TimePoint &tp)
inline uint32_t TimePointToMinutes(const calendar::TimePoint &tp)
{
    auto time = TimePointToTimeT(tp);
    utils::time::Timestamp timestamp(time);


@@ 131,7 131,7 @@ inline uint32_t TimePointToMinutes(const TimePoint &tp)
    return minute;
}

inline TimePoint getFirstWeekDay(const TimePoint &tp)
inline calendar::TimePoint getFirstWeekDay(const calendar::TimePoint &tp)
{
    date::year_month_day yearMonthDay = date::year_month_day{date::floor<date::days>(tp)};
    auto hourV                        = TimePointToHour24H(tp);


@@ 146,12 146,12 @@ inline TimePoint getFirstWeekDay(const TimePoint &tp)
    return finalDateTime;
}

inline std::string TimePointToString(const TimePoint &tp, date::months months)
inline std::string TimePointToString(const calendar::TimePoint &tp, date::months months)
{
    date::year_month_day yearMonthDay     = date::year_month_day{date::floor<date::days>(tp)};
    date::year_month_day yearMonthDayLast = yearMonthDay.year() / yearMonthDay.month() / date::last;

    TimePoint timePoint;
    calendar::TimePoint timePoint;

    if ((static_cast<unsigned>(yearMonthDay.month()) + months.count()) <= 12) {
        if (yearMonthDayLast.day() == yearMonthDay.day()) {


@@ 173,41 173,41 @@ inline std::string TimePointToString(const TimePoint &tp, date::months months)
            timePoint = date::sys_days{yearMonthDay.year() / yearMonthDay.month() / yearMonthDay.day()};
        }
    }
    return date::format("%F %T", time_point_cast<seconds>(timePoint));
    return date::format("%F %T", std::chrono::time_point_cast<std::chrono::seconds>(timePoint));
}

inline std::string TimePointToLocalizedDateString(const TimePoint &tp, const std::string format = "")
inline std::string TimePointToLocalizedDateString(const calendar::TimePoint &tp, const std::string format = "")
{
    auto time = TimePointToTimeT(tp);
    utils::time::Date timestamp(time);
    return timestamp.str(format);
}

inline std::string TimePointToLocalizedTimeString(const TimePoint &tp, const std::string format = "")
inline std::string TimePointToLocalizedTimeString(const calendar::TimePoint &tp, const std::string format = "")
{
    auto time = TimePointToTimeT(tp);
    utils::time::Time timestamp(time);
    return timestamp.str(format);
}

inline TimePoint TimePointFromString(const char *s1)
inline calendar::TimePoint TimePointFromString(const char *s1)
{
    TimePoint tp;
    calendar::TimePoint tp;
    std::istringstream(s1) >> date::parse("%F %T", tp);
    return tp;
}

inline YearMonthDay TimePointToYearMonthDay(const TimePoint &tp)
inline calendar::YearMonthDay TimePointToYearMonthDay(const calendar::TimePoint &tp)
{
    return date::year_month_day{date::floor<date::days>(tp)};
}

inline TimePoint TimePointFromYearMonthDay(const YearMonthDay &ymd)
inline calendar::TimePoint TimePointFromYearMonthDay(const calendar::YearMonthDay &ymd)
{
    return date::sys_days{ymd.year() / ymd.month() / ymd.day()};
}

inline time_t TimePointToMin(const TimePoint &tp)
inline time_t TimePointToMin(const calendar::TimePoint &tp)
{
    auto time     = TimePointToTimeT(tp);
    auto duration = new utils::time::Duration(time);


@@ 215,7 215,7 @@ inline time_t TimePointToMin(const TimePoint &tp)
    return minutes;
}

inline uint32_t TimePointToHour12H(const TimePoint &tp)
inline uint32_t TimePointToHour12H(const calendar::TimePoint &tp)
{
    auto time = TimePointToTimeT(tp);
    utils::time::Timestamp timestamp(time);


@@ 226,7 226,7 @@ inline uint32_t TimePointToHour12H(const TimePoint &tp)
    return hour;
}

inline std::string TimePointToHourString12H(const TimePoint &tp)
inline std::string TimePointToHourString12H(const calendar::TimePoint &tp)
{
    auto hour =
        utils::time::Timestamp(TimePointToTimeT(tp)).get_UTC_date_time_sub_value(utils::time::GetParameters::Hour);


@@ 234,14 234,14 @@ inline std::string TimePointToHourString12H(const TimePoint &tp)
    return utils::to_string(hour12h);
}

inline std::string TimePointToHourString24H(const TimePoint &tp)
inline std::string TimePointToHourString24H(const calendar::TimePoint &tp)
{
    auto hour =
        utils::time::Timestamp(TimePointToTimeT(tp)).get_UTC_date_time_sub_value(utils::time::GetParameters::Hour);
    return utils::to_string(hour);
}

inline std::string TimePointToMinutesString(const TimePoint &tp)
inline std::string TimePointToMinutesString(const calendar::TimePoint &tp)
{
    auto minute       = TimePointToMinutes(tp);
    auto minuteString = std::to_string(minute);


@@ 252,9 252,9 @@ inline std::string TimePointToMinutesString(const TimePoint &tp)
}

// 0: Monday, 1: Tuesday ... 6: Sunday
inline unsigned int WeekdayIndexFromTimePoint(const TimePoint &tp)
inline unsigned int WeekdayIndexFromTimePoint(const calendar::TimePoint &tp)
{
    auto ymw = date::year_month_weekday{floor<date::days>(tp)};
    auto ymw = date::year_month_weekday{std::chrono::floor<date::days>(tp)};
    return ymw.weekday().iso_encoding() - 1;
}


M module-apps/application-calendar/models/AllEventsModel.cpp => module-apps/application-calendar/models/AllEventsModel.cpp +2 -2
@@ 83,8 83,8 @@ auto AllEventsModel::handleQueryResponse(db::QueryResult *queryResult) -> bool
    auto eventShift = app->getEventShift();
    if (eventShift) {
        for (auto &record : records) {
            record.date_from += hours(eventShift);
            record.date_till += hours(eventShift);
            record.date_from += std::chrono::hours(eventShift);
            record.date_till += std::chrono::hours(eventShift);
        }
    }
    return this->updateRecords(std::move(records));

M module-apps/application-calendar/models/DayEventsModel.cpp => module-apps/application-calendar/models/DayEventsModel.cpp +3 -3
@@ 82,8 82,8 @@ auto DayEventsModel::handleQueryResponse(db::QueryResult *queryResult) -> bool
            auto eventShift = app->getEventShift();
            if (eventShift) {
                for (auto &record : records) {
                    record.date_from += hours(eventShift);
                    record.date_till += hours(eventShift);
                    record.date_from += std::chrono::hours(eventShift);
                    record.date_till += std::chrono::hours(eventShift);
                }
            }
            return updateRecords(std::move(records));


@@ 95,7 95,7 @@ auto DayEventsModel::handleQueryResponse(db::QueryResult *queryResult) -> bool
    return false;
}

void DayEventsModel::setFilters(TimePoint from, TimePoint till, const std::string &dayMonth)
void DayEventsModel::setFilters(calendar::TimePoint from, calendar::TimePoint till, const std::string &dayMonth)
{
    this->filterFrom    = from;
    this->filterTill    = till;

M module-apps/application-calendar/models/DayEventsModel.hpp => module-apps/application-calendar/models/DayEventsModel.hpp +3 -3
@@ 15,13 15,13 @@ class DayEventsModel : public app::DatabaseModel<EventsRecord>,
{
    app::Application *application = nullptr;
    std::string dayMonthTitle;
    TimePoint filterFrom = TIME_POINT_INVALID;
    TimePoint filterTill = TIME_POINT_INVALID;
    calendar::TimePoint filterFrom = TIME_POINT_INVALID;
    calendar::TimePoint filterTill = TIME_POINT_INVALID;

  public:
    DayEventsModel(app::Application *app);

    void setFilters(TimePoint from, TimePoint till, const std::string &dayMonth);
    void setFilters(calendar::TimePoint from, calendar::TimePoint till, const std::string &dayMonth);

    bool updateRecords(std::vector<EventsRecord> records) override;
    auto handleQueryResponse(db::QueryResult *) -> bool;

M module-apps/application-calendar/widgets/EventDateItem.cpp => module-apps/application-calendar/widgets/EventDateItem.cpp +3 -3
@@ 149,7 149,7 @@ namespace gui
        return true;
    }

    YearMonthDay EventDateItem::validateDate()
    calendar::YearMonthDay EventDateItem::validateDate()
    {
        auto actualDate = TimePointToYearMonthDay(TimePointNow());
        uint32_t day;


@@ 185,7 185,7 @@ namespace gui
        }
        month = std::clamp(static_cast<unsigned>(month), 1u, static_cast<unsigned>(date::dec));

        YearMonthDayLast max_date = date::year(year) / date::month(month) / date::last;
        calendar::YearMonthDayLast max_date = date::year(year) / date::month(month) / date::last;
        if (day > static_cast<unsigned>(max_date.day())) {
            dayInput->setText(std::to_string(static_cast<unsigned>(max_date.day())));
        }


@@ 194,7 194,7 @@ namespace gui
        return date::year(year) / date::month(month) / date::day(day);
    }

    const YearMonthDay EventDateItem::getChosenDate()
    const calendar::YearMonthDay EventDateItem::getChosenDate()
    {
        return validateDate();
    }

M module-apps/application-calendar/widgets/EventDateItem.hpp => module-apps/application-calendar/widgets/EventDateItem.hpp +2 -2
@@ 24,12 24,12 @@ namespace gui
        void buildInterface();
        void applyItemSpecificProperties(gui::Text *item);
        void applyCallbacks();
        YearMonthDay validateDate();
        calendar::YearMonthDay validateDate();

      public:
        EventDateItem();

        const YearMonthDay getChosenDate();
        const calendar::YearMonthDay getChosenDate();
        // virtual methods from Item
        bool onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim) override;
    };

M module-apps/application-calendar/widgets/EventTimeItem.cpp => module-apps/application-calendar/widgets/EventTimeItem.cpp +3 -3
@@ 433,9 433,9 @@ namespace gui
        }
    }

    TimePoint EventTimeItem::calculateEventTime(YearMonthDay date,
                                                std::chrono::hours hours,
                                                std::chrono::minutes minutes)
    calendar::TimePoint EventTimeItem::calculateEventTime(calendar::YearMonthDay date,
                                                          std::chrono::hours hours,
                                                          std::chrono::minutes minutes)
    {
        return TimePointFromYearMonthDay(date) + hours + minutes;
    }

M module-apps/application-calendar/widgets/EventTimeItem.hpp => module-apps/application-calendar/widgets/EventTimeItem.hpp +3 -1
@@ 43,7 43,9 @@ namespace gui
                                    std::chrono::minutes end_hour,
                                    uint32_t start_minutes,
                                    uint32_t end_minutes);
        TimePoint calculateEventTime(YearMonthDay date, std::chrono::hours hours, std::chrono::minutes minutes);
        calendar::TimePoint calculateEventTime(calendar::YearMonthDay date,
                                               std::chrono::hours hours,
                                               std::chrono::minutes minutes);

      public:
        EventTimeItem(const std::string &description,

M module-apps/application-calendar/widgets/MonthBox.cpp => module-apps/application-calendar/widgets/MonthBox.cpp +1 -1
@@ 58,7 58,7 @@ namespace gui
        auto mainWindow = dynamic_cast<CalendarMainWindow *>(parent);
        if (mainWindow->returnedFromWindow) {
            focusChangedCallback = [=](Item &item) {
                YearMonthDay date = monthFilterValue.year() / monthFilterValue.month() / date::last;
                calendar::YearMonthDay date = monthFilterValue.year() / monthFilterValue.month() / date::last;
                if (unsigned(date.day()) < mainWindow->dayFocusedBefore) {
                    setFocusOnElement(unsigned(date.day()) - 1);
                }

M module-apps/application-calendar/windows/AllEventsWindow.cpp => module-apps/application-calendar/windows/AllEventsWindow.cpp +0 -1
@@ 34,7 34,6 @@ namespace gui
    {
        AppWindow::buildInterface();

        topBar->setActive(gui::TopBar::Elements::TIME, true);
        bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
        bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
        bottomBar->setText(gui::BottomBar::Side::CENTER, utils::localize.get(style::strings::common::open));

M module-apps/application-calendar/windows/AllEventsWindow.hpp => module-apps/application-calendar/windows/AllEventsWindow.hpp +1 -1
@@ 16,7 16,7 @@ namespace gui
        gui::Image *leftArrowImage   = nullptr;
        gui::Image *newDayEventImage = nullptr;

        TimePoint dateFilter                           = TimePointNow();
        calendar::TimePoint dateFilter                 = TimePointNow();
        gui::ListView *allEventsList                   = nullptr;
        std::shared_ptr<AllEventsModel> allEventsModel = nullptr;


M module-apps/application-calendar/windows/CalendarMainWindow.cpp => module-apps/application-calendar/windows/CalendarMainWindow.cpp +8 -8
@@ 100,9 100,9 @@ namespace gui
            }
            case KeyCode::KEY_LEFT: {
                LOG_DEBUG("Call borderCallback -> go to the previous element");
                auto it = monthBox->getNavigationFocusedItem();
                if (monthBox->nextNavigationItem(std::prev(it)) != nullptr) {
                    monthBox->setFocusItem(monthBox->nextNavigationItem(std::prev(it)));
                auto it = std::prev(monthBox->getNavigationFocusedItem());
                if (it != monthBox->children.end() && (*it)->isActive()) {
                    monthBox->setFocusItem(*it);
                }
                else {
                    monthBox->setFocusOnLastElement();


@@ 111,9 111,9 @@ namespace gui
            }
            case KeyCode::KEY_RIGHT: {
                LOG_DEBUG("Call borderCallback -> go to the next element");
                auto it = monthBox->getNavigationFocusedItem();
                if (monthBox->nextNavigationItem(std::next(it)) != nullptr) {
                    monthBox->setFocusItem(monthBox->nextNavigationItem(std::next(it)));
                auto it = std::next(monthBox->getNavigationFocusedItem());
                if (it != monthBox->children.end() && (*it)->isActive()) {
                    monthBox->setFocusItem(*it);
                }
                else {
                    monthBox->setFocusOnElement(0);


@@ 197,8 197,8 @@ namespace gui

    void CalendarMainWindow::filterRequest()
    {
        YearMonthDay date_from = actualDate.year() / actualDate.month() / 1;
        YearMonthDay date_till = date_from + date::months{1};
        calendar::YearMonthDay date_from = actualDate.year() / actualDate.month() / 1;
        calendar::YearMonthDay date_till = date_from + date::months{1};
        auto filter_from       = TimePointFromYearMonthDay(date_from);
        auto filter_till       = TimePointFromYearMonthDay(date_till);
        LOG_DEBUG("filter:  %s", TimePointToString(filter_till).c_str());

M module-apps/application-calendar/windows/CustomRepeatWindow.cpp => module-apps/application-calendar/windows/CustomRepeatWindow.cpp +0 -1
@@ 28,7 28,6 @@ namespace gui
    {
        AppWindow::buildInterface();

        topBar->setActive(gui::TopBar::Elements::TIME, true);
        bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
        bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));


M module-apps/application-calendar/windows/DayEventsWindow.cpp => module-apps/application-calendar/windows/DayEventsWindow.cpp +0 -1
@@ 64,7 64,6 @@ namespace gui
    {
        AppWindow::buildInterface();

        topBar->setActive(gui::TopBar::Elements::TIME, true);
        bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
        bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
        bottomBar->setText(gui::BottomBar::Side::CENTER, utils::localize.get(style::strings::common::open));

M module-apps/application-calendar/windows/DayEventsWindow.hpp => module-apps/application-calendar/windows/DayEventsWindow.hpp +1 -1
@@ 19,7 19,7 @@ namespace gui
    class DayEventsWindow : public gui::AppWindow
    {
        std::string dayMonthTitle;
        TimePoint filterFrom;
        calendar::TimePoint filterFrom;
        gui::Image *leftArrowImage                               = nullptr;
        gui::Image *newDayEventImage                             = nullptr;
        gui::ListView *dayEventsList                             = nullptr;

M module-apps/application-calendar/windows/EventDetailWindow.cpp => module-apps/application-calendar/windows/EventDetailWindow.cpp +0 -1
@@ 28,7 28,6 @@ namespace gui
    {
        AppWindow::buildInterface();

        topBar->setActive(gui::TopBar::Elements::TIME, true);
        bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
        bottomBar->setActive(gui::BottomBar::Side::LEFT, true);
        bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

M module-apps/application-calendar/windows/EventReminderWindow.cpp => module-apps/application-calendar/windows/EventReminderWindow.cpp +11 -4
@@ 38,14 38,21 @@ namespace gui
        buildInterface();
    }

    top_bar::Configuration EventReminderWindow::configureTopBar(top_bar::Configuration appConfiguration)
    {
        using namespace top_bar;
        appConfiguration.enable({Indicator::Signal,
                                 Indicator::Time,
                                 Indicator::Battery,
                                 Indicator::SimCard,
                                 Indicator::NetworkAccessTechnology});
        return appConfiguration;
    }

    void EventReminderWindow::buildInterface()
    {
        AppWindow::buildInterface();

        topBar->setActive(TopBar::Elements::BATTERY, true);
        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(gui::TopBar::Elements::TIME, true);

        bottomBar->setActive(gui::BottomBar::Side::CENTER, true);
        bottomBar->setText(gui::BottomBar::Side::CENTER, utils::localize.get(style::strings::common::ok));
        bottomBar->setBorderColor(ColorNoColor);

M module-apps/application-calendar/windows/EventReminderWindow.hpp => module-apps/application-calendar/windows/EventReminderWindow.hpp +1 -0
@@ 42,6 42,7 @@ namespace gui
        void rebuild() override;
        void buildInterface() override;
        void destroyInterface() override;
        top_bar::Configuration configureTopBar(top_bar::Configuration appConfiguration) override;
        auto handleSwitchData(SwitchData *data) -> bool override;
    };


M module-apps/application-calendar/windows/NewEditEventWindow.cpp => module-apps/application-calendar/windows/NewEditEventWindow.cpp +0 -1
@@ 25,7 25,6 @@ namespace gui
    {
        AppWindow::buildInterface();

        topBar->setActive(gui::TopBar::Elements::TIME, true);
        bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
        bottomBar->setActive(gui::BottomBar::Side::CENTER, true);
        bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

M module-apps/application-call/ApplicationCall.cpp => module-apps/application-call/ApplicationCall.cpp +6 -0
@@ 33,6 33,12 @@ namespace app
    ApplicationCall::ApplicationCall(std::string name, std::string parent, StartInBackground startInBackground)
        : Application(name, parent, startInBackground, app::call_stack_size)
    {
        using namespace gui::top_bar;
        topBarManager->enableIndicators({Indicator::Signal,
                                         Indicator::Time,
                                         Indicator::Battery,
                                         Indicator::SimCard,
                                         Indicator::NetworkAccessTechnology});
        addActionReceiver(manager::actions::Call, [this](auto &&data) {
            switchWindow(window::name_call, std::forward<decltype(data)>(data));
            return msgHandled();

M module-apps/application-call/windows/CallWindow.cpp => module-apps/application-call/windows/CallWindow.cpp +0 -4
@@ 58,10 58,6 @@ namespace gui
    {
        AppWindow::buildInterface();

        topBar->setActive(gui::TopBar::Elements::BATTERY, true);
        topBar->setActive(gui::TopBar::Elements::SIGNAL, true);
        topBar->setActive(gui::TopBar::Elements::TIME, true);

        bottomBar->setActive(BottomBar::Side::CENTER, true);
        bottomBar->setActive(BottomBar::Side::RIGHT, true);


M module-apps/application-call/windows/EnterNumberWindow.cpp => module-apps/application-call/windows/EnterNumberWindow.cpp +0 -4
@@ 58,10 58,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get("common_add"));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get("app_call_clear"));

        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);
        topBar->setActive(TopBar::Elements::TIME, true);

        numberLabel = new gui::Label(this, numberLabel::x, numberLabel::y, numberLabel::w, numberLabel::h);
        numberLabel->setPenWidth(numberLabel::borderW);
        numberLabel->setFont(style::window::font::largelight);

M module-apps/application-calllog/windows/CallLogDetailsWindow.cpp => module-apps/application-calllog/windows/CallLogDetailsWindow.cpp +0 -2
@@ 82,8 82,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::call));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::TIME, true);

        // NOTE: height of all labels is set using decorators

        // Information

M module-apps/application-calllog/windows/CallLogMainWindow.cpp => module-apps/application-calllog/windows/CallLogMainWindow.cpp +0 -2
@@ 47,8 47,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::open));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::TIME, true);

        list = new gui::ListView(this, mainWindow::x, mainWindow::y, mainWindow::w, mainWindow::h, calllogModel);

        setFocusItem(list);

M module-apps/application-desktop/ApplicationDesktop.cpp => module-apps/application-desktop/ApplicationDesktop.cpp +15 -4
@@ 37,6 37,12 @@ namespace app
    ApplicationDesktop::ApplicationDesktop(std::string name, std::string parent, StartInBackground startInBackground)
        : Application(name, parent, startInBackground), lockHandler(this)
    {
        using namespace gui::top_bar;
        topBarManager->enableIndicators({Indicator::Signal,
                                         Indicator::Time,
                                         Indicator::Battery,
                                         Indicator::SimCard,
                                         Indicator::NetworkAccessTechnology});
        busChannels.push_back(sys::BusChannels::ServiceDBNotifications);

        addActionReceiver(app::manager::actions::RequestPin, [this](auto &&data) {


@@ 317,11 323,15 @@ namespace app
            std::make_shared<sdesktop::UpdateOsMessage>(updateos::UpdateMessageType::UpdateCheckForUpdateOnce);
        sys::Bus::SendUnicast(msgToSend, service::name::service_desktop, this);

        settings->registerValueChange(settings::SystemProperties::activeSim,
                                      [this](std::string value) { activeSimChanged(value); });
        settings->registerValueChange(
            settings::SystemProperties::activeSim,
            [this](std::string value) { activeSimChanged(value); },
            settings::SettingsScope::Global);
        Store::GSM::get()->selected = Store::GSM::SIM::NONE;
        settings->registerValueChange(settings::SystemProperties::lockPassHash,
                                      [this](std::string value) { lockPassHashChanged(value); });
        settings->registerValueChange(
            settings::SystemProperties::lockPassHash,
            [this](std::string value) { lockPassHashChanged(value); },
            settings::SettingsScope::Global);

        return sys::ReturnCodes::Success;
    }


@@ 329,6 339,7 @@ namespace app
    sys::ReturnCodes ApplicationDesktop::DeinitHandler()
    {
        LOG_INFO("DeinitHandler");
        settings->unregisterValueChange();
        return sys::ReturnCodes::Success;
    }


M module-apps/application-desktop/data/Style.hpp => module-apps/application-desktop/data/Style.hpp +2 -2
@@ 24,7 24,7 @@ namespace style::desktop
        constexpr auto X     = 0;
        constexpr auto Y     = 106;
        constexpr auto Width = style::window_width;
        constexpr auto Hight = 96;
        constexpr auto Height = 96;

    } // namespace timeLabel



@@ 33,7 33,7 @@ namespace style::desktop
        constexpr auto X     = 0;
        constexpr auto Y     = 204;
        constexpr auto Width = style::window_width;
        constexpr auto Hight = 51;
        constexpr auto Height = 51;

    } // namespace dayLabel


M module-apps/application-desktop/windows/DesktopMainWindow.cpp => module-apps/application-desktop/windows/DesktopMainWindow.cpp +22 -8
@@ 35,19 35,17 @@ namespace gui
        AppWindow::buildInterface();

        bottomBar->setActive(BottomBar::Side::CENTER, true);
        topBar->setActive(
            {{TopBar::Elements::SIGNAL, true}, {TopBar::Elements::LOCK, true}, {TopBar::Elements::BATTERY, true}});

        using namespace style::desktop;

        time = new gui::Label(this, timeLabel::X, timeLabel::Y, timeLabel::Width, timeLabel::Hight);
        time = new gui::Label(this, timeLabel::X, timeLabel::Y, timeLabel::Width, timeLabel::Height);
        time->setFilled(false);
        time->setBorderColor(gui::ColorNoColor);
        time->setFont(style::window::font::supersizemelight);
        time->setText(ttime);
        time->setAlignment(Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Top));

        dayText = new gui::Label(this, dayLabel::X, dayLabel::Y, dayLabel::Width, dayLabel::Hight);
        dayText = new gui::Label(this, dayLabel::X, dayLabel::Y, dayLabel::Width, dayLabel::Height);
        dayText->setFilled(false);
        dayText->setBorderColor(gui::ColorNoColor);
        dayText->setFont(style::window::font::biglight);


@@ 75,6 73,20 @@ namespace gui
        notifications = nullptr;
    }

    top_bar::Configuration DesktopMainWindow::configureTopBar(top_bar::Configuration appConfiguration)
    {
        auto app            = getAppDesktop();
        const auto isLocked = app->lockHandler.isScreenLocked();
        updateTopBarConfiguration(isLocked, appConfiguration);
        return appConfiguration;
    }

    void DesktopMainWindow::updateTopBarConfiguration(bool isScreenLocked, top_bar::Configuration &configuration)
    {
        configuration.set(top_bar::Indicator::Lock, isScreenLocked);
        configuration.set(top_bar::Indicator::Time, !isScreenLocked);
    }

    DesktopMainWindow::DesktopMainWindow(app::Application *app) : AppWindow(app, app::window::name::desktop_main_window)
    {
        buildInterface();


@@ 89,13 101,18 @@ namespace gui
    void DesktopMainWindow::setVisibleState()
    {
        auto app = getAppDesktop();
        applyToTopBar([isLocked = app->lockHandler.isScreenLocked()](top_bar::Configuration configuration) {
            updateTopBarConfiguration(isLocked, configuration);
            return configuration;
        });

        if (app->lockHandler.isScreenLocked()) {
            bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get("app_desktop_unlock"));
            bottomBar->setActive(BottomBar::Side::RIGHT, false);
            bottomBar->setText(BottomBar::Side::LEFT,
                               utils::localize.get("app_desktop_emergency"),
                               app->lockHandler.isScreenBlocked());
            topBar->setActive(TopBar::Elements::LOCK, true);

            inputCallback = nullptr;
            setFocusItem(nullptr);
            buildNotifications(app);


@@ 104,8 121,6 @@ namespace gui
                std::make_shared<TimersProcessingStopMessage>(), service::name::service_time, application);
        }
        else {
            topBar->setActive(TopBar::Elements::LOCK, false);

            if (!buildNotifications(app)) {
                LOG_ERROR("Couldn't fit in all notifications");
            }


@@ 146,7 161,6 @@ namespace gui
            if (inputEvent.is(KeyCode::KEY_PND)) {
                app->lockHandler.lockScreen();
                setVisibleState();
                application->setSuspendFlag(true);
                return true;
            }
            // long press of '0' key is translated to '+'

M module-apps/application-desktop/windows/DesktopMainWindow.hpp => module-apps/application-desktop/windows/DesktopMainWindow.hpp +3 -0
@@ 81,11 81,14 @@ namespace gui
        void rebuild() override;
        void buildInterface() override;
        void destroyInterface() override;
        top_bar::Configuration configureTopBar(top_bar::Configuration appConfiguration) override;

        bool updateTime(const UTF8 &timeStr) override;
        bool updateTime(const uint32_t &timestamp, bool mode24H) override;

      private:
        void invalidate() noexcept;
        static void updateTopBarConfiguration(bool isScreenLocked, top_bar::Configuration &configuration);

        gui::KeyInputMappedTranslation translator;
    };

M module-apps/application-desktop/windows/LockWindow.cpp => module-apps/application-desktop/windows/LockWindow.cpp +0 -1
@@ 14,7 14,6 @@ namespace gui
    void LockWindow::build()
    {
        buildBottomBar();
        buildTopBar();
        buildTitleBar();
        buildInfoTexts();
    }

M module-apps/application-desktop/windows/LockWindow.hpp => module-apps/application-desktop/windows/LockWindow.hpp +0 -1
@@ 58,7 58,6 @@ namespace gui
      protected:
        virtual void buildBottomBar();
        virtual void buildTitleBar() = 0;
        virtual void buildTopBar()   = 0;

      private:
        [[nodiscard]] auto getText(TextType type) noexcept -> gui::Text *;

M module-apps/application-desktop/windows/LockedInfoWindow.cpp => module-apps/application-desktop/windows/LockedInfoWindow.cpp +7 -4
@@ 34,10 34,6 @@ void LockedInfoWindow::setVisibleState()
    bottomBar->setActive(BottomBar::Side::LEFT, true);
    bottomBar->setActive(BottomBar::Side::CENTER, false);
    bottomBar->setActive(BottomBar::Side::RIGHT, true);

    topBar->setActive(TopBar::Elements::LOCK, true);
    topBar->setActive(TopBar::Elements::BATTERY, true);
    topBar->setActive(TopBar::Elements::SIGNAL, true);
}

bool LockedInfoWindow::onInput(const InputEvent &inputEvent)


@@ 61,6 57,13 @@ void LockedInfoWindow::rebuild()
    buildInterface();
}

top_bar::Configuration LockedInfoWindow::configureTopBar(top_bar::Configuration appConfiguration)
{
    appConfiguration.enable(top_bar::Indicator::Lock);
    appConfiguration.disable(top_bar::Indicator::Time);
    return appConfiguration;
}

void LockedInfoWindow::buildInterface()
{
    namespace lock_style = style::window::pin_lock;

M module-apps/application-desktop/windows/LockedInfoWindow.hpp => module-apps/application-desktop/windows/LockedInfoWindow.hpp +1 -0
@@ 25,5 25,6 @@ namespace gui
        void rebuild() override;
        void buildInterface() override;
        void destroyInterface() override;
        top_bar::Configuration configureTopBar(top_bar::Configuration appConfiguration) override;
    };
} /* namespace gui */

M module-apps/application-desktop/windows/MenuWindow.cpp => module-apps/application-desktop/windows/MenuWindow.cpp +0 -3
@@ 149,9 149,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::open));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        auto app = dynamic_cast<app::ApplicationDesktop *>(application);
        assert(app);


M module-apps/application-desktop/windows/MmiPullWindow.cpp => module-apps/application-desktop/windows/MmiPullWindow.cpp +0 -2
@@ 37,8 37,6 @@ MmiPullWindow::MmiPullWindow(app::Application *app, const std::string &name) : g
{
    AppWindow::buildInterface();

    topBar->setActive(TopBar::Elements::TIME, true);
    topBar->setActive(TopBar::Elements::SIM, false);
    bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get("app_desktop_replay"));
    bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
    text = new Text(

M module-apps/application-desktop/windows/MmiPushWindow.cpp => module-apps/application-desktop/windows/MmiPushWindow.cpp +0 -2
@@ 30,8 30,6 @@ namespace style::desktop
MmiPushWindow::MmiPushWindow(app::Application *app, const std::string &name) : gui::AppWindow(app, name)
{
    AppWindow::buildInterface();
    topBar->setActive(TopBar::Elements::TIME, true);
    topBar->setActive(TopBar::Elements::SIM, false);
    bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::ok));
    icon = new Image(this, style::desktop::image::x, style::desktop::image::y, "");
    icon->set("info_big_circle_W_G");

M module-apps/application-desktop/windows/PinLockBaseWindow.cpp => module-apps/application-desktop/windows/PinLockBaseWindow.cpp +6 -7
@@ 32,7 32,12 @@ namespace gui
        }
        return std::string{};
    }

    top_bar::Configuration PinLockBaseWindow::configureTopBar(top_bar::Configuration appConfiguration)
    {
        appConfiguration.enable(top_bar::Indicator::Lock);
        appConfiguration.disable(top_bar::Indicator::Time);
        return appConfiguration;
    }
    void PinLockBaseWindow::restore() noexcept
    {
        LockWindow::restore();


@@ 91,10 96,4 @@ namespace gui
        title->setPenWidth(2);
    }

    void PinLockBaseWindow::buildTopBar()
    {
        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);
        topBar->setActive(TopBar::Elements::LOCK, true);
    }
} // namespace gui

M module-apps/application-desktop/windows/PinLockBaseWindow.hpp => module-apps/application-desktop/windows/PinLockBaseWindow.hpp +3 -1
@@ 12,6 12,9 @@ namespace gui
      public:
        PinLockBaseWindow(app::Application *app, std::string name) : LockWindow(app, name)
        {}

        top_bar::Configuration configureTopBar(top_bar::Configuration appConfiguration) override;

        void buildImages(const std::string &lockImg, const std::string &infoImg);
        [[nodiscard]] auto getToken(Token token) const -> std::string;
        void restore() noexcept override;


@@ 25,6 28,5 @@ namespace gui
      private:
        void buildBottomBar() override;
        void buildTitleBar() override;
        void buildTopBar() override;
    };
} // namespace gui

M module-apps/application-meditation/windows/MeditationListViewWindows.cpp => module-apps/application-meditation/windows/MeditationListViewWindows.cpp +0 -2
@@ 64,7 64,6 @@ void MeditationOptionsWindow::buildInterface()
    MeditationListViewWindow::buildInterface();
    setTitle(utils::localize.get("common_options"));
    bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::Switch));
    topBar->setActive(TopBar::Elements::TIME, true);
}

PreparationTimeWindow::PreparationTimeWindow(app::Application *app)


@@ 79,5 78,4 @@ void PreparationTimeWindow::buildInterface()
    MeditationListViewWindow::buildInterface();
    setTitle(utils::localize.get("app_meditation_preparation_time"));
    bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::select));
    topBar->setActive(TopBar::Elements::TIME, true);
}

M module-apps/application-meditation/windows/MeditationTimerWindow.cpp => module-apps/application-meditation/windows/MeditationTimerWindow.cpp +5 -1
@@ 112,7 112,11 @@ auto MeditationTimerWindow::onInput(const InputEvent &inputEvent) -> bool

void MeditationTimerWindow::setWidgetVisible(bool tBar, bool bBar, bool counter)
{
    topBar->setActive(TopBar::Elements::TIME, tBar);
    applyToTopBar([tBar](top_bar::Configuration configuration) {
        configuration.set(top_bar::Indicator::Time, tBar);
        return configuration;
    });

    title->setVisible(tBar);
    bottomBar->setActive(BottomBar::Side::CENTER, bBar);
    bottomBar->setActive(BottomBar::Side::LEFT, bBar);

M module-apps/application-messages/windows/MessagesMainWindow.cpp => module-apps/application-messages/windows/MessagesMainWindow.cpp +0 -2
@@ 64,8 64,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::open));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::TIME, true);

        setTitle(utils::localize.get("app_messages_title_main"));

        leftArrowImage  = new gui::Image(this, 30, 62, 0, 0, "arrow_left");

M module-apps/application-messages/windows/NewMessage.cpp => module-apps/application-messages/windows/NewMessage.cpp +0 -3
@@ 188,9 188,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::LEFT, utils::localize.get(style::strings::common::options));
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::select));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
        topBar->setActive(TopBar::Elements::BATTERY, false);
        topBar->setActive(TopBar::Elements::SIM, false);
        topBar->setActive(TopBar::Elements::SIGNAL, false);

        setTitle(utils::localize.get("sms_title_message"));


M module-apps/application-messages/windows/SMSTemplatesWindow.cpp => module-apps/application-messages/windows/SMSTemplatesWindow.cpp +0 -2
@@ 44,8 44,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::use));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::TIME, true);

        namespace style = style::messages::templates::list;

        list = new gui::ListView(this, style::x, style::y, style::w, style::h, smsTemplateModel);

M module-apps/application-messages/windows/SMSThreadViewWindow.cpp => module-apps/application-messages/windows/SMSThreadViewWindow.cpp +0 -1
@@ 29,7 29,6 @@ namespace gui
    {
        AppWindow::buildInterface();
        setTitle(utils::localize.get("app_messages_title_main"));
        topBar->setActive(TopBar::Elements::TIME, true);
        bottomBar->setText(BottomBar::Side::LEFT, utils::localize.get(style::strings::common::options));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));


M module-apps/application-music-player/windows/MusicPlayerAllSongsWindow.cpp => module-apps/application-music-player/windows/MusicPlayerAllSongsWindow.cpp +0 -2
@@ 54,8 54,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get("app_music_player_play"));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::TIME, true);

        songsList = new gui::ListView(this,
                                      musicPlayerStyle::allSongsWindow::x,
                                      musicPlayerStyle::allSongsWindow::y,

M module-apps/application-music-player/windows/MusicPlayerEmptyWindow.cpp => module-apps/application-music-player/windows/MusicPlayerEmptyWindow.cpp +0 -2
@@ 33,8 33,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::LEFT, utils::localize.get("app_music_player_music_library"));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get("app_music_player_quit"));

        topBar->setActive(TopBar::Elements::TIME, true);

        img = new gui::Image(this, noteImg::x, noteImg::y, "note");

        text = new Text(this, infoText::x, infoText::y, infoText::w, infoText::h);

M module-apps/application-notes/windows/NoteEditWindow.cpp => module-apps/application-notes/windows/NoteEditWindow.cpp +0 -2
@@ 85,8 85,6 @@ namespace app::notes
        bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
        bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(::style::strings::common::back));

        topBar->setActive(gui::TopBar::Elements::TIME, true);

        setFocusItem(edit);
    }


M module-apps/application-notes/windows/NoteMainWindow.cpp => module-apps/application-notes/windows/NoteMainWindow.cpp +0 -1
@@ 54,7 54,6 @@ namespace app::notes
        bottomBar->setText(gui::BottomBar::Side::CENTER, utils::localize.get(::style::strings::common::open));
        bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
        bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(::style::strings::common::back));
        topBar->setActive(gui::TopBar::Elements::TIME, true);

        namespace windowStyle = app::notes::style::main_window;
        leftArrowImage        = new gui::Image(this,

M module-apps/application-notes/windows/NotePreviewWindow.cpp => module-apps/application-notes/windows/NotePreviewWindow.cpp +0 -2
@@ 79,8 79,6 @@ namespace app::notes
        bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
        bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(::style::strings::common::back));

        topBar->setActive(gui::TopBar::Elements::TIME, true);

        setFocusItem(note);
    }


M module-apps/application-phonebook/windows/PhonebookContactDetails.cpp => module-apps/application-phonebook/windows/PhonebookContactDetails.cpp +0 -1
@@ 25,7 25,6 @@ namespace gui
    void PhonebookContactDetails::buildInterface()
    {
        AppWindow::buildInterface();
        topBar->setActive(TopBar::Elements::TIME, true);

        bottomBar->setText(BottomBar::Side::LEFT, utils::localize.get(style::strings::common::options));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

M module-apps/application-phonebook/windows/PhonebookIceContacts.cpp => module-apps/application-phonebook/windows/PhonebookIceContacts.cpp +0 -1
@@ 25,7 25,6 @@ namespace gui
    {
        AppWindow::buildInterface();

        topBar->setActive(TopBar::Elements::TIME, true);
        setTitle(utils::localize.get("app_phonebook_ice_contacts_title"));

        contactsListIce = new gui::ListView(this,

M module-apps/application-phonebook/windows/PhonebookMainWindow.cpp => module-apps/application-phonebook/windows/PhonebookMainWindow.cpp +0 -1
@@ 30,7 30,6 @@ namespace gui
    {
        AppWindow::buildInterface();

        topBar->setActive(TopBar::Elements::TIME, true);
        setTitle(utils::localize.get("app_phonebook_title_main"));
        leftArrowImage  = new gui::Image(this,
                                        phonebookStyle::mainWindow::leftArrowImage::x,

M module-apps/application-phonebook/windows/PhonebookSearch.cpp => module-apps/application-phonebook/windows/PhonebookSearch.cpp +0 -1
@@ 16,7 16,6 @@ namespace gui
    void PhonebookSearch::buildInterface()
    {
        AppWindow::buildInterface();
        topBar->setActive(TopBar::Elements::TIME, true);

        setTitle(utils::localize.get("app_phonebook_title_main"));


M module-apps/application-phonebook/windows/PhonebookSearchResults.cpp => module-apps/application-phonebook/windows/PhonebookSearchResults.cpp +0 -2
@@ 40,8 40,6 @@ namespace gui
        bottomBar->setActive(BottomBar::Side::RIGHT, true);
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::TIME, true);

        setTitle(utils::localize.get("common_results_prefix"));
    }


M module-apps/application-settings-new/ApplicationSettings.cpp => module-apps/application-settings-new/ApplicationSettings.cpp +101 -24
@@ 5,7 5,8 @@

#include "windows/AddDeviceWindow.hpp"
#include "windows/AllDevicesWindow.hpp"
#include "windows/APNSettingsWindow.hpp"
#include "windows/ApnSettingsWindow.hpp"
#include "windows/ApnOptionsWindow.hpp"
#include "windows/BluetoothWindow.hpp"
#include "windows/SettingsMainWindow.hpp"
#include "windows/DisplayAndKeypadWindow.hpp"


@@ 25,28 26,38 @@
#include "windows/QuotesMainWindow.hpp"
#include "windows/QuotesAddWindow.hpp"
#include "windows/SecurityMainWindow.hpp"
#include "windows/QuotesOptionsWindow.hpp"
#include "windows/ChangePasscodeWindow.hpp"
#include "windows/SystemMainWindow.hpp"
#include "windows/NewApnWindow.hpp"

#include "Dialog.hpp"

#include <service-evtmgr/EventManagerServiceAPI.hpp>
#include <service-bluetooth/BluetoothMessage.hpp>
#include <service-cellular/CellularServiceAPI.hpp>
#include <service-db/Settings.hpp>
#include <module-services/service-bluetooth/service-bluetooth/messages/Status.hpp>
#include <service-bluetooth/BluetoothMessage.hpp>
#include <service-bluetooth/service-bluetooth/messages/Status.hpp>
#include <service-bluetooth/messages/BondedDevices.hpp>
#include <service-bluetooth/messages/DeviceName.hpp>
#include <application-settings-new/data/BondedDevicesData.hpp>
#include <service-db/agents/settings/SystemSettings.hpp>
#include <application-settings-new/data/ApnListData.hpp>
#include <application-settings-new/data/BondedDevicesData.hpp>
#include <application-settings-new/data/PhoneNameData.hpp>
#include <module-services/service-db/agents/settings/SystemSettings.hpp>
#include <service-db/Settings.hpp>

#include <i18n/i18n.hpp>
#include <module-services/service-evtmgr/service-evtmgr/ScreenLightControlMessage.hpp>
#include <module-services/service-evtmgr/service-evtmgr/Constants.hpp>

namespace app
{
    namespace settings
    {
        constexpr inline auto operators_on = "operators_on";
    }
        const std::string quotesPath =
            purefs::createPath(purefs::dir::getUserDiskPath(), "data/applications/settings/quotes.json");
    } // namespace settings

    ApplicationSettingsNew::ApplicationSettingsNew(std::string name,
                                                   std::string parent,


@@ 57,17 68,10 @@ namespace app
            Store::GSM::get()->sim == selectedSim) {
            selectedSimNumber = CellularServiceAPI::GetOwnNumber(this);
        }
        settings->registerValueChange(settings::operators_on,
                                      [this](const std::string &value) { operatorOnChanged(value); });

        settings->registerValueChange(::settings::Cellular::volte_on,
                                      [this](const std::string &value) { volteChanged(value); });
    }

    ApplicationSettingsNew::~ApplicationSettingsNew()
    {
        settings->unregisterValueChange(settings::operators_on);
        settings->unregisterValueChange(::settings::Cellular::volte_on);
    }

    // Invoked upon receiving data message


@@ 143,13 147,29 @@ namespace app
            return sys::MessageNone{};
        });

        connect(typeid(CellularGetAPNResponse), [&](sys::Message *msg) {
            if (gui::window::name::apn_settings == getCurrentWindow()->getName()) {
                auto apns = dynamic_cast<CellularGetAPNResponse *>(msg);
                if (apns != nullptr) {
                    auto apnsData = std::make_unique<gui::ApnListData>(apns->getAPNs());
                    switchWindow(gui::window::name::apn_settings, std::move(apnsData));
                }
            }
            return sys::MessageNone{};
        });

        createUserInterface();

        setActiveWindow(gui::name::window::main_window);

        settings->registerValueChange(::settings::SystemProperties::lockPassHash, [this](std::string value) {
            lockPassHash = utils::getNumericValue<unsigned int>(value);
        });
        settings->registerValueChange(settings::operators_on,
                                      [this](const std::string &value) { operatorOnChanged(value); });
        settings->registerValueChange(::settings::Cellular::volte_on,
                                      [this](const std::string &value) { volteChanged(value); });
        settings->registerValueChange(
            ::settings::SystemProperties::lockPassHash,
            [this](std::string value) { lockPassHash = utils::getNumericValue<unsigned int>(value); },
            ::settings::SettingsScope::Global);

        return ret;
    }


@@ 188,7 208,7 @@ namespace app
            return std::make_unique<gui::FontSizeWindow>(app);
        });
        windowsFactory.attach(gui::window::name::display_light, [](Application *app, const std::string &name) {
            return std::make_unique<gui::DisplayLightWindow>(app);
            return std::make_unique<gui::DisplayLightWindow>(app, static_cast<ApplicationSettingsNew *>(app));
        });
        windowsFactory.attach(gui::window::name::apps_and_tools, [](Application *app, const std::string &name) {
            return std::make_unique<gui::AppsAndToolsWindow>(app);


@@ 201,7 221,10 @@ namespace app
                app, static_cast<ApplicationSettingsNew *>(app), static_cast<ApplicationSettingsNew *>(app));
        });
        windowsFactory.attach(gui::window::name::apn_settings, [](Application *app, const std::string &name) {
            return std::make_unique<gui::APNSettingsWindow>(app);
            return std::make_unique<gui::ApnSettingsWindow>(app);
        });
        windowsFactory.attach(gui::window::name::apn_options, [](Application *app, const std::string &name) {
            return std::make_unique<gui::ApnOptionsWindow>(app);
        });
        windowsFactory.attach(gui::window::name::messages, [](Application *app, const std::string &name) {
            return std::make_unique<gui::MessagesWindow>(app);


@@ 218,11 241,8 @@ namespace app
        windowsFactory.attach(gui::window::name::wallpaper, [](Application *app, const std::string &name) {
            return std::make_unique<gui::WallpaperWindow>(app);
        });
        windowsFactory.attach(gui::window::name::quotes, [](Application *app, const std::string &name) {
            return std::make_unique<gui::QuotesMainWindow>(app);
        });
        windowsFactory.attach(gui::window::name::new_quote, [](Application *app, const std::string &name) {
            return std::make_unique<gui::QuotesAddWindow>(app);
        windowsFactory.attach(gui::window::name::quotes_dialog_yes_no, [](Application *app, const std::string &name) {
            return std::make_unique<gui::DialogYesNo>(app, name);
        });
        windowsFactory.attach(gui::window::name::security, [](Application *app, const std::string &name) {
            return std::make_unique<gui::SecurityMainWindow>(app);


@@ 233,6 253,12 @@ namespace app
        windowsFactory.attach(gui::window::name::dialog_confirm, [](Application *app, const std::string &name) {
            return std::make_unique<gui::DialogConfirm>(app, gui::window::name::dialog_confirm);
        });
        windowsFactory.attach(gui::window::name::system, [](Application *app, const std::string &name) {
            return std::make_unique<gui::SystemMainWindow>(app);
        });
        windowsFactory.attach(gui::window::name::new_apn, [](Application *app, const std::string &name) {
            return std::make_unique<gui::NewApnWindow>(app);
        });
    }

    void ApplicationSettingsNew::destroyUserInterface()


@@ 255,17 281,20 @@ namespace app

    void ApplicationSettingsNew::operatorOnChanged(const std::string &value)
    {
        LOG_DEBUG("[ApplicationSettingsNew::operatorOnChanged] value=%s", value.c_str());
        if (!value.empty()) {
            operatorsOn = utils::getNumericValue<bool>(value);
        }
    }
    bool ApplicationSettingsNew::getOperatorsOn() const noexcept
    {
        LOG_DEBUG("[ApplicationSettingsNew::getOperatorsOn] %d", operatorsOn);
        return operatorsOn;
    }
    void ApplicationSettingsNew::setOperatorsOn(bool value)
    {
        operatorsOn = value;
        LOG_DEBUG("[ApplicationSettingsNew::setOperatorsOn] to %d", operatorsOn);
        settings->setValue(settings::operators_on, std::to_string(value));
    }



@@ 290,6 319,54 @@ namespace app
    void ApplicationSettingsNew::setLockPassHash(unsigned int value)
    {
        lockPassHash = value;
        settings->setValue(::settings::SystemProperties::lockPassHash, std::to_string(value));
        settings->setValue(
            ::settings::SystemProperties::lockPassHash, std::to_string(value), ::settings::SettingsScope::Global);
    }

    auto ApplicationSettingsNew::getCurrentValues() -> settingsInterface::ScreenLightSettings::Values
    {
        constexpr int timeout = pdMS_TO_TICKS(1500);

        auto response = sys::Bus::SendUnicast(
            std::make_shared<sevm::ScreenLightControlRequestParameters>(), service::name::evt_manager, this, timeout);

        if (response.first == sys::ReturnCodes::Success) {
            auto msgState = dynamic_cast<sevm::ScreenLightControlParametersResponse *>(response.second.get());
            if (msgState == nullptr) {
                return {};
            }

            return {msgState->lightOn, msgState->mode, msgState->parameters};
        }

        return {};
    }

    void ApplicationSettingsNew::setBrightness(bsp::eink_frontlight::BrightnessPercentage value)
    {
        screen_light_control::Parameters parameters{value};
        sys::Bus::SendUnicast(std::make_shared<sevm::ScreenLightControlMessage>(
                                  screen_light_control::Action::setManualModeBrightness, parameters),
                              service::name::evt_manager,
                              this);
    }

    void ApplicationSettingsNew::setMode(bool isAutoLightSwitchOn)
    {
        sys::Bus::SendUnicast(std::make_shared<sevm::ScreenLightControlMessage>(
                                  isAutoLightSwitchOn ? screen_light_control::Action::enableAutomaticMode
                                                      : screen_light_control::Action::disableAutomaticMode),
                              service::name::evt_manager,
                              this);
    }

    void ApplicationSettingsNew::setStatus(bool isDisplayLightSwitchOn)
    {
        sys::Bus::SendUnicast(
            std::make_shared<sevm::ScreenLightControlMessage>(
                isDisplayLightSwitchOn ? screen_light_control::Action::turnOn : screen_light_control::Action::turnOff),
            service::name::evt_manager,
            this);
    }

} /* namespace app */

M module-apps/application-settings-new/ApplicationSettings.hpp => module-apps/application-settings-new/ApplicationSettings.hpp +43 -5
@@ 6,6 6,7 @@
#include "Application.hpp"

#include <bsp/common.hpp>
#include <module-services/service-evtmgr/screen-light-control/ScreenLightControl.hpp>

namespace gui::window::name
{


@@ 16,6 17,7 @@ namespace gui::window::name

    inline constexpr auto network        = "Network";
    inline constexpr auto apn_settings   = "APNSettings";
    inline constexpr auto apn_options    = "APNOptions";
    inline constexpr auto phone_modes    = "PhoneModes";
    inline constexpr auto apps_and_tools = "AppsAndTools";
    inline constexpr auto security       = "Security";


@@ 32,10 34,14 @@ namespace gui::window::name
    inline constexpr auto nightshift = "Nightshift";
    inline constexpr auto templates  = "Templates";

    inline constexpr auto autolock  = "Autolock";
    inline constexpr auto wallpaper = "Wallpaper";
    inline constexpr auto quotes    = "Quotes";
    inline constexpr auto new_quote = "NewQuote";
    inline constexpr auto autolock             = "Autolock";
    inline constexpr auto wallpaper            = "Wallpaper";
    inline constexpr auto quotes               = "Quotes";
    inline constexpr auto new_quote            = "NewQuote";
    inline constexpr auto edit_quote           = "EditQuote";
    inline constexpr auto options_quote        = "OptionsQuote";
    inline constexpr auto delete_quote         = "DeleteQuote";
    inline constexpr auto quotes_dialog_yes_no = "DialogYesNo";

    inline constexpr auto display_and_keypad = "DisplayAndKeypad";
    inline constexpr auto change_settings    = "ChangeSettings";


@@ 44,6 50,14 @@ namespace gui::window::name
    inline constexpr auto dialog_settings    = "DialogSettings";
    inline constexpr auto change_passcode    = "ChangePasscode";

    inline constexpr auto language        = "Language";
    inline constexpr auto date_and_time   = "DateAndTime";
    inline constexpr auto factory_reset   = "FactoryReset";
    inline constexpr auto about_your_pure = "AboutYourPure";
    inline constexpr auto certification   = "Certification";

    inline constexpr auto new_apn = "NewApn";

} // namespace gui::window::name

namespace app


@@ 69,11 83,28 @@ namespace app
            virtual void setVoLTEOn(bool value)                        = 0;
            [[nodiscard]] virtual bool getVoLTEOn() const noexcept     = 0;
        };
        class ScreenLightSettings
        {
          public:
            struct Values
            {
                bool lightOn;
                screen_light_control::ScreenLightMode mode;
                screen_light_control::Parameters parameters;
            };

            virtual ~ScreenLightSettings()                      = default;
            virtual auto getCurrentValues() -> Values           = 0;
            virtual void setBrightness(float brigtnessValue)    = 0;
            virtual void setMode(bool isAutoLightSwitchOn)      = 0;
            virtual void setStatus(bool isDisplayLightSwitchOn) = 0;
        };
    }; // namespace settingsInterface

    class ApplicationSettingsNew : public app::Application,
                                   public settingsInterface::SimParams,
                                   public settingsInterface::OperatorsSettings
                                   public settingsInterface::OperatorsSettings,
                                   public settingsInterface::ScreenLightSettings
    {
      public:
        ApplicationSettingsNew(std::string name                    = name_settings_new,


@@ 106,7 137,14 @@ namespace app
        }
        void setLockPassHash(unsigned int value);

        ScreenLightSettings::Values getCurrentValues() override;
        void setBrightness(float brigtnessValue) override;
        void setMode(bool isAutoLightSwitchOn) override;
        void setStatus(bool isDisplayLightSwitchOn) override;

      private:
        void attachQuotesWindows();

        Store::GSM::SIM selectedSim   = Store::GSM::get()->selected;
        std::string selectedSimNumber = {};
        bsp::Board board              = bsp::Board::none;

M module-apps/application-settings-new/CMakeLists.txt => module-apps/application-settings-new/CMakeLists.txt +13 -2
@@ 15,12 15,17 @@ target_sources( ${PROJECT_NAME}

    PRIVATE
        ApplicationSettings.cpp
        models/ApnSettingsModel.cpp
        models/NewApnModel.cpp
        widgets/timeWidget.cpp
        widgets/ChangePasscodeLockHandler.cpp
        widgets/QuoteWidget.cpp
        widgets/ApnInputWidget.cpp
        windows/SettingsMainWindow.cpp
        windows/AddDeviceWindow.cpp
        windows/AllDevicesWindow.cpp
        windows/APNSettingsWindow.cpp
        windows/ApnSettingsWindow.cpp
        windows/ApnOptionsWindow.cpp
        windows/BaseSettingsWindow.cpp
        windows/BluetoothWindow.cpp
        windows/FontSizeWindow.cpp


@@ 41,10 46,16 @@ target_sources( ${PROJECT_NAME}
        windows/QuotesAddWindow.cpp
        windows/SecurityMainWindow.cpp
        windows/ChangePasscodeWindow.cpp
        windows/NewApnWindow.cpp
        widgets/SpinBox.cpp
        widgets/SpinBoxOptionSetting.cpp
        windows/SystemMainWindow.cpp

    PUBLIC
        ApplicationSettings.hpp
        widgets/ChangePasscodeLockHandler.hpp
        widgets/ApnInputWidget.hpp
        windows/NewApnWindow.hpp
        windows/SettingsMainWindow.hpp
        windows/BaseSettingsWindow.hpp
        windows/FontSizeWindow.hpp


@@ 59,6 70,7 @@ target_sources( ${PROJECT_NAME}
        windows/AutolockWindow.hpp
        windows/WallpaperWindow.hpp
        windows/ChangePasscodeWindow.hpp
        windows/SystemMainWindow.hpp
)

add_dependencies(${PROJECT_NAME} version)


@@ 66,5 78,4 @@ add_dependencies(${PROJECT_NAME} version)
target_link_libraries(${PROJECT_NAME}
    PUBLIC
        service-bluetooth
        service-evtmgr
)

A module-apps/application-settings-new/data/ApnListData.hpp => module-apps/application-settings-new/data/ApnListData.hpp +27 -0
@@ 0,0 1,27 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <service-cellular/PacketDataTypes.hpp>
#include <SwitchData.hpp>

#include <vector>

namespace gui
{

    class ApnListData : public SwitchData
    {
      public:
        explicit ApnListData(std::vector<std::shared_ptr<packet_data::APN::Config>> apns) : apns(std::move(apns))
        {}
        [[nodiscard]] auto getAPNs() const noexcept -> const std::vector<std::shared_ptr<packet_data::APN::Config>> &
        {
            return apns;
        }

      private:
        std::vector<std::shared_ptr<packet_data::APN::Config>> apns;
    };
} // namespace gui

A module-apps/application-settings-new/data/QuoteSwitchData.hpp => module-apps/application-settings-new/data/QuoteSwitchData.hpp +45 -0
@@ 0,0 1,45 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "application-settings-new/models/QuotesModel.hpp"

#include <SwitchData.hpp>
#include <json/json11.hpp>
#include <utility>

namespace app
{
    class QuotesModel;
};

namespace gui
{
    enum class QuoteAction
    {
        None,
        Add,
        Edit
    };

    class QuoteSwitchData : public gui::SwitchData
    {
      public:
        QuoteSwitchData(QuoteAction action, app::QuoteRecord quote = {}) : action(action), quote(std::move(quote))
        {}

        [[nodiscard]] auto getQuote() const
        {
            return quote;
        }
        [[nodiscard]] auto getAction() const
        {
            return action;
        }

      private:
        QuoteAction action;
        app::QuoteRecord quote;
    };
} // namespace gui

A module-apps/application-settings-new/data/SettingsInternals.hpp => module-apps/application-settings-new/data/SettingsInternals.hpp +30 -0
@@ 0,0 1,30 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <cstdint>

namespace settingsInternals
{
    enum class ListItemName
    {
        Name,
        APN,
        Proxy,
        Port,
        Username,
        Password,

        Server,
        MMSC,
        MmsProxy,
        MmsPort,
        MCC,
        MNC,
        AuthType,
        ApnType,
        ApnProtocol
    };

} // namespace settingsInternals

A module-apps/application-settings-new/data/SettingsItemData.hpp => module-apps/application-settings-new/data/SettingsItemData.hpp +23 -0
@@ 0,0 1,23 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <service-cellular/service-cellular/PacketDataTypes.hpp>
#include <ListItem.hpp>
#include <SwitchData.hpp>

class ApnItemData : public gui::SwitchData
{
  public:
    ApnItemData(std::shared_ptr<packet_data::APN::Config> Apn) : apn(std::move(Apn)){};
    ApnItemData() : apn(nullptr){};

    auto getApn() -> std::shared_ptr<packet_data::APN::Config>
    {
        return apn;
    }

  private:
    std::shared_ptr<packet_data::APN::Config> apn;
};

A module-apps/application-settings-new/models/ApnSettingsModel.cpp => module-apps/application-settings-new/models/ApnSettingsModel.cpp +28 -0
@@ 0,0 1,28 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "ApnSettingsModel.hpp"
#include <service-cellular/PacketDataCellularMessage.hpp>
#include <service-cellular/ServiceCellular.hpp>

ApnSettingsModel::ApnSettingsModel(app::Application *application) : application{application}
{}

void ApnSettingsModel::requestAPNList()
{
    sys::Bus::SendUnicast(std::make_shared<CellularGetAPNMessage>(), ServiceCellular::serviceName, application);
}

void ApnSettingsModel::saveAPN(std::shared_ptr<packet_data::APN::Config> apn)
{
    sys::Bus::SendUnicast(std::make_shared<CellularSetAPNMessage>(apn), ServiceCellular::serviceName, application);
}

void ApnSettingsModel::removeAPN(std::shared_ptr<packet_data::APN::Config> apn)
{}

void ApnSettingsModel::setAsDefaultAPN(std::shared_ptr<packet_data::APN::Config> apn)
{
    apn->apnType = packet_data::APN::APNType::Default;
    sys::Bus::SendUnicast(std::make_shared<CellularSetAPNMessage>(apn), ServiceCellular::serviceName, application);
}

A module-apps/application-settings-new/models/ApnSettingsModel.hpp => module-apps/application-settings-new/models/ApnSettingsModel.hpp +21 -0
@@ 0,0 1,21 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <service-cellular/PacketDataTypes.hpp>
#include <module-apps/Application.hpp>

class ApnSettingsModel
{
  public:
    ApnSettingsModel(app::Application *application);

    void requestAPNList();
    void saveAPN(std::shared_ptr<packet_data::APN::Config> apn);
    void removeAPN(std::shared_ptr<packet_data::APN::Config> apn);
    void setAsDefaultAPN(std::shared_ptr<packet_data::APN::Config> apn);

  private:
    app::Application *application = nullptr;
};

A module-apps/application-settings-new/models/NewApnModel.cpp => module-apps/application-settings-new/models/NewApnModel.cpp +133 -0
@@ 0,0 1,133 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "NewApnModel.hpp"

#include "application-settings-new/widgets/ApnInputWidget.hpp"

#include <ListView.hpp>
#include <time/ScopedTime.hpp>
#include <BottomBar.hpp>

NewApnModel::NewApnModel(app::Application *app) : application(app)
{}

auto NewApnModel::requestRecordsCount() -> unsigned int
{
    return internalData.size();
}

auto NewApnModel::getMinimalItemHeight() const -> unsigned int
{
    return style::settings::widget::apnInputWidget::h;
}

void NewApnModel::requestRecords(const uint32_t offset, const uint32_t limit)
{
    setupModel(offset, limit);
    list->onProviderDataUpdate();
}

auto NewApnModel::getItem(gui::Order order) -> gui::ListItem *
{
    return getRecord(order);
}

void NewApnModel::createData()
{
    auto app = application;

    internalData.emplace_back(new gui::ApnInputWidget(
        settingsInternals::ListItemName::Name,
        [app](const UTF8 &text) { app->getCurrentWindow()->bottomBarTemporaryMode(text); },
        [app]() { app->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); },
        [app]() { app->getCurrentWindow()->selectSpecialCharacter(); },
        [this]() { this->apnDataChanged(); }));

    internalData.emplace_back(new gui::ApnInputWidget(
        settingsInternals::ListItemName::APN,
        [app](const UTF8 &text) { app->getCurrentWindow()->bottomBarTemporaryMode(text); },
        [app]() { app->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); },
        [app]() { app->getCurrentWindow()->selectSpecialCharacter(); },
        [this]() { this->apnDataChanged(); }));

    internalData.emplace_back(new gui::ApnInputWidget(
        settingsInternals::ListItemName::Username,
        [app](const UTF8 &text) { app->getCurrentWindow()->bottomBarTemporaryMode(text); },
        [app]() { app->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); },
        [app]() { app->getCurrentWindow()->selectSpecialCharacter(); },
        [this]() { this->apnDataChanged(); }));

    internalData.emplace_back(new gui::ApnInputWidget(
        settingsInternals::ListItemName::Password,
        [app](const UTF8 &text) { app->getCurrentWindow()->bottomBarTemporaryMode(text); },
        [app]() { app->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); },
        [app]() { app->getCurrentWindow()->selectSpecialCharacter(); },
        [this]() { this->apnDataChanged(); }));

    internalData.emplace_back(new gui::ApnInputWidget(
        settingsInternals::ListItemName::AuthType,
        [app](const UTF8 &text) { app->getCurrentWindow()->bottomBarTemporaryMode(text); },
        [app]() { app->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); },
        [app]() { app->getCurrentWindow()->selectSpecialCharacter(); },
        [this]() { this->apnDataChanged(); }));

    internalData.emplace_back(new gui::ApnInputWidget(
        settingsInternals::ListItemName::ApnType,
        [app](const UTF8 &text) { app->getCurrentWindow()->bottomBarTemporaryMode(text); },
        [app]() { app->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); },
        [app]() { app->getCurrentWindow()->selectSpecialCharacter(); },
        [this]() { this->apnDataChanged(); }));

    internalData.emplace_back(new gui::ApnInputWidget(
        settingsInternals::ListItemName::ApnProtocol,
        [app](const UTF8 &text) { app->getCurrentWindow()->bottomBarTemporaryMode(text); },
        [app]() { app->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); },
        [app]() { app->getCurrentWindow()->selectSpecialCharacter(); },
        [this]() { this->apnDataChanged(); }));

    for (auto item : internalData) {
        item->deleteByList = false;
    }
}

void NewApnModel::clearData()
{
    list->clear();

    eraseInternalData();

    createData();

    list->rebuildList();
}

void NewApnModel::saveData(std::shared_ptr<packet_data::APN::Config> apnRecord)
{
    for (auto item : internalData) {
        if (item->onSaveCallback) {
            item->onSaveCallback(apnRecord);
        }
    }
}

void NewApnModel::loadData(std::shared_ptr<packet_data::APN::Config> apnRecord)
{
    for (auto item : internalData) {
        if (item->onLoadCallback) {
            item->onLoadCallback(apnRecord);
        }
    }
}

void NewApnModel::apnDataChanged()
{
    for (auto item : internalData) {
        if (item->onEmptyCallback && !item->onEmptyCallback()) {
            application->getCurrentWindow()->setBottomBarActive(gui::BottomBar::Side::CENTER, true); // SAVE button
            return;
        }
    }
    application->getCurrentWindow()->setBottomBarActive(gui::BottomBar::Side::CENTER, false); // SAVE button
    return;
}

A module-apps/application-settings-new/models/NewApnModel.hpp => module-apps/application-settings-new/models/NewApnModel.hpp +35 -0
@@ 0,0 1,35 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "application-settings-new/data/SettingsItemData.hpp"
#include "application-settings-new/widgets/ApnListItem.hpp"
#include "application-settings-new/widgets/SettingsStyle.hpp"
#include "InternalModel.hpp"
#include "Application.hpp"

#include <ListItemProvider.hpp>

class NewApnModel : public app::InternalModel<gui::ApnListItem *>, public gui::ListItemProvider
{
    app::Application *application = nullptr;

  public:
    NewApnModel(app::Application *app);

    void clearData();
    void saveData(std::shared_ptr<packet_data::APN::Config> apnRecord);
    void loadData(std::shared_ptr<packet_data::APN::Config> apnRecord);

    void createData();

    [[nodiscard]] auto requestRecordsCount() -> unsigned int override;

    [[nodiscard]] auto getMinimalItemHeight() const -> unsigned int override;

    auto getItem(gui::Order order) -> gui::ListItem * override;

    void requestRecords(const uint32_t offset, const uint32_t limit) override;
    void apnDataChanged();
};

A module-apps/application-settings-new/models/QuotesModel.cpp => module-apps/application-settings-new/models/QuotesModel.cpp +99 -0
@@ 0,0 1,99 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "application-settings-new/windows/QuotesMainWindow.hpp"
#include "application-settings-new/ApplicationSettings.hpp"
#include "QuotesRepository.hpp"
#include "QuotesModel.hpp"

#include <InputEvent.hpp>
#include <i18n/i18n.hpp>
#include <json/json11.hpp>
#include <Utils.hpp>
#include <string>
#include <utility>

namespace style::quotes::list
{
    constexpr auto item_height = 63;
    constexpr auto max_quotes  = 100;
} // namespace style::quotes::list

namespace app
{
    QuotesModel::QuotesModel(app::Application *app, std::unique_ptr<QuotesRepository> repository)
        : application(app), repository(std::move(repository))
    {}

    auto QuotesModel::requestRecordsCount() -> unsigned int
    {
        return internalData.size();
    }

    auto QuotesModel::getMinimalItemHeight() const -> unsigned int
    {
        return style::quotes::list::item_height;
    }

    void QuotesModel::requestRecords(const uint32_t offset, const uint32_t limit)
    {
        setupModel(offset, limit);
        list->onProviderDataUpdate();
    }

    auto QuotesModel::getItem(gui::Order order) -> gui::ListItem *
    {
        auto app   = application;
        auto *item = dynamic_cast<gui::QuoteWidget *>(getRecord(order));

        if (item != nullptr) {
            item->inputCallback = [app, item](gui::Item &, const gui::InputEvent &event) {
                if (event.isShortPress() && event.is(gui::KeyCode::KEY_LF)) {
                    app->switchWindow(
                        gui::window::name::options_quote,
                        std::make_unique<gui::QuoteSwitchData>(gui::QuoteAction::None, item->getQuoteData()));
                }
                return false;
            };
        }
        return item;
    }

    void QuotesModel::rebuild()
    {
        list->clear();
        eraseInternalData();
        createData();
        list->rebuildList();
    }

    void QuotesModel::createData()
    {
        repository->get(0, style::quotes::list::max_quotes, [this](const std::list<QuoteRecord> &quotes, unsigned int) {
            auto app = application;
            for (const auto &quote : quotes) {
                auto item = new gui::QuoteWidget(
                    quote,
                    [app](const UTF8 &text) {
                        app->getCurrentWindow()->bottomBarTemporaryMode(text, gui::BottomBar::Side::CENTER, false);
                    },
                    [app]() { app->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); });

                item->deleteByList = false;
                internalData.push_back(item);
            }
            return true;
        });
    }

    void QuotesModel::remove(const app::QuoteRecord &quote)
    {
        repository->remove(quote);
    }

    void QuotesModel::save(const app::QuoteRecord &quote)
    {
        repository->save(quote);
    }

} // namespace app

A module-apps/application-settings-new/models/QuotesModel.hpp => module-apps/application-settings-new/models/QuotesModel.hpp +42 -0
@@ 0,0 1,42 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "QuotesRepository.hpp"

#include <purefs/filesystem_paths.hpp>
#include <module-gui/gui/widgets/ListView.hpp>
#include <module-apps/InternalModel.hpp>

namespace gui
{
    class QuoteWidget;
}

namespace app
{
    class QuotesModel : public app::InternalModel<gui::QuoteWidget *>, public gui::ListItemProvider
    {
      public:
        QuotesModel(app::Application *app, std::unique_ptr<QuotesRepository> repository);

        [[nodiscard]] auto requestRecordsCount() -> unsigned int final;
        [[nodiscard]] auto getMinimalItemHeight() const -> unsigned int final;

        auto getItem(gui::Order order) -> gui::ListItem * final;
        void requestRecords(const uint32_t offset, const uint32_t limit) final;

        void rebuild();

        void remove(const app::QuoteRecord &quote);
        void save(const app::QuoteRecord &quote);

      private:
        void createData();

        app::Application *application                     = nullptr;
        std::unique_ptr<app::QuotesRepository> repository = nullptr;
    };

} // namespace app

A module-apps/application-settings-new/models/QuotesRepository.cpp => module-apps/application-settings-new/models/QuotesRepository.cpp +100 -0
@@ 0,0 1,100 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "QuotesRepository.hpp"

#include <module-utils/gsl/gsl_util>
#include <algorithm>
#include <utility>

namespace app
{
    QuotesJsonRepository::QuotesJsonRepository(const std::string &path) : repositoryPath{std::move(path)}
    {}

    void QuotesJsonRepository::get(std::uint32_t offset, std::uint32_t limit, const OnGetCallback &callback)
    {
        if (quotes.empty()) {
            readQuotes(repositoryPath);
        }

        if (callback) {
            std::uint32_t size = quotes.size();
            auto start         = std::next(quotes.begin(), std::min(offset, size));
            auto end           = std::next(quotes.begin(), std::min(offset + limit, size));
            std::list<QuoteRecord> result{start, end};
            callback(result, result.size());
        }
    }

    void QuotesJsonRepository::save(const QuoteRecord &quote)
    {
        auto toEdit = std::find_if(quotes.begin(), quotes.end(), [quote](auto &&d) { return d.id == quote.id; });

        if (toEdit != quotes.end()) {
            toEdit->quote  = quote.quote;
            toEdit->author = quote.author;
        }
        else if (quote.id == 0) {
            quotes.push_back(quote);
        }

        writeQuotes(repositoryPath);
    }

    void QuotesJsonRepository::remove(const QuoteRecord &quote)
    {
        quotes.remove_if([quote](auto &&d) { return d.id == quote.id; });
        writeQuotes(repositoryPath);
    }

    void QuotesJsonRepository::writeQuotes(const fs::path &quotesFilename)
    {
        if (auto file = std::fopen(repositoryPath.c_str(), "w"); file != nullptr) {
            auto _    = gsl::finally([file] { std::fclose(file); });
            auto body = json11::Json{quotes};
            auto text = body.dump();
            std::fwrite(text.c_str(), 1, text.length(), file);
        }
    }

    void QuotesJsonRepository::readQuotes(const fs::path &quotesFilename)
    {
        std::string err;

        const auto fileContents = readFileToString(quotesFilename);
        auto obj                = json11::Json::parse(fileContents.c_str(), err).array_items();

        if (!err.empty()) {
            LOG_ERROR("Error while parsing quotes from file: %s error: %s ", quotesFilename.c_str(), err.c_str());
            return;
        }

        quotes.clear();

        auto id = 1;
        std::transform(obj.begin(), obj.end(), std::back_inserter(quotes), [&id](auto item) {
            return QuoteRecord{id++, item["quote"].string_value(), item["author"].string_value()};
        });
    }

    auto QuotesJsonRepository::readFileToString(const fs::path &filename) -> std::string
    {
        constexpr auto tar_buf = 8192 * 4;
        auto file              = std::fopen(filename.c_str(), "r");
        if (file == nullptr) {
            return {};
        }
        auto _            = gsl::finally([file] { std::fclose(file); });
        const auto length = utils::filesystem::filelength(file);

        if (length >= tar_buf) {
            LOG_ERROR("File %s length is too high!", filename.c_str());
            return {};
        }
        LOG_INFO("file length: %ld", length);
        auto buffer = std::make_unique<char[]>(length + 1);
        std::fread(buffer.get(), 1, length, file);
        return std::string(buffer.get());
    }
} // namespace app

A module-apps/application-settings-new/models/QuotesRepository.hpp => module-apps/application-settings-new/models/QuotesRepository.hpp +58 -0
@@ 0,0 1,58 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <json/json11.hpp>

#include <list>
#include <functional>
#include <module-apps/Application.hpp>

namespace app
{
    struct QuoteRecord
    {
        int id = 0;
        std::string quote;
        std::string author;

        [[nodiscard]] auto to_json() const -> json11::Json
        {
            return json11::Json::object{{"quote", quote}, {"author", author}};
        }
    };

    class QuotesRepository
    {
      public:
        using OnGetCallback = std::function<bool(const std::list<QuoteRecord> &, unsigned int)>;

        virtual ~QuotesRepository() noexcept = default;

        virtual void get(std::uint32_t offset, std::uint32_t limit, const OnGetCallback &callback) = 0;
        virtual void save(const QuoteRecord &quote)                                                = 0;
        virtual void remove(const QuoteRecord &quote)                                              = 0;
    };

    class QuotesJsonRepository : public QuotesRepository
    {
      public:
        QuotesJsonRepository(const std::string &path);

        void get(std::uint32_t offset, std::uint32_t limit, const OnGetCallback &callback) override;
        void save(const QuoteRecord &quote) override;
        void remove(const QuoteRecord &quote) override;

      private:
        void writeQuotes(const fs::path &path);
        void readQuotes(const fs::path &fn);
        std::string readFileToString(const fs::path &fn);

        std::list<QuoteRecord> quotes;
        std::string repositoryPath;
    };
} // namespace app

A module-apps/application-settings-new/widgets/ApnInputWidget.cpp => module-apps/application-settings-new/widgets/ApnInputWidget.cpp +221 -0
@@ 0,0 1,221 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "ApnInputWidget.hpp"
#include <Span.hpp>
#include "application-settings-new/widgets/SettingsStyle.hpp"
#include <i18n/i18n.hpp>
#include <utility>

namespace gui
{
    ApnInputWidget::ApnInputWidget(settingsInternals::ListItemName listItemName,
                                   std::function<void(const UTF8 &)> bottomBarTemporaryMode,
                                   std::function<void()> bottomBarRestoreFromTemporaryMode,
                                   std::function<void()> selectSpecialCharacter,
                                   std::function<void()> contentChanged,
                                   unsigned int lines)
        : listItemName(listItemName), checkTextContent(std::move(contentChanged))
    {

        setMinimumSize(style::settings::widget::apnInputWidget::w,
                       style::settings::widget::apnInputWidget::title_label_h +
                           style::settings::widget::apnInputWidget::span_size +
                           style::settings::widget::apnInputWidget::input_text_h * lines);

        setMargins(gui::Margins(0, style::margins::huge, 0, 0));

        vBox = new VBox(this, 0, 0, 0, 0);
        vBox->setEdges(RectangleEdge::None);

        titleLabel = new Label(vBox);
        titleLabel->setMinimumSize(style::settings::widget::apnInputWidget::w,
                                   style::settings::widget::apnInputWidget::title_label_h);
        titleLabel->setEdges(RectangleEdge::None);
        titleLabel->setAlignment(Alignment(gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Top));
        titleLabel->setFont(style::window::font::verysmall);
        titleLabel->activeItem = false;

        inputText = new TextFixedSize(vBox, 0, 0, 0, 0);
        inputText->setMinimumSize(style::settings::widget::apnInputWidget::w,
                                  style::settings::widget::apnInputWidget::input_text_h * lines);
        inputText->setMargins(Margins(0, style::settings::widget::apnInputWidget::span_size, 0, 0));
        inputText->setUnderlinePadding(style::settings::widget::apnInputWidget::underline_padding);

        inputText->setEdges(RectangleEdge::None);
        inputText->setAlignment(Alignment(gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Top));
        inputText->setFont(style::window::font::medium);
        inputText->setInputMode(new InputMode(
            {InputMode::ABC, InputMode::abc, InputMode::digit},
            [=](const UTF8 &text) { bottomBarTemporaryMode(text); },
            [=]() { bottomBarRestoreFromTemporaryMode(); },
            [=]() { selectSpecialCharacter(); }));
        inputText->setPenFocusWidth(style::window::default_border_focus_w);
        inputText->setPenWidth(style::window::default_border_no_focus_w);
        inputText->setEditMode(EditMode::Edit);

        applyItemNameSpecificSettings();

        focusChangedCallback = [&](Item &item) {
            setFocusItem(focus ? vBox : nullptr);

            auto tempText = inputText->getText();

            if (focus) {
                inputText->setFont(style::window::font::mediumbold);
                inputText->setText(tempText);
            }
            else {
                inputText->setFont(style::window::font::medium);
                inputText->setText(tempText);
            }
            return true;
        };

        inputCallback = [&](Item &item, const InputEvent &event) {
            auto result = inputText->onInput(event);
            if (checkTextContent != nullptr) {
                checkTextContent();
            }
            return result;
        };
        setEdges(RectangleEdge::None);
    }

    auto ApnInputWidget::onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim) -> bool
    {
        vBox->setPosition(0, 0);
        vBox->setSize(newDim.w, newDim.h);

        return true;
    }

    void ApnInputWidget::applyItemNameSpecificSettings()
    {
        switch (listItemName) {

        case settingsInternals::ListItemName::Name:
            nameHandler();
            break;

        case settingsInternals::ListItemName::APN:
            apnHandler();
            break;

        case settingsInternals::ListItemName::Username:
            usernameHandler();
            break;

        case settingsInternals::ListItemName::Password:
            passwordNumberHandler();
            break;

        case settingsInternals::ListItemName::AuthType:
            authtypeHandler();
            break;

        case settingsInternals::ListItemName::ApnType:
            apntypeHandler();
            break;

        case settingsInternals::ListItemName::ApnProtocol:
            protocolHandler();
            break;

        default:
            LOG_ERROR("Incorrect List Item Name!");
            break;
        }
    }

    void ApnInputWidget::nameHandler()
    {
        titleLabel->setText(utils::localize.get("app_settings_apn_name"));
        inputText->setTextType(TextType::SingleLine);
        onSaveCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            apnRecord->apn = inputText->getText();
        };
        onLoadCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            inputText->setText(apnRecord->apn);
        };
        onEmptyCallback = [&]() { return inputText->isEmpty(); };
    }

    void ApnInputWidget::apnHandler()
    {
        titleLabel->setText(utils::localize.get("app_settings_apn_APN"));
        inputText->setTextType(TextType::SingleLine);
        onSaveCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            apnRecord->ip = inputText->getText();
        };
        onLoadCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            inputText->setText(apnRecord->ip);
        };
        onEmptyCallback = [&]() { return inputText->isEmpty(); };
    }

    void ApnInputWidget::usernameHandler()
    {
        titleLabel->setText(utils::localize.get("app_settings_apn_username"));
        inputText->setTextType(TextType::SingleLine);
        onSaveCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            apnRecord->username = inputText->getText();
        };
        onLoadCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            inputText->setText(apnRecord->username);
        };
        onEmptyCallback = [&]() { return inputText->isEmpty(); };
    }

    void ApnInputWidget::passwordNumberHandler()
    {
        titleLabel->setText(utils::localize.get("app_settings_apn_password"));
        inputText->setTextType(TextType::SingleLine);
        onSaveCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            apnRecord->password = inputText->getText();
        };
        onLoadCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            inputText->setText(apnRecord->password);
        };
        onEmptyCallback = [&]() { return inputText->isEmpty(); };
    }

    void ApnInputWidget::authtypeHandler()
    {
        titleLabel->setText(utils::localize.get("app_settings_apn_authtype"));
        inputText->setTextType(TextType::SingleLine);
        onSaveCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            apnRecord->setAuthMethod(inputText->getText());
        };
        onLoadCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            inputText->setText(apnRecord->getAuthMethod());
        };
        onEmptyCallback = [&]() { return inputText->isEmpty(); };
    }

    void ApnInputWidget::apntypeHandler()
    {
        titleLabel->setText(utils::localize.get("app_settings_apn_apntype"));
        inputText->setTextType(TextType::SingleLine);
        onSaveCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            apnRecord->setApnType(inputText->getText());
        };
        onLoadCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            inputText->setText(apnRecord->getApnType());
        };
        onEmptyCallback = [&]() { return inputText->isEmpty(); };
    }
    void ApnInputWidget::protocolHandler()
    {
        titleLabel->setText(utils::localize.get("app_settings_apn_apnprotocol"));
        inputText->setTextType(TextType::SingleLine);
        onSaveCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            apnRecord->setApnProtocol(inputText->getText());
        };
        onLoadCallback = [&](std::shared_ptr<packet_data::APN::Config> apnRecord) {
            inputText->setText(apnRecord->getApnProtocol());
        };
        onEmptyCallback = [&]() { return inputText->isEmpty(); };
    }

} /* namespace gui */

A module-apps/application-settings-new/widgets/ApnInputWidget.hpp => module-apps/application-settings-new/widgets/ApnInputWidget.hpp +44 -0
@@ 0,0 1,44 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "application-settings-new/data/SettingsInternals.hpp"
#include "application-settings-new//widgets/ApnListItem.hpp"

#include <ListItem.hpp>
#include <Text.hpp>
#include <TextFixedSize.hpp>

namespace gui
{
    class ApnInputWidget : public ApnListItem
    {
        settingsInternals::ListItemName listItemName;

      public:
        ApnInputWidget(settingsInternals::ListItemName listItemName,
                       std::function<void(const UTF8 &text)> bottomBarTemporaryMode = nullptr,
                       std::function<void()> bottomBarRestoreFromTemporaryMode      = nullptr,
                       std::function<void()> selectSpecialCharacter                 = nullptr,
                       std::function<void()> contentChanged                         = nullptr,
                       unsigned int lines                                           = 1);

      private:
        VBox *vBox                             = nullptr;
        Label *titleLabel                      = nullptr;
        TextFixedSize *inputText               = nullptr;
        std::function<void()> checkTextContent = nullptr;

        void applyItemNameSpecificSettings();
        auto onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim) -> bool override;
        void nameHandler();
        void apnHandler();
        void usernameHandler();
        void passwordNumberHandler();
        void authtypeHandler();
        void apntypeHandler();
        void protocolHandler();
    };

} /* namespace gui */

A module-apps/application-settings-new/widgets/ApnListItem.hpp => module-apps/application-settings-new/widgets/ApnListItem.hpp +18 -0
@@ 0,0 1,18 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "application-settings-new/data/SettingsItemData.hpp"

namespace gui
{
    class ApnListItem : public ListItem
    {
      public:
        std::function<void(std::shared_ptr<packet_data::APN::Config> apnRecord)> onSaveCallback = nullptr;
        std::function<void(std::shared_ptr<packet_data::APN::Config> apnRecord)> onLoadCallback = nullptr;
        std::function<bool()> onEmptyCallback                                                   = nullptr;
    };

} /* namespace gui */

A module-apps/application-settings-new/widgets/OptionSetting.hpp => module-apps/application-settings-new/widgets/OptionSetting.hpp +30 -0
@@ 0,0 1,30 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "SpinBox.hpp"
#include "OptionWindow.hpp"
#include "Application.hpp"

#include <module-apps/options/type/OptionSetting.hpp>

namespace gui
{
    class SpinBoxOptionSettings : public option::OptionSettings
    {
      public:
        SpinBoxOptionSettings(UTF8 text,
                              uint8_t value,
                              uint8_t maxValue,
                              std::function<bool(uint8_t)> updateCallback,
                              std::function<bool(Item &)> focusChangedCallback = nullptr);

        [[nodiscard]] auto build() const -> ListItem * override;

      private:
        std::function<bool(uint8_t)> updateCallback;
        std::uint8_t maxValue;
        std::uint8_t value;
    };
} // namespace gui

A module-apps/application-settings-new/widgets/QuoteWidget.cpp => module-apps/application-settings-new/widgets/QuoteWidget.cpp +117 -0
@@ 0,0 1,117 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "QuoteWidget.hpp"

#include <BottomBar.hpp>
#include <InputEvent.hpp>
#include <utility>
#include <i18n/i18n.hpp>

namespace style::quotes
{
    namespace widget
    {
        inline constexpr uint32_t w = style::window::default_body_width;
        inline constexpr uint32_t h = 50;

        inline constexpr uint32_t input_box_w           = 55;
        inline constexpr uint32_t input_box_h           = h;
        inline constexpr int32_t input_box_right_margin = 20;

        inline constexpr uint32_t description_label_w           = 280;
        inline constexpr uint32_t description_label_h           = 33;
        inline constexpr int32_t description_label_right_margin = 40;

        inline constexpr int32_t tick_image_left_margin  = -64;
        inline constexpr int32_t tick_image_right_margin = 32;

    } // namespace widget

} // namespace style::quotes

namespace gui
{

    QuoteWidget::QuoteWidget(const app::QuoteRecord &quote,
                             std::function<void(const UTF8 &)> bottomBarTemporaryMode,
                             std::function<void()> bottomBarRestoreFromTemporaryMode)
        : bottomBarTemporaryMode(std::move(bottomBarTemporaryMode)),
          bottomBarRestoreFromTemporaryMode(std::move(bottomBarRestoreFromTemporaryMode)), quote(quote)
    {

        setMinimumSize(style::quotes::widget::w, style::quotes::widget::h);

        setMargins(gui::Margins(0, style::margins::big, 0, 0));

        hBox = new gui::HBox(this, 0, 0, this->getWidth(), 80);
        hBox->setEdges(gui::RectangleEdge::None);
        hBox->setPenFocusWidth(style::window::default_border_focus_w);
        hBox->setPenWidth(style::window::default_border_rect_no_focus);

        inputBoxLabel = new gui::Label(hBox, 0, 0, 0, 0);
        inputBoxLabel->setMinimumSize(style::quotes::widget::input_box_w, style::quotes::widget::input_box_h);

        inputBoxLabel->setMargins(gui::Margins(0, 0, style::quotes::widget::input_box_right_margin, 0));
        inputBoxLabel->setEdges(gui::RectangleEdge::Bottom);
        inputBoxLabel->setAlignment(Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center));
        inputBoxLabel->setFont(style::window::font::medium);
        inputBoxLabel->activeItem = false;

        tickImage = new gui::Image(hBox, 0, 0, 0, 0);
        tickImage->setAlignment(Alignment(gui::Alignment::Vertical::Center));
        // Not ideal -> best solution would be to create separate widget with image inside box.
        tickImage->setMargins(gui::Margins(
            style::quotes::widget::tick_image_left_margin, 0, style::quotes::widget::tick_image_right_margin, 0));
        tickImage->set("small_tick_W_M");
        tickImage->setVisible(true);
        tickImage->activeItem = false;

        descriptionLabel = new gui::Label(hBox, 0, 0, 0, 0);
        descriptionLabel->setMinimumSize(style::quotes::widget::description_label_w,
                                         style::quotes::widget::description_label_h);
        descriptionLabel->setMargins(gui::Margins(0, 0, style::quotes::widget::description_label_right_margin, 0));
        descriptionLabel->setEdges(gui::RectangleEdge::None);
        descriptionLabel->setAlignment(Alignment(gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Center));
        descriptionLabel->setFont(style::window::font::medium);
        descriptionLabel->activeItem = false;

        descriptionLabel->setText(quote.quote);

        focusChangedCallback = [&](gui::Item &item) {
            if (item.focus) {
                descriptionLabel->setFont(style::footer::font::bold);
                setFocusItem(inputBoxLabel);
                auto bottorBarText =
                    tickImage->visible ? utils::localize.get("common_uncheck") : utils::localize.get("common_check");
                this->bottomBarTemporaryMode(bottorBarText);
            }
            else {
                descriptionLabel->setFont(style::footer::font::medium);
                setFocusItem(nullptr);
                this->bottomBarRestoreFromTemporaryMode();
            }
            return true;
        };

        activatedCallback = [&](gui::Item &item) {
            tickImage->setVisible(!tickImage->visible);
            auto bottorBarText =
                tickImage->visible ? utils::localize.get("common_uncheck") : utils::localize.get("common_check");
            this->bottomBarTemporaryMode(bottorBarText);
            hBox->resizeItems();
            return true;
        };

        setEdges(gui::RectangleEdge::None);
    }

    auto QuoteWidget::onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim) -> bool
    {
        hBox->setPosition(0, 0);
        hBox->setSize(newDim.w, newDim.h);

        return true;
    }

} /* namespace gui */

A module-apps/application-settings-new/widgets/QuoteWidget.hpp => module-apps/application-settings-new/widgets/QuoteWidget.hpp +42 -0
@@ 0,0 1,42 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "application-settings-new/data/QuoteSwitchData.hpp"

#include <BoxLayout.hpp>
#include <Image.hpp>
#include <Label.hpp>
#include <ListItem.hpp>
#include <json/json11.hpp>

namespace gui
{
    class QuoteWidget : public ListItem
    {
      public:
        QuoteWidget(const app::QuoteRecord &quote,
                    std::function<void(const UTF8 &text)> bottomBarTemporaryMode = nullptr,
                    std::function<void()> bottomBarRestoreFromTemporaryMode      = nullptr);

        auto onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim) -> bool override;

        [[nodiscard]] auto getQuoteData() const -> app::QuoteRecord
        {
            return quote;
        }

      private:
        gui::HBox *hBox              = nullptr;
        gui::Label *inputBoxLabel    = nullptr;
        gui::Label *descriptionLabel = nullptr;
        gui::Image *tickImage        = nullptr;

        std::function<void(const UTF8 &text)> bottomBarTemporaryMode = nullptr;
        std::function<void()> bottomBarRestoreFromTemporaryMode      = nullptr;

        app::QuoteRecord quote;
    };

} /* namespace gui */

M module-apps/application-settings-new/widgets/SettingsStyle.hpp => module-apps/application-settings-new/widgets/SettingsStyle.hpp +20 -0
@@ 28,7 28,18 @@ namespace style
                inline constexpr auto before_noon             = "AM";
                inline constexpr auto after_noon              = "PM";
            } // namespace time

            namespace apnInputWidget
            {
                inline constexpr uint32_t w                = style::window::default_body_width;
                inline constexpr uint32_t h                = 63;
                inline constexpr uint32_t title_label_h    = 20;
                inline constexpr uint32_t input_text_h     = 37;
                inline constexpr uint32_t span_size        = 6;
                inline constexpr int32_t underline_padding = 4;
            } // namespace apnInputWidget
        }     // namespace widget

        namespace window
        {
            namespace leftArrowImage


@@ 70,6 81,15 @@ namespace style

                inline constexpr auto separator_h = 55;
            } // namespace nightshift

            namespace newApn
            {
                inline constexpr uint32_t x = style::window::default_left_margin;
                inline constexpr uint32_t y = style::header::height;
                inline constexpr uint32_t w = style::listview::body_width_with_scroll;
                inline constexpr uint32_t h = style::window_height - y - style::footer::height;
            } // namespace newApn

        }     // namespace window
    };        // namespace settings
} // namespace style

A module-apps/application-settings-new/widgets/SpinBox.cpp => module-apps/application-settings-new/widgets/SpinBox.cpp +93 -0
@@ 0,0 1,93 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "SpinBox.hpp"
#include "widgets/BarGraph.hpp"

#include <InputEvent.hpp>
#include <Label.hpp>
#include <Image.hpp>
#include <utf8/UTF8.hpp>
#include <utility>

namespace gui
{
    SpinBox::SpinBox(
        Item *parent, const std::string &title, UpdateCallback updateCallback, uint8_t maxValue, uint8_t startValue)
        : HBox(parent, style::window::default_left_margin), updateBarCallback(std::move(updateCallback))
    {
        setMinimumSize(style::window::default_body_width, style::window::label::big_h);
        setPenWidth(style::window::default_border_no_focus_w);
        setPenFocusWidth(style::window::default_border_focus_w);
        setEdges(gui::RectangleEdge::Top | gui::RectangleEdge::Bottom);

        titleLabel = addTitle(this, title);
        leftArrow  = addArrow(this, "arrow_left", Alignment::Horizontal::Left, false);
        rightArrow = addArrow(this, "arrow_right", Alignment::Horizontal::Right, false);
        bar        = addBarGraph(this, maxValue, startValue);

        focusChangedCallback = [this](Item &item) {
            leftArrow->setVisible(item.focus);
            rightArrow->setVisible(item.focus);
            resizeItems();
            return true;
        };

        inputCallback = [this](gui::Item &item, const gui::InputEvent &event) {
            if (!event.isShortPress()) {
                return false;
            }

            int update = 0;
            if (event.is(KeyCode::KEY_LEFT)) {
                update = -1;
            }
            else if (event.is(KeyCode::KEY_RIGHT)) {
                update = 1;
            }

            if (update != 0 && bar->update(update)) {
                updateBarCallback(bar->getValue());
                return true;
            }

            return false;
        };
    }

    Image *SpinBox::addArrow(Item *parent, const std::string &arrowName, Alignment::Horizontal aligment, bool visible)
    {
        auto arrow = new Image(parent, 0, 0, 0, 0);
        arrow->setAlignment(Alignment(aligment, Alignment::Vertical::Center));
        arrow->setMargins(Margins(0, 0, style::margins::big, 0));
        arrow->set(arrowName);
        arrow->setVisible(visible);

        return arrow;
    }

    Label *SpinBox::addTitle(Item *parent, const std::string &text)
    {
        auto label = new Label(parent);
        label->setMinimumHeight(style::window::label::default_h);
        label->setMaximumWidth(style::window::default_body_width);

        label->setEdges(RectangleEdge::None);
        label->setAlignment(Alignment(gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Center));
        label->setFont(style::window::font::big);
        label->setText(text);
        label->activeItem = false;

        return label;
    }

    HBarGraph *SpinBox::addBarGraph(Item *parent, uint8_t maxValue, uint8_t startValue)
    {
        auto barGraph = new HBarGraph(parent, 0, 0, maxValue);
        barGraph->setAlignment(Alignment(gui::Alignment::Horizontal::Right, gui::Alignment::Vertical::Center));
        barGraph->setValue(startValue);
        barGraph->activeItem = false;

        return barGraph;
    }
} // namespace gui

A module-apps/application-settings-new/widgets/SpinBox.hpp => module-apps/application-settings-new/widgets/SpinBox.hpp +43 -0
@@ 0,0 1,43 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once
#include "widgets/BarGraph.hpp"

namespace style::settings::brightness
{
    inline constexpr auto max_value = 6;
};

class UTF8;

namespace gui
{
    class Image;
    class SpinBox : public HBox
    {
      public:
        using UpdateCallback = std::function<bool(uint8_t)>;

        SpinBox(Item *parent,
                const std::string &title,
                UpdateCallback updateCallback,
                std::uint8_t maxValue   = style::settings::brightness::max_value,
                std::uint8_t startValue = 0);

      private:
        auto addArrow(Item *parent, const std::string &arrowName, Alignment::Horizontal aligment, bool visible)
            -> Image *;
        auto addBarGraph(Item *parent, uint8_t maxValue, uint8_t startValue) -> HBarGraph *;
        auto addTitle(Item *parent, const std::string &text) -> Label *;

        HBarGraph *bar;
        Label *titleLabel;
        Image *leftArrow;
        Image *rightArrow;
        UpdateCallback updateBarCallback;
    };
} // namespace gui

A module-apps/application-settings-new/widgets/SpinBoxOptionSetting.cpp => module-apps/application-settings-new/widgets/SpinBoxOptionSetting.cpp +41 -0
@@ 0,0 1,41 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "OptionSetting.hpp"

#include <utility>
#include "SpinBox.hpp"

namespace gui
{
    SpinBoxOptionSettings::SpinBoxOptionSettings(UTF8 text,
                                                 std::uint8_t value,
                                                 std::uint8_t maxValue,
                                                 std::function<bool(uint8_t)> updateCallback,
                                                 std::function<bool(Item &)> focusChangedCallback)
        : option::OptionSettings(text, nullptr, focusChangedCallback, nullptr),
          updateCallback(std::move(updateCallback)), maxValue(maxValue), value(value)
    {}

    auto SpinBoxOptionSettings::build() const -> ListItem *
    {
        auto spinBox = new SpinBox(nullptr, text, updateCallback, maxValue, value);

        auto optionItem = new gui::ListItem();
        optionItem->setMinimumSize(style::window::default_body_width, style::window::label::big_h);
        optionItem->inputCallback        = spinBox->inputCallback;
        optionItem->focusChangedCallback = [spinBox, this](Item &item) {
            spinBox->focusChangedCallback(item);
            return focusChangedCallback(item);
        };
        optionItem->dimensionChangedCallback = [spinBox](gui::Item &, const BoundingBox &newDim) -> bool {
            spinBox->setPosition(0, 0);
            spinBox->setSize(newDim.w, newDim.h);
            return true;
        };

        optionItem->addWidget(spinBox);

        return optionItem;
    }
} // namespace gui

D module-apps/application-settings-new/windows/APNSettingsWindow.cpp => module-apps/application-settings-new/windows/APNSettingsWindow.cpp +0 -61
@@ 1,61 0,0 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "APNSettingsWindow.hpp"
#include "application-settings-new/ApplicationSettings.hpp"
#include "application-settings-new/widgets/SettingsStyle.hpp"
#include "OptionSetting.hpp"

#include <InputEvent.hpp>

namespace gui
{

    APNSettingsWindow::APNSettingsWindow(app::Application *app) : OptionWindow(app, gui::window::name::apn_settings)
    {
        buildInterface();
    }

    auto APNSettingsWindow::onInput(const InputEvent &inputEvent) -> bool
    {

        if (inputEvent.isShortPress()) {
            if (inputEvent.is(KeyCode::KEY_LEFT)) {
                // switch to new/edit APN window
            }
        }

        return AppWindow::onInput(inputEvent);
    }
    void APNSettingsWindow::buildInterface()
    {
        setTitle(utils::localize.get("app_settings_network_apn_settings"));

        topBar->setActive(TopBar::Elements::SIGNAL, false);
        topBar->setActive(TopBar::Elements::BATTERY, false);
        topBar->setActive(TopBar::Elements::SIM, false);

        leftArrowImage = new gui::Image(this,
                                        style::settings::window::leftArrowImage::x,
                                        style::settings::window::leftArrowImage::y,
                                        style::settings::window::leftArrowImage::w,
                                        style::settings::window::leftArrowImage::h,
                                        "arrow_left");
        crossImage     = new gui::Image(this,
                                    style::settings::window::crossImage::x,
                                    style::settings::window::crossImage::y,
                                    style::settings::window::crossImage::w,
                                    style::settings::window::crossImage::h,
                                    "cross");
        emptyListIcon  = new Icon(this,
                                 0,
                                 style::header::height,
                                 style::window_width,
                                 style::window_height - style::header::height - style::footer::height,
                                 "phonebook_empty_grey_circle_W_G",
                                 utils::localize.get("app_settings_network_apn_settings_no_apns"));

        bottomBar->setActive(gui::BottomBar::Side::CENTER, false);
    }

} // namespace gui

M module-apps/application-settings-new/windows/AllDevicesWindow.cpp => module-apps/application-settings-new/windows/AllDevicesWindow.cpp +0 -4
@@ 71,10 71,6 @@ namespace gui
                gui::option::SettingRightItem::Bt));
        }

        topBar->setActive(TopBar::Elements::SIGNAL, false);
        topBar->setActive(TopBar::Elements::BATTERY, false);
        topBar->setActive(TopBar::Elements::SIM, false);

        leftArrowImage = new gui::Image(this,
                                        style::settings::window::leftArrowImage::x,
                                        style::settings::window::leftArrowImage::y,

A module-apps/application-settings-new/windows/ApnOptionsWindow.cpp => module-apps/application-settings-new/windows/ApnOptionsWindow.cpp +73 -0
@@ 0,0 1,73 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "ApnOptionsWindow.hpp"

#include "application-settings-new/ApplicationSettings.hpp"
#include "application-settings-new/data/SettingsItemData.hpp"
#include "application-settings-new/models/ApnSettingsModel.hpp"
#include "OptionSetting.hpp"

namespace gui
{
    ApnOptionsWindow::ApnOptionsWindow(app::Application *app) : BaseSettingsWindow(app, window::name::apn_options)
    {
        setTitle(utils::localize.get("app_settings_apn_options"));
        apnSettingsModel = new ApnSettingsModel(application);
    }

    auto ApnOptionsWindow::buildOptionsList() -> std::list<gui::Option>
    {
        std::list<gui::Option> optionsList;

        optionsList.emplace_back(std::make_unique<gui::option::OptionSettings>(
            utils::localize.get("app_settings_apn_options_edit"),
            [=](gui::Item &item) {
                std::unique_ptr<gui::SwitchData> data = std::make_unique<ApnItemData>(apn);
                application->switchWindow(gui::window::name::new_apn, gui::ShowMode::GUI_SHOW_INIT, std::move(data));
                return true;
            },
            nullptr,
            this));

        optionsList.emplace_back(std::make_unique<gui::option::OptionSettings>(
            utils::localize.get("app_settings_apn_options_delete"),
            [=](gui::Item &item) {
                apnSettingsModel->removeAPN(apn);
                return true;
            },
            nullptr,
            this));

        optionsList.emplace_back(std::make_unique<gui::option::OptionSettings>(
            utils::localize.get("app_settings_apn_options_set_as_default"),
            [=](gui::Item &item) {
                apnSettingsModel->setAsDefaultAPN(apn);
                return true;
            },
            nullptr,
            this));

        return optionsList;
    }

    auto ApnOptionsWindow::handleSwitchData(SwitchData *data) -> bool
    {
        if (data == nullptr) {
            return false;
        }

        auto item = dynamic_cast<ApnItemData *>(data);
        if (item == nullptr) {
            return false;
        }

        apn = item->getApn();
        if (apn == nullptr) {
            apn = std::make_shared<packet_data::APN::Config>();
            return true;
        }

        return true;
    }
} // namespace gui

A module-apps/application-settings-new/windows/ApnOptionsWindow.hpp => module-apps/application-settings-new/windows/ApnOptionsWindow.hpp +25 -0
@@ 0,0 1,25 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "application-settings-new/models/ApnSettingsModel.hpp"
#include "BaseSettingsWindow.hpp"

#include <service-cellular/PacketDataTypes.hpp>

namespace gui
{

    class ApnOptionsWindow : public BaseSettingsWindow
    {
      public:
        ApnOptionsWindow(app::Application *app);

      private:
        auto buildOptionsList() -> std::list<gui::Option> override;
        auto handleSwitchData(SwitchData *data) -> bool override;
        std::shared_ptr<packet_data::APN::Config> apn;
        ApnSettingsModel *apnSettingsModel = nullptr;
    };
} // namespace gui

A module-apps/application-settings-new/windows/ApnSettingsWindow.cpp => module-apps/application-settings-new/windows/ApnSettingsWindow.cpp +135 -0
@@ 0,0 1,135 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "ApnSettingsWindow.hpp"
#include "application-settings-new/ApplicationSettings.hpp"
#include "application-settings-new/data/ApnListData.hpp"
#include "application-settings-new/models/ApnSettingsModel.hpp"
#include "application-settings-new/widgets/SettingsStyle.hpp"
#include "application-settings-new/data/SettingsItemData.hpp"
#include "OptionSetting.hpp"

#include <InputEvent.hpp>

namespace gui
{

    ApnSettingsWindow::ApnSettingsWindow(app::Application *app) : OptionWindow(app, gui::window::name::apn_settings)
    {
        buildInterface();
    }

    void ApnSettingsWindow::buildInterface()
    {
        setTitle(utils::localize.get("app_settings_network_apn_settings"));

        leftArrowImage = new gui::Image(this,
                                        style::settings::window::leftArrowImage::x,
                                        style::settings::window::leftArrowImage::y,
                                        style::settings::window::leftArrowImage::w,
                                        style::settings::window::leftArrowImage::h,
                                        "arrow_left");
        crossImage     = new gui::Image(this,
                                    style::settings::window::crossImage::x,
                                    style::settings::window::crossImage::y,
                                    style::settings::window::crossImage::w,
                                    style::settings::window::crossImage::h,
                                    "cross");
        emptyListIcon  = new Icon(this,
                                 0,
                                 style::header::height,
                                 style::window_width,
                                 style::window_height - style::header::height - style::footer::height,
                                 "phonebook_empty_grey_circle_W_G",
                                 utils::localize.get("app_settings_apn_settings_no_apns"));

        bottomBar->setText(BottomBar::Side::LEFT, utils::localize.get(style::strings::common::options));

        auto apnSettingsModel = new ApnSettingsModel(application);
        apnSettingsModel->requestAPNList();
    }
    auto ApnSettingsWindow::handleSwitchData(SwitchData *data) -> bool
    {
        if (data == nullptr) {
            LOG_ERROR("Received nullptr");
            return false;
        }

        const auto newData = dynamic_cast<ApnListData *>(data);
        if (newData == nullptr) {
            LOG_ERROR("Received nullptr");
            return false;
        }

        apns = newData->getAPNs();
        if (apns.empty()) {
            emptyListIcon->setVisible(true);
            return false;
        }

        return true;
    }

    void ApnSettingsWindow::onBeforeShow(ShowMode mode, SwitchData *data)
    {
        clearOptions();
        bottomBar->setActive(gui::BottomBar::Side::LEFT, false);
        bottomBar->setActive(gui::BottomBar::Side::CENTER, false);
        emptyListIcon->setVisible(false);

        if (apns.empty()) {
            return;
        }

        addOptions(optionsList(apns));
        bottomBar->setActive(gui::BottomBar::Side::LEFT, true);
        bottomBar->setActive(gui::BottomBar::Side::CENTER, true);
    }

    auto ApnSettingsWindow::onInput(const InputEvent &inputEvent) -> bool
    {
        if (AppWindow::onInput(inputEvent)) {
            return true;
        }
        if (!inputEvent.isShortPress()) {
            return false;
        }
        if (inputEvent.is(gui::KeyCode::KEY_LEFT)) {
            auto apnRecord                        = std::make_shared<packet_data::APN::Config>();
            std::unique_ptr<gui::SwitchData> data = std::make_unique<ApnItemData>(apnRecord);
            application->switchWindow(gui::window::name::new_apn, gui::ShowMode::GUI_SHOW_INIT, std::move(data));
            return true;
        }
        if (inputEvent.is(gui::KeyCode::KEY_LF)) {
            auto apnRecord                        = std::make_shared<packet_data::APN::Config>();
            std::unique_ptr<gui::SwitchData> data = std::make_unique<ApnItemData>(apnRecord);
            application->switchWindow(gui::window::name::apn_options, gui::ShowMode::GUI_SHOW_INIT, std::move(data));
            return true;
        }

        return false;
    }

    auto ApnSettingsWindow::optionsList(std::vector<std::shared_ptr<packet_data::APN::Config>> apnsList)
        -> std::list<Option>
    {
        std::list<gui::Option> optionsList;

        for (const auto &apn : apnsList) {
            optionsList.emplace_back(std::make_unique<gui::option::OptionSettings>(
                (apn->apnType == packet_data::APN::APNType::Default) ? "<b>" + apn->apn + "</b>" : apn->apn,
                [=](gui::Item &item) {
                    LOG_DEBUG("APN: %s", apn->apn.c_str());
                    std::unique_ptr<gui::SwitchData> apnData = std::make_unique<ApnItemData>(apn);
                    application->switchWindow(
                        gui::window::name::new_apn, gui::ShowMode::GUI_SHOW_INIT, std::move(apnData));
                    return true;
                },
                nullptr,
                nullptr));
        }

        return optionsList;
    }

} // namespace gui

R module-apps/application-settings-new/windows/APNSettingsWindow.hpp => module-apps/application-settings-new/windows/ApnSettingsWindow.hpp +7 -2
@@ 5,20 5,25 @@

#include "OptionWindow.hpp"
#include <Icon.hpp>
#include <service-cellular/PacketDataTypes.hpp>

namespace gui
{
    class APNSettingsWindow : public OptionWindow
    class ApnSettingsWindow : public OptionWindow
    {
      public:
        APNSettingsWindow(app::Application *app);
        ApnSettingsWindow(app::Application *app);

      private:
        void buildInterface() override;
        auto handleSwitchData(SwitchData *data) -> bool override;
        void onBeforeShow(ShowMode mode, SwitchData *data) override;
        auto onInput(const InputEvent &inputEvent) -> bool override;
        auto optionsList(std::vector<std::shared_ptr<packet_data::APN::Config>> vector) -> std::list<Option>;

        Image *leftArrowImage = nullptr;
        Image *crossImage     = nullptr;
        Icon *emptyListIcon   = nullptr;
        std::vector<std::shared_ptr<packet_data::APN::Config>> apns;
    };
}; // namespace gui

M module-apps/application-settings-new/windows/AppsAndToolsWindow.cpp => module-apps/application-settings-new/windows/AppsAndToolsWindow.cpp +0 -4
@@ 33,10 33,6 @@ namespace gui
                                                gui::option::Arrow::Enabled});
        };

        topBar->setActive(TopBar::Elements::SIGNAL, false);
        topBar->setActive(TopBar::Elements::BATTERY, false);
        topBar->setActive(TopBar::Elements::SIM, false);

        addMenu(i18("app_settings_apps_messages"), gui::window::name::messages);
        addMenu(i18("app_settings_apps_torch"), gui::window::name::torch);


M module-apps/application-settings-new/windows/BaseSettingsWindow.cpp => module-apps/application-settings-new/windows/BaseSettingsWindow.cpp +0 -4
@@ 2,7 2,6 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "BaseSettingsWindow.hpp"

#include <i18n/i18n.hpp>

namespace gui


@@ 17,9 16,6 @@ namespace gui

        bottomBar->setActive(BottomBar::Side::RIGHT, true);
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
        topBar->setActive(TopBar::Elements::BATTERY, false);
        topBar->setActive(TopBar::Elements::SIM, false);
        topBar->setActive(TopBar::Elements::TIME, true);
    }

    void BaseSettingsWindow::destroyInterface()

M module-apps/application-settings-new/windows/BaseSettingsWindow.hpp => module-apps/application-settings-new/windows/BaseSettingsWindow.hpp +1 -0
@@ 6,6 6,7 @@
#include "Application.hpp"
#include "windows/AppWindow.hpp"
#include "windows/OptionWindow.hpp"
#include <service-db/Settings.hpp>

namespace gui
{

M module-apps/application-settings-new/windows/BluetoothWindow.cpp => module-apps/application-settings-new/windows/BluetoothWindow.cpp +0 -2
@@ 15,8 15,6 @@ namespace gui

    BluetoothWindow::BluetoothWindow(app::Application *app) : OptionWindow(app, gui::window::name::bluetooth)
    {
        topBar->setActive(TopBar::Elements::BATTERY, false);
        topBar->setActive(TopBar::Elements::SIM, false);
        sys::Bus::SendUnicast(
            std::make_shared<::message::bluetooth::RequestStatus>(), service::name::bluetooth, application);
    }

M module-apps/application-settings-new/windows/ChangePasscodeWindow.cpp => module-apps/application-settings-new/windows/ChangePasscodeWindow.cpp +0 -8
@@ 76,14 76,6 @@ namespace gui
        setTitle(utils::localize.get("app_settings_security_change_passcode"));
    }

    void ChangePasscodeWindow::buildTopBar()
    {
        topBar->setActive(TopBar::Elements::SIM, false);
        topBar->setActive(TopBar::Elements::LOCK, false);
        topBar->setActive(TopBar::Elements::BATTERY, false);
        topBar->setActive(TopBar::Elements::TIME, true);
    }

    void ChangePasscodeWindow::destroyInterface()
    {
        erase();

M module-apps/application-settings-new/windows/ChangePasscodeWindow.hpp => module-apps/application-settings-new/windows/ChangePasscodeWindow.hpp +0 -1
@@ 21,7 21,6 @@ namespace gui
        void buildBottomBar() override;
        void buildInterface() override;
        void buildTitleBar() override;
        void buildTopBar() override;
        void destroyInterface() override;
        void onBeforeShow(ShowMode mode, SwitchData *data) override;
        void processPasscode();

M module-apps/application-settings-new/windows/DisplayLightWindow.cpp => module-apps/application-settings-new/windows/DisplayLightWindow.cpp +50 -14
@@ 2,23 2,37 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "DisplayLightWindow.hpp"

#include "application-settings-new/widgets/OptionSetting.hpp"
#include "OptionSetting.hpp"
#include "application-settings-new/ApplicationSettings.hpp"
#include "OptionSetting.hpp"

#include <service-evtmgr/screen-light-control/ScreenLightControl.hpp>
#include <i18n/i18n.hpp>
#include <Service/Bus.hpp>

namespace gui
{
    DisplayLightWindow::DisplayLightWindow(app::Application *app) : BaseSettingsWindow(app, window::name::display_light)
    DisplayLightWindow::DisplayLightWindow(app::Application *app, app::settingsInterface::ScreenLightSettings *settings)
        : BaseSettingsWindow(app, window::name::display_light), screenLightSettings(settings)
    {
        auto values = screenLightSettings->getCurrentValues();

        isDisplayLightSwitchOn = values.lightOn;
        isAutoLightSwitchOn    = values.mode == screen_light_control::ScreenLightMode::Automatic;
        brightnessValue        = values.parameters.manualModeBrightness;

        setTitle(utils::localize.get("app_settings_display_display_light"));
    }

    void DisplayLightWindow::switchHandler(bool &onOffSwitch)
    {
        onOffSwitch = !onOffSwitch;

        rebuildOptionList();

        screenLightSettings->setStatus(isDisplayLightSwitchOn);
        screenLightSettings->setMode(isAutoLightSwitchOn);
    }

    auto DisplayLightWindow::buildOptionsList() -> std::list<gui::Option>


@@ 49,21 63,43 @@ namespace gui
        }

        if (isDisplayLightSwitchOn && !isAutoLightSwitchOn) {
            optionsList.emplace_back(std::make_unique<gui::option::OptionSettings>(
                utils::translateI18("app_settings_display_light_brightness"),
                [=](gui::Item &item) { return true; },
                [=](gui::Item &item) {
                    if (item.focus) {
                        this->setBottomBarText(utils::translateI18(style::strings::common::set),
                                               BottomBar::Side::CENTER);
                    }
                    return true;
                },
                this,
                gui::option::SettingRightItem::ArrowWhite));
            addBrightnessOption(optionsList);
        }

        return optionsList;
    }

    auto DisplayLightWindow::createBrightnessOption(int brightnessStep) -> std::unique_ptr<SpinBoxOptionSettings>
    {
        auto setBrightness = [this, brightnessStep](uint8_t value) {
            screenLightSettings->setBrightness(value * brightnessStep);
            return true;
        };

        auto setBottomBarOnSpinnerFocus = [&](gui::Item &item) {
            if (item.focus) {
                setBottomBarText(utils::translateI18(style::strings::common::set), BottomBar::Side::CENTER);
            }
            return true;
        };

        auto spinner = std::make_unique<gui::SpinBoxOptionSettings>(
            utils::translateI18("app_settings_display_light_brightness") + " " + utils::to_string(brightnessStep),
            brightnessValue * brightnessStep,
            std::ceil(screen_light_control::Parameters::MAX_BRIGHTNESS / brightnessStep),
            setBrightness,
            setBottomBarOnSpinnerFocus);

        return spinner;
    }

    void DisplayLightWindow::addBrightnessOption(std::list<gui::Option> &options)
    {
        /*
         * We are adding 4 brightness widgets to easily check what is the best step for setting screen brightness.
         */
        for (auto step : {10, 15, 20, 25}) {
            options.emplace_back(createBrightnessOption(step));
        }
    }
} // namespace gui

M module-apps/application-settings-new/windows/DisplayLightWindow.hpp => module-apps/application-settings-new/windows/DisplayLightWindow.hpp +13 -5
@@ 3,21 3,29 @@

#pragma once

#include <module-services/service-evtmgr/screen-light-control/ScreenLightControl.hpp>
#include <module-apps/application-settings-new/widgets/SpinBox.hpp>
#include <module-apps/application-settings-new/ApplicationSettings.hpp>
#include <module-apps/application-settings-new/widgets/OptionSetting.hpp>
#include "BaseSettingsWindow.hpp"

namespace gui
{

    class DisplayLightWindow : public BaseSettingsWindow
    {
      public:
        DisplayLightWindow(app::Application *app);
        DisplayLightWindow(app::Application *app, app::settingsInterface::ScreenLightSettings *screenLightSettings);

      private:
        void switchHandler(bool &onOffSwitch);
        auto buildOptionsList() -> std::list<Option> override;
        void switchHandler(bool &onOffSwitch);

        void addBrightnessOption(std::list<Option> &);
        auto createBrightnessOption(int step) -> std::unique_ptr<SpinBoxOptionSettings>;

        bool isDisplayLightSwitchOn = false;
        bool isAutoLightSwitchOn    = false;
        bool isDisplayLightSwitchOn                                      = false;
        bool isAutoLightSwitchOn                                         = false;
        std::uint8_t brightnessValue                                     = 0;
        app::settingsInterface::ScreenLightSettings *screenLightSettings = nullptr;
    };
} // namespace gui

M module-apps/application-settings-new/windows/MessagesWindow.cpp => module-apps/application-settings-new/windows/MessagesWindow.cpp +0 -3
@@ 64,9 64,6 @@ namespace gui
        };

        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::select));
        topBar->setActive(TopBar::Elements::SIGNAL, false);
        topBar->setActive(TopBar::Elements::BATTERY, false);
        topBar->setActive(TopBar::Elements::SIM, false);

        addMenuSwitch(utils::translateI18("app_settings_show_unread_first"), "");
        addMenu(utils::translateI18("app_settings_Templates"), gui::window::name::templates);

M module-apps/application-settings-new/windows/NetworkWindow.cpp => module-apps/application-settings-new/windows/NetworkWindow.cpp +0 -3
@@ 122,9 122,6 @@ namespace gui

        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::select));

        topBar->setActive(TopBar::Elements::SIGNAL, false);
        topBar->setActive(TopBar::Elements::BATTERY, false);
        topBar->setActive(TopBar::Elements::SIM, false);
        return optList;
    }
    void NetworkWindow::rebuild()

A module-apps/application-settings-new/windows/NewApnWindow.cpp => module-apps/application-settings-new/windows/NewApnWindow.cpp +119 -0
@@ 0,0 1,119 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "NewApnWindow.hpp"
#include "application-settings-new/ApplicationSettings.hpp"

#include <Dialog.hpp>
#include <messages/DialogMetadataMessage.hpp>

namespace gui
{

    NewApnWindow::NewApnWindow(app::Application *app)
        : AppWindow(app, gui::window::name::new_apn), newApnModel{std::make_shared<NewApnModel>(app)}
    {
        buildInterface();
    }

    void NewApnWindow::rebuild()
    {
        destroyInterface();
        buildInterface();
    }

    void NewApnWindow::buildInterface()
    {
        AppWindow::buildInterface();

        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::save));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        setTitle(utils::localize.get("app_settings_new_edit_apn"));

        list = new gui::ListView(this,
                                 style::settings::window::newApn::x,
                                 style::settings::window::newApn::y,
                                 style::settings::window::newApn::w,
                                 style::settings::window::newApn::h,
                                 newApnModel);
        setFocusItem(list);
        apnSettingsModel = new ApnSettingsModel(application);
    }

    void NewApnWindow::destroyInterface()
    {
        erase();
    }

    void NewApnWindow::onBeforeShow(ShowMode mode, SwitchData *data)
    {
        if (mode != ShowMode::GUI_SHOW_RETURN) {
            newApnModel->clearData();
        }

        if (mode == ShowMode::GUI_SHOW_INIT) {
            list->rebuildList();
        }

        if (apn != nullptr) {
            newApnModel->loadData(apn);
        }
    }

    auto NewApnWindow::handleSwitchData(SwitchData *data) -> bool
    {
        setSaveButtonVisible(false);

        if (data == nullptr) {
            return false;
        }

        auto *item = dynamic_cast<ApnItemData *>(data);
        if (item == nullptr) {
            return false;
        }

        apn = item->getApn();
        if (apn == nullptr) {
            apn = std::make_shared<packet_data::APN::Config>();
            return true;
        }

        return true;
    }

    void NewApnWindow::setSaveButtonVisible(bool visible)
    {
        bottomBar->setActive(BottomBar::Side::CENTER, visible);
    }

    auto NewApnWindow::onInput(const InputEvent &inputEvent) -> bool
    {
        if (!inputEvent.isShortPress()) {
            return false;
        }
        if (inputEvent.is(gui::KeyCode::KEY_ENTER)) {
            if (apn != nullptr) {
                newApnModel->saveData(apn);
            }
            verifyAndSave();
            return true;
        }

        return AppWindow::onInput(inputEvent);
    }

    auto NewApnWindow::verifyAndSave() -> bool
    {
        if (apn == nullptr) {
            LOG_DEBUG("APN record not found");
            return false;
        }
        apnSettingsModel->saveAPN(apn);
        LOG_DEBUG("APN record  saved : \"%s\" ", apn->apn.c_str());

        return true;
    }

} // namespace gui

A module-apps/application-settings-new/windows/NewApnWindow.hpp => module-apps/application-settings-new/windows/NewApnWindow.hpp +35 -0
@@ 0,0 1,35 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "application-settings-new/models/ApnSettingsModel.hpp"
#include "application-settings-new/models/NewApnModel.hpp"

#include <AppWindow.hpp>
#include <ListView.hpp>
#include <Text.hpp>

namespace gui
{
    class NewApnWindow : public AppWindow
    {
      public:
        NewApnWindow(app::Application *app);

      private:
        auto onInput(const InputEvent &inputEvent) -> bool override;
        void onBeforeShow(ShowMode mode, SwitchData *data) override;
        auto handleSwitchData(SwitchData *data) -> bool override;
        void rebuild() override;
        void buildInterface() override;
        void destroyInterface() override;
        auto verifyAndSave() -> bool;
        void setSaveButtonVisible(bool visible);
        std::shared_ptr<packet_data::APN::Config> apn;
        std::shared_ptr<NewApnModel> newApnModel;
        ApnSettingsModel *apnSettingsModel = nullptr;
        gui::ListView *list                = nullptr;
    };

} /* namespace gui */

M module-apps/application-settings-new/windows/NightshiftWindow.cpp => module-apps/application-settings-new/windows/NightshiftWindow.cpp +0 -3
@@ 16,9 16,6 @@ namespace gui
    {
        AppWindow::buildInterface();

        topBar->setActive(TopBar::Elements::SIM, false);
        topBar->setActive(TopBar::Elements::TIME, true);

        setTitle(utils::localize.get("app_settings_title_nightshift"));

        body = new gui::VBox(this,

M module-apps/application-settings-new/windows/PhoneNameWindow.cpp => module-apps/application-settings-new/windows/PhoneNameWindow.cpp +0 -2
@@ 22,8 22,6 @@ namespace gui
    void PhoneNameWindow::buildInterface()
    {
        AppWindow::buildInterface();
        topBar->setActive(TopBar::Elements::SIM, false);
        topBar->setActive(TopBar::Elements::TIME, true);

        setTitle(utils::localize.get("app_settings_bluetooth_phone_name"));


M module-apps/application-settings-new/windows/QuotesAddWindow.cpp => module-apps/application-settings-new/windows/QuotesAddWindow.cpp +165 -10
@@ 2,32 2,187 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "QuotesAddWindow.hpp"
#include "QuotesMainWindow.hpp"

#include "application-settings-new/ApplicationSettings.hpp"
#include "application-settings-new/data/QuoteSwitchData.hpp"
#include "application-settings-new/models/QuotesRepository.hpp"

#include <i18n/i18n.hpp>
#include <widgets/Text.hpp>

namespace style
{
    constexpr auto counterWidth = 70;
    constexpr auto headerWidth  = style::window::default_body_width - counterWidth;
} // namespace style

namespace gui
{
    QuotesAddWindow::QuotesAddWindow(app::Application *app) : AppWindow(app, gui::window::name::quotes)
    namespace
    {
        constexpr auto maxQuoteCharactersCount  = 150U;
        constexpr auto maxQuoteLinesCount       = 4;
        constexpr auto maxAuthorCharactersCount = 30U;

        auto formatCounterText(uint32_t counter, uint32_t maxValue) -> std::string
        {
            std::ostringstream counterText;
            counterText << counter << '/' << maxValue;
            return counterText.str();
        }
    } // namespace

    QuoteAddEditWindow::QuoteAddEditWindow(app::Application *app, std::shared_ptr<app::QuotesModel> model)
        : AppWindow(app, gui::window::name::quotes), quoteModel(std::move(model))
    {
        setTitle(utils::localize.get("app_settings_display_locked_screen_new_quote"));
        buildInterface();
    }

    void QuotesAddWindow::buildInterface()
    void QuoteAddEditWindow::buildInterface()
    {
        AppWindow::buildInterface();

        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::save));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        auto text = new gui::Text(nullptr,
                                  style::window::default_left_margin,
                                  title->offset_h() + style::margins::big,
                                  style::window::default_body_width,
                                  style::window::default_body_height);
        auto vBox = new VBox(this,
                             style::window::default_left_margin,
                             style::header::height + style::margins::very_big,
                             style::window::default_body_width,
                             style::window::default_body_height);

        vBox->setEdges(RectangleEdge::None);
        vBox->setPenFocusWidth(::style::window::default_border_focus_w);
        vBox->setPenWidth(::style::window::default_border_rect_no_focus);

        auto quoteHeader = new HBox(vBox, 0, 0, 0, 0);
        quoteHeader->setMinimumSize(style::window::default_body_width, style::window::label::default_h);
        quoteHeader->activeItem = false;
        quoteHeader->setEdges(gui::RectangleEdge::None);

        auto quoteLabel = new Label(quoteHeader, 0, 0, 0, 0);
        quoteLabel->setMinimumSize(style::headerWidth, style::window::label::default_h);
        quoteLabel->setEdges(RectangleEdge::None);
        quoteLabel->setPenFocusWidth(::style::window::default_border_focus_w);
        quoteLabel->setText(utils::localize.get("app_settings_display_wallpaper_quotes_quote"));
        quoteLabel->setFont(::style::window::font::verysmall);
        quoteLabel->setAlignment(gui::Alignment{gui::Alignment::Horizontal::Left});
        quoteLabel->activeItem = false;

        quoteCharCounter = new gui::Label(quoteHeader, 0, 0, 0, 0);
        quoteCharCounter->setMinimumSize(style::counterWidth, style::window::label::default_h);
        quoteCharCounter->setEdges(gui::RectangleEdge::None);
        quoteCharCounter->setFont(::style::window::font::verysmall);
        quoteCharCounter->setAlignment(gui::Alignment{gui::Alignment::Horizontal::Right});

        quoteText = new gui::Text(vBox, 0, 0, 0, 0);
        quoteText->setAlignment(gui::Alignment{gui::Alignment::Vertical::Top});
        quoteText->setMinimumSize(style::window::default_body_width,
                                  style::window::label::default_h * maxQuoteLinesCount);
        quoteText->setPenFocusWidth(::style::window::default_border_focus_w);
        quoteText->setPenWidth(::style::window::default_border_rect_no_focus);
        quoteText->setEdges(gui::RectangleEdge::None);
        quoteText->setFont(::style::window::font::medium);
        quoteText->setInputMode(new InputMode(
            {InputMode::ABC, InputMode::abc, InputMode::digit},
            [=](const UTF8 &text) { bottomBarTemporaryMode(text); },
            [=]() { bottomBarRestoreFromTemporaryMode(); },
            [=]() { selectSpecialCharacter(); }));
        quoteText->setTextLimitType(gui::TextLimitType::MaxSignsCount, maxQuoteCharactersCount);
        quoteText->setTextChangedCallback([this](Item &, const UTF8 &text) { setQuoteCharactersCount(text.length()); });

        auto authorHeader = new HBox(vBox, 0, 0, 0, 0);
        authorHeader->setMinimumSize(style::window::default_body_width, style::window::label::default_h);
        authorHeader->setEdges(gui::RectangleEdge::None);
        authorHeader->activeItem = false;

        auto authorLabel = new Label(authorHeader, 0, 0, 0, 0);
        authorLabel->setMinimumSize(style::headerWidth, style::window::label::default_h);
        authorLabel->setEdges(RectangleEdge::None);
        authorLabel->setAlignment(gui::Alignment{gui::Alignment::Horizontal::Left});
        authorLabel->setText(utils::localize.get("app_settings_display_wallpaper_quotes_author"));
        authorLabel->setPenFocusWidth(::style::window::default_border_focus_w);
        authorLabel->setFont(::style::window::font::verysmall);
        authorLabel->setPadding(gui::Padding(0, 0, 0, 0));
        authorLabel->activeItem = false;

        authorCharCounter = new gui::Label(authorHeader, 0, 0, 0, 0);
        authorCharCounter->setMinimumSize(style::counterWidth, style::window::label::default_h);
        authorCharCounter->setEdges(gui::RectangleEdge::None);
        authorCharCounter->setFont(::style::window::font::verysmall);
        authorCharCounter->setAlignment(gui::Alignment{gui::Alignment::Horizontal::Right});

        authorText = new gui::Text(vBox, 0, 0, 0, 0);
        authorText->setMinimumSize(style::window::default_body_width, style::window::label::default_h);
        authorText->setAlignment(gui::Alignment{gui::Alignment::Vertical::Top});
        authorText->setPenFocusWidth(::style::window::default_border_focus_w);
        authorText->setPenWidth(::style::window::default_border_rect_no_focus);
        authorText->setEdges(gui::RectangleEdge::None);
        authorText->setFont(::style::window::font::medium);
        authorText->setInputMode(new InputMode(
            {InputMode::ABC, InputMode::abc, InputMode::digit},
            [=](const UTF8 &text) { bottomBarTemporaryMode(text); },
            [=]() { bottomBarRestoreFromTemporaryMode(); },
            [=]() { selectSpecialCharacter(); }));
        authorText->setTextLimitType(gui::TextLimitType::MaxSignsCount, maxAuthorCharactersCount);
        authorText->setTextChangedCallback(
            [this](Item &, const UTF8 &text) { setAuthorCharactersCount(text.length()); });

        setTitle(utils::localize.get("app_settings_display_wallpaper_quotes_new"));
        vBox->resizeItems();
        setFocusItem(quoteText);
    }

        addWidget(text);
        setFocusItem(text);
    void QuoteAddEditWindow::onBeforeShow(ShowMode mode, SwitchData *data)
    {
        auto *quotedata = dynamic_cast<QuoteSwitchData *>(data);
        if (quotedata == nullptr) {
            return;
        }

        quoteAction = quotedata->getAction();
        quoteData   = quotedata->getQuote();

        if (quoteAction == QuoteAction::Edit) {
            setTitle(utils::localize.get("app_settings_display_wallpaper_quotes_edit"));
            quoteText->setText(quoteData.quote);
            authorText->setText(quoteData.author);
        }
        else {
            setTitle(utils::localize.get("app_settings_display_wallpaper_quotes_new"));
        }

        setAuthorCharactersCount(authorText->getText().length());
        setQuoteCharactersCount(quoteText->getText().length());
    }

    bool QuoteAddEditWindow::onInput(const gui::InputEvent &inputEvent)
    {
        if (inputEvent.isShortPress() && inputEvent.is(gui::KeyCode::KEY_ENTER)) {
            LOG_DEBUG("Save Quote: %s", quoteText->getText().c_str());
            quoteData.quote  = quoteText->getText();
            quoteData.author = authorText->getText();
            quoteModel->save(quoteData);

            auto backToOptionWindow = 1;
            auto backToMainWindow   = 2;

            auto windowToBack = quoteAction == QuoteAction::Add ? backToOptionWindow : backToMainWindow;
            application->returnToPreviousWindow(windowToBack);
        }

        return AppWindow::onInput(inputEvent);
    }

    void QuoteAddEditWindow::setAuthorCharactersCount(std::uint32_t count)
    {
        authorCharCounter->setText(formatCounterText(count, maxAuthorCharactersCount));
    }

    void QuoteAddEditWindow::setQuoteCharactersCount(std::uint32_t count)
    {
        quoteCharCounter->setText(formatCounterText(count, maxQuoteCharactersCount));
    }

} // namespace gui

M module-apps/application-settings-new/windows/QuotesAddWindow.hpp => module-apps/application-settings-new/windows/QuotesAddWindow.hpp +17 -3
@@ 4,18 4,32 @@
#pragma once

#include "BaseSettingsWindow.hpp"
#include "QuotesMainWindow.hpp"
#include "application-settings-new/models/QuotesModel.hpp"

namespace gui
{
    class CheckBoxWithLabel;

    class QuotesAddWindow : public AppWindow
    class QuoteAddEditWindow : public AppWindow
    {
      public:
        QuotesAddWindow(app::Application *app);
        QuoteAddEditWindow(app::Application *app, std::shared_ptr<app::QuotesModel> model);
        void buildInterface() override;

      private:
        std::vector<CheckBoxWithLabel *> boxes;
        auto onInput(const InputEvent &inputEvent) -> bool override;
        void onBeforeShow(ShowMode mode, SwitchData *data) override;
        void setAuthorCharactersCount(uint32_t count);
        void setQuoteCharactersCount(uint32_t count);

        gui::Text *quoteText          = nullptr;
        gui::Text *authorText         = nullptr;
        gui::Label *authorCharCounter = nullptr;
        gui::Label *quoteCharCounter  = nullptr;

        QuoteAction quoteAction;
        app::QuoteRecord quoteData;
        std::shared_ptr<app::QuotesModel> quoteModel;
    };
} // namespace gui

M module-apps/application-settings-new/windows/QuotesMainWindow.cpp => module-apps/application-settings-new/windows/QuotesMainWindow.cpp +52 -74
@@ 2,7 2,8 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "QuotesMainWindow.hpp"

#include "application-settings-new/models/QuotesRepository.hpp"
#include "application-settings-new/models/QuotesModel.hpp"
#include "application-settings-new/ApplicationSettings.hpp"
#include "application-settings-new/widgets/SettingsStyle.hpp"
#include "OptionSetting.hpp"


@@ 10,17 11,54 @@
#include <InputEvent.hpp>
#include <i18n/i18n.hpp>
#include <json/json11.hpp>
#include <purefs/filesystem_paths.hpp>
#include <Utils.hpp>
#include <string>
#include <utility>

namespace style::quotes
{
    namespace list
    {
        constexpr auto X      = style::window::default_left_margin;
        constexpr auto Y      = style::header::height;
        constexpr auto Width  = style::listview::body_width_with_scroll;
        constexpr auto Height = style::window_height - Y - style::footer::height;
    } // namespace list

    inline constexpr auto cross_x = 48;
    inline constexpr auto cross_y = 55;
    inline constexpr auto arrow_x = 30;
    inline constexpr auto arrow_y = 62;

} // namespace style::quotes

namespace gui
{
    QuotesMainWindow::QuotesMainWindow(app::Application *app) : BaseSettingsWindow(app, gui::window::name::quotes)
    QuotesMainWindow::QuotesMainWindow(app::Application *app, std::shared_ptr<app::QuotesModel> model)
        : AppWindow(app, gui::window::name::quotes), quotesModel(std::move(model))
    {
        const auto quotesPath = purefs::dir::getCurrentOSPath() / "data/applications/settings/quotes.json";
        setTitle(utils::localize.get("app_settings_display_locked_screen_quotes"));
        readQuotes(quotesPath);
        buildInterface();
    }

    void QuotesMainWindow::buildInterface()
    {
        AppWindow::buildInterface();

        setTitle(utils::localize.get("app_settings_display_wallpaper_quotes"));

        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::check));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
        bottomBar->setText(BottomBar::Side::LEFT, utils::localize.get(style::strings::common::options));

        new gui::Image(this, style::quotes::arrow_x, style::quotes::arrow_y, 0, 0, "arrow_left");
        new gui::Image(this, style::quotes::cross_x, style::quotes::cross_y, 0, 0, "cross");

        list = new gui::ListView(this,
                                 style::quotes::list::X,
                                 style::quotes::list::Y,
                                 style::quotes::list::Width,
                                 style::quotes::list::Height,
                                 quotesModel);

        setFocusItem(list);
    }

    auto QuotesMainWindow::onInput(const InputEvent &inputEvent) -> bool


@@ 29,10 67,12 @@ namespace gui
        if (AppWindow::onInput(inputEvent)) {
            return true;
        }
        if (inputEvent.state == InputEvent::State::keyReleasedShort) {

        if (inputEvent.isShortPress()) {
            switch (inputEvent.keyCode) {
            case gui::KeyCode::KEY_LEFT:
                application->switchWindow(gui::window::name::new_quote, nullptr);
                application->switchWindow(gui::window::name::new_quote,
                                          std::make_unique<QuoteSwitchData>(QuoteAction::Add));
                return true;
            default:
                break;


@@ 41,70 81,8 @@ namespace gui
        return false;
    }

    void QuotesMainWindow::readQuotes(fs::path fn)
    {
        std::string err;

        const auto fileContents = readFileToString(fn);
        auto obj                = json11::Json::parse(fileContents.c_str(), err).array_items();

        if (!err.empty()) {
            LOG_ERROR("Error while parsing quotes: %s", err.c_str());
        }

        std::transform(obj.begin(), obj.end(), std::back_inserter(quotes), [](auto item) {
            return std::pair{item["quote"].string_value(), false};
        });
    }

    auto QuotesMainWindow::buildOptionsList() -> std::list<gui::Option>
    void QuotesMainWindow::onBeforeShow(ShowMode mode, SwitchData *data)
    {
        std::list<gui::Option> optionsList;

        for (auto &quote : quotes) {
            optionsList.emplace_back(std::make_unique<gui::option::OptionSettings>(
                utils::translateI18(quote.first),
                [&quote, this](gui::Item &item) {
                    switchHandler(quote.second);
                    return true;
                },
                [=](gui::Item &item) {
                    if (item.focus) {
                        this->setBottomBarText(utils::translateI18(style::strings::common::Switch),
                                               BottomBar::Side::CENTER);
                    }
                    return true;
                },
                this,
                quote.second ? gui::option::SettingRightItem::Checked : gui::option::SettingRightItem::Disabled));
        }

        return optionsList;
        quotesModel->rebuild();
    }

    void QuotesMainWindow::switchHandler(bool &optionSwitch)
    {
        optionSwitch = !optionSwitch;
        rebuildOptionList();
    }

    std::string QuotesMainWindow::readFileToString(const fs::path &fn)
    {
        constexpr auto tar_buf = 8192 * 4;
        auto file              = std::fopen(fn.c_str(), "r");
        if (!file) {
            return {};
        }
        const auto length = utils::filesystem::filelength(file);
        if (length >= tar_buf) {
            LOG_ERROR("File %s length is too high!", fn.c_str());
            std::fclose(file);
            return {};
        }
        auto buffer = std::make_unique<char[]>(length + 1);
        std::fread(buffer.get(), 1, length, file);
        std::fclose(file);
        return std::string(buffer.get());
    }

} // namespace gui

M module-apps/application-settings-new/windows/QuotesMainWindow.hpp => module-apps/application-settings-new/windows/QuotesMainWindow.hpp +14 -13
@@ 4,27 4,28 @@
#pragma once

#include "BaseSettingsWindow.hpp"
#include "application-settings-new/widgets/QuoteWidget.hpp"
#include "application-settings-new/models/QuotesModel.hpp"

#include <purefs/filesystem_paths.hpp>
#include <module-gui/gui/widgets/ListView.hpp>
#include <module-apps/InternalModel.hpp>
#include <utility>

namespace gui
{
    class CheckBoxWithLabel;

    class QuotesMainWindow : public BaseSettingsWindow
    class QuotesMainWindow : public AppWindow
    {
      public:
        QuotesMainWindow(app::Application *app);

        auto onInput(const InputEvent &inputEvent) -> bool override;

      protected:
        auto buildOptionsList() -> std::list<Option> override;
        QuotesMainWindow(app::Application *app, std::shared_ptr<app::QuotesModel> model);

      private:
        void readQuotes(fs::path fn);
        void switchHandler(bool &optionSwitch);
        [[nodiscard]] static std::string readFileToString(const fs::path &fn);
        void buildInterface() override;
        auto onInput(const InputEvent &inputEvent) -> bool override;
        void onBeforeShow(ShowMode mode, SwitchData *data) override;

        std::list<std::pair<std::string, bool>> quotes;
        std::shared_ptr<app::QuotesModel> quotesModel = nullptr;
        gui::ListView *list                           = nullptr;
    };

} // namespace gui

A module-apps/application-settings-new/windows/QuotesOptionsWindow.cpp => module-apps/application-settings-new/windows/QuotesOptionsWindow.cpp +85 -0
@@ 0,0 1,85 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "QuotesOptionsWindow.hpp"
#include "OptionSetting.hpp"
#include "application-settings-new/models/QuotesRepository.hpp"
#include "application-settings-new/ApplicationSettings.hpp"
#include "DialogMetadataMessage.hpp"
#include "QuotesMainWindow.hpp"
#include "application-settings-new/models/QuotesRepository.hpp"
#include "application-settings-new/ApplicationSettings.hpp"
#include "application-settings-new/widgets/QuoteWidget.hpp"

#include <i18n/i18n.hpp>
#include <widgets/Text.hpp>

namespace gui
{

    QuotesOptionsWindow::QuotesOptionsWindow(app::Application *app, std::shared_ptr<app::QuotesModel> model)
        : BaseSettingsWindow(app, gui::window::name::quotes), quotesModel(std::move(model))
    {
        setTitle(utils::localize.get("app_settings_display_wallpaper_quotes_options"));
    }

    auto QuotesOptionsWindow::buildOptionsList() -> std::list<gui::Option>
    {
        std::list<gui::Option> optionsList;

        optionsList.emplace_back(std::make_unique<gui::option::OptionSettings>(
            utils::translateI18("app_settings_display_wallpaper_quotes_edit"),
            [=](gui::Item &item) {
                application->switchWindow(gui::window::name::new_quote,
                                          std::make_unique<QuoteSwitchData>(QuoteAction::Edit, quote));
                return true;
            },
            [=](gui::Item &item) {
                if (item.focus) {
                    this->setBottomBarText(utils::translateI18(style::strings::common::select),
                                           BottomBar::Side::CENTER);
                }
                return true;
            },
            this));

        optionsList.emplace_back(std::make_unique<gui::option::OptionSettings>(
            utils::translateI18("app_settings_display_wallpaper_quotes_delete"),
            [=](gui::Item &item) {
                gui::DialogMetadata meta;
                meta.text   = utils::localize.get("app_settings_display_wallpaper_quotes_delete_confirmation");
                meta.title  = quote.quote;
                meta.icon   = "phonebook_contact_delete_trashcan";
                meta.action = [this]() {
                    auto backToQuotesMainWindow = 2;
                    quotesModel->remove(quote);
                    application->returnToPreviousWindow(backToQuotesMainWindow);
                    return true;
                };

                application->switchWindow(gui::window::name::quotes_dialog_yes_no,
                                          std::make_unique<gui::DialogMetadataMessage>(meta));
                return true;
            },
            [=](gui::Item &item) {
                if (item.focus) {
                    this->setBottomBarText(utils::translateI18(style::strings::common::select),
                                           BottomBar::Side::CENTER);
                }
                return true;
            },
            this));

        return optionsList;
    } // namespace gui

    void QuotesOptionsWindow::onBeforeShow(ShowMode mode, SwitchData *data)
    {
        auto *quoteSwitchData = dynamic_cast<QuoteSwitchData *>(data);
        if (quoteSwitchData != nullptr) {
            quote = quoteSwitchData->getQuote();
        }

        BaseSettingsWindow::onBeforeShow(mode, data);
    }
} // namespace gui

A module-apps/application-settings-new/windows/QuotesOptionsWindow.hpp => module-apps/application-settings-new/windows/QuotesOptionsWindow.hpp +24 -0
@@ 0,0 1,24 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "BaseSettingsWindow.hpp"
#include "QuotesMainWindow.hpp"
#include "application-settings-new/widgets/QuoteWidget.hpp"

namespace gui
{
    class QuotesOptionsWindow : public BaseSettingsWindow
    {
      public:
        QuotesOptionsWindow(app::Application *app, std::shared_ptr<app::QuotesModel> model);

      private:
        std::list<Option> buildOptionsList() override;
        void onBeforeShow(ShowMode mode, SwitchData *data) override;

        std::shared_ptr<app::QuotesModel> quotesModel;
        app::QuoteRecord quote;
    };
} // namespace gui

A module-apps/application-settings-new/windows/SystemMainWindow.cpp => module-apps/application-settings-new/windows/SystemMainWindow.cpp +37 -0
@@ 0,0 1,37 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "application-settings-new/ApplicationSettings.hpp"
#include "OptionSetting.hpp"
#include "SystemMainWindow.hpp"

namespace gui
{
    SystemMainWindow::SystemMainWindow(app::Application *app) : BaseSettingsWindow(app, window::name::system)
    {}

    auto SystemMainWindow::buildOptionsList() -> std::list<Option>
    {
        std::list<Option> optionList;
        auto addOption = [&](UTF8 name, const std::string &window) {
            optionList.emplace_back(std::make_unique<option::OptionSettings>(
                utils::translateI18(name),
                [=](Item &item) {
                    LOG_INFO("switching to %s page", window.c_str());
                    application->switchWindow(window, nullptr);
                    return true;
                },
                nullptr,
                nullptr,
                option::SettingRightItem::ArrowWhite));
        };

        addOption("app_settings_language", gui::window::name::language);
        addOption("app_settings_date_and_time", gui::window::name::date_and_time);
        addOption("app_settings_factory_reset", gui::window::name::factory_reset);
        addOption("app_settings_about_your_pure", gui::window::name::about_your_pure);
        addOption("app_settings_certification", gui::window::name::certification);

        return optionList;
    }
} // namespace gui

A module-apps/application-settings-new/windows/SystemMainWindow.hpp => module-apps/application-settings-new/windows/SystemMainWindow.hpp +18 -0
@@ 0,0 1,18 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "BaseSettingsWindow.hpp"

namespace gui
{
    class SystemMainWindow : public BaseSettingsWindow
    {
      public:
        explicit SystemMainWindow(app::Application *app);

      private:
        auto buildOptionsList() -> std::list<Option> override;
    };
} // namespace gui

M module-apps/application-settings/ApplicationSettings.cpp => module-apps/application-settings/ApplicationSettings.cpp +12 -8
@@ 47,16 47,10 @@ namespace app
            switchWindow(app::sim_select);
            return msgHandled();
        });
        settings->registerValueChange(settings::SystemProperties::lockPassHash,
                                      [this](std::string value) { lockPassChanged(value); });
        settings->registerValueChange(settings::SystemProperties::timeDateFormat,
                                      [this](std::string value) { timeDateChanged(value); });
    }

    ApplicationSettings::~ApplicationSettings()
    {
        settings->unregisterValueChange(settings::SystemProperties::lockPassHash);
        settings->unregisterValueChange(settings::SystemProperties::timeDateFormat);
    }

    // Invoked upon receiving data message


@@ 104,6 98,15 @@ namespace app
        if (ret != sys::ReturnCodes::Success)
            return ret;

        settings->registerValueChange(
            settings::SystemProperties::lockPassHash,
            [this](std::string value) { lockPassChanged(value); },
            settings::SettingsScope::Global);
        settings->registerValueChange(
            settings::SystemProperties::timeDateFormat,
            [this](std::string value) { timeDateChanged(value); },
            settings::SettingsScope::Global);

        createUserInterface();

        setActiveWindow(gui::name::window::main_window);


@@ 173,13 176,14 @@ namespace app

    void ApplicationSettings::setPin(unsigned int value)
    {
        settings->setValue(settings::SystemProperties::lockPassHash, std::to_string(value));
        settings->setValue(
            settings::SystemProperties::lockPassHash, std::to_string(value), settings::SettingsScope::Global);
        lockPassHash = value;
    }

    void ApplicationSettings::clearPin()
    {
        settings->setValue(settings::SystemProperties::lockPassHash, "");
        settings->setValue(settings::SystemProperties::lockPassHash, "", settings::SettingsScope::Global);
        lockPassHash = 0U;
    }


M module-apps/application-settings/windows/BtScanWindow.cpp => module-apps/application-settings/windows/BtScanWindow.cpp +0 -2
@@ 57,8 57,6 @@ namespace gui
        bottomBar->setActive(BottomBar::Side::RIGHT, true);
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::select));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        setTitle(utils::localize.get("BT_scan_results"));


M module-apps/application-settings/windows/BtWindow.cpp => module-apps/application-settings/windows/BtWindow.cpp +0 -2
@@ 59,8 59,6 @@ namespace gui
        bottomBar->setActive(BottomBar::Side::RIGHT, true);
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::select));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        setTitle(utils::localize.get("app_settings_bt"));


M module-apps/application-settings/windows/CellularPassthroughWindow.cpp => module-apps/application-settings/windows/CellularPassthroughWindow.cpp +0 -2
@@ 31,8 31,6 @@ namespace gui
        bottomBar->setActive(BottomBar::Side::RIGHT, true);
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::select));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        setTitle(utils::localize.get("app_settings_cellular_passthrough"));


M module-apps/application-settings/windows/CellularPassthroughWindow.hpp => module-apps/application-settings/windows/CellularPassthroughWindow.hpp +1 -3
@@ 30,8 30,6 @@ namespace gui
        } // namespace cellular_passthrough
    }     // namespace window

    using namespace bsp::cellular::USB;

    class CellularPassthroughWindow : public AppWindow
    {
      private:


@@ 76,7 74,7 @@ namespace gui

        CellularPassthroughWindow::State getInitialState();

        bool set(PassthroughState pass_to_set, BootPinState dfu_to_set);
        bool set(bsp::cellular::USB::PassthroughState pass_to_set, bsp::cellular::USB::BootPinState dfu_to_set);

        void setWindowState(State state);


M module-apps/application-settings/windows/DateTimeWindow.cpp => module-apps/application-settings/windows/DateTimeWindow.cpp +0 -3
@@ 52,9 52,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::select));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        setTitle(utils::localize.get("app_settings_date_and_time"));

        // create date widgets

M module-apps/application-settings/windows/EinkModeWindow.cpp => module-apps/application-settings/windows/EinkModeWindow.cpp +0 -2
@@ 27,8 27,6 @@ namespace gui
        bottomBar->setActive(BottomBar::Side::RIGHT, true);
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::select));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        setTitle("Change eink mode");
        auto label               = new Label(this, 100, 200, 300, 50, "Change mode on click");

M module-apps/application-settings/windows/FotaWindow.cpp => module-apps/application-settings/windows/FotaWindow.cpp +0 -3
@@ 37,9 37,6 @@ namespace gui
        AppWindow::buildInterface();
        setTitle("Modem Firmware update (FOTA)");

        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        bottomBar->setActive(BottomBar::Side::CENTER, true);
        bottomBar->setActive(BottomBar::Side::RIGHT, true);
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get("Go"));

M module-apps/application-settings/windows/Info.cpp => module-apps/application-settings/windows/Info.cpp +0 -2
@@ 36,8 36,6 @@ namespace gui
        AppWindow::buildInterface();
        bottomBar->setActive(BottomBar::Side::RIGHT, true);
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        setTitle("Info");


M module-apps/application-settings/windows/LanguageWindow.cpp => module-apps/application-settings/windows/LanguageWindow.cpp +0 -3
@@ 49,9 49,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::select));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        setTitle(utils::localize.get("app_settings_title_languages"));
        const auto &langList = loader.getAvailableDisplayLanguages();
        for (const auto &lang : langList) {

M module-apps/application-settings/windows/SimSelectWindow.hpp => module-apps/application-settings/windows/SimSelectWindow.hpp +1 -1
@@ 10,4 10,4 @@ namespace app
    class SimSetter;
} // namespace app

std::list<gui::Option> simSelectWindow(app::Application *app, app::SimSetter *setter);
std::list<gui::Option> simSelectWindow(app::Application *app, app::SimSetter *setter);
\ No newline at end of file

M module-apps/application-settings/windows/TestMessageWindow.cpp => module-apps/application-settings/windows/TestMessageWindow.cpp +0 -3
@@ 61,9 61,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::select));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);

        receivedLabel = new gui::Label(this, 10, 50, 480 - 20, 50, "Received SMS");
        receivedLabel->setAlignment(
            gui::Alignment(gui::Alignment::Vertical::Center, gui::Alignment::Horizontal::Center));

M module-apps/application-special-input/windows/SpecialInputMainWindow.cpp => module-apps/application-special-input/windows/SpecialInputMainWindow.cpp +0 -2
@@ 36,8 36,6 @@ void SpecialInputMainWindow::buildInterface()
    bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
    bottomBar->setText(BottomBar::Side::LEFT, utils::localize.get(style::strings::common::emoji));

    topBar->setActive(TopBar::Elements::TIME, true);

    charList = new gui::ListView(this,
                                 specialInputStyle::specialInputListView::x,
                                 specialInputStyle::specialInputListView::y,

M module-apps/options/type/OptionSetting.hpp => module-apps/options/type/OptionSetting.hpp +1 -1
@@ 10,7 10,7 @@ namespace gui::option
{
    class OptionSettings : public option::Base
    {
      private:
      protected:
        UTF8 text;
        std::function<bool(Item &)> activatedCallback    = nullptr;
        std::function<bool(Item &)> focusChangedCallback = nullptr;

M module-apps/widgets/BarGraph.cpp => module-apps/widgets/BarGraph.cpp +59 -100
@@ 18,104 18,111 @@ namespace gui
        setValue(absoluteValue);
    }

    Rect *BarGraph::createRectangle(uint32_t width, uint32_t height)
    auto BarGraph::createRectangle(uint32_t width, uint32_t height) const -> Rect *
    {
        auto rectangle = new Rect(nullptr, 0, 0, width, height);
        rectangle->setFillColor(ColorFullBlack);
        rectangle->setBorderColor(ColorFullBlack);
        rectangle->setFilled(true);
        rectangle->setFilled(false);
        rectangle->setRadius(style::bargraph::radius);
        rectangle->setPenWidth(style::window::default_border_focus_w);
        return rectangle;
    }

    Rect *BarGraph::createSpace(uint32_t width, uint32_t height)
    auto BarGraph::createSpace(uint32_t width, uint32_t height) const -> Rect *
    {
        auto space = new Rect(nullptr, 0, 0, width, height);
        space->setEdges(RectangleEdge::None);
        return space;
    }

    VBarGraph::VBarGraph(Item *parent, Position x, Position y, uint32_t numberOfRectangles)
        : VBox(parent, x, y, style::bargraph::rect_axis_length_lrg, rectAxisLenghtFrom(numberOfRectangles))
    auto BarGraph::incrementWith(uint32_t levels) -> bool
    {
        setRadius(style::bargraph::radius);
        setEdges(RectangleEdge::None);
        setMaximum(numberOfRectangles);
        std::reverse(std::begin(rectangles), std::end(rectangles));
        if ((currentLevel + levels) <= numberOfRectangles) {
            for (uint32_t i = 0; i < levels; ++i) {
                rectangles[currentLevel]->setFillColor(ColorFullBlack);
                rectangles[currentLevel]->setBorderColor(ColorFullBlack);
                ++currentLevel;
            }
            return true;
        }
        else {
            LOG_ERROR("bargraph incremented out of size");
            return false;
        }
    }

    void VBarGraph::setMaximum(unsigned int value)
    auto BarGraph::decrementWith(uint32_t levels) -> bool
    {
        numberOfRectangles = value;
        setSize(rectAxisLenghtFrom(numberOfRectangles), Axis::Y);
        if (currentLevel > numberOfRectangles) {
            currentLevel = numberOfRectangles;
        }
        if (!rectangles.empty()) {
            erase();
            rectangles.clear();
        if (currentLevel >= levels) {
            for (uint32_t i = levels; i > 0; --i) {
                --currentLevel;
                rectangles[currentLevel]->setFillColor(ColorFullWhite);
                rectangles[currentLevel]->setBorderColor(ColorFullBlack);
            }
            return true;
        }
        for (uint32_t i = 0; i < numberOfRectangles; ++i) {
            auto rectangle =
                createRectangle(style::bargraph::rect_axis_length_lrg, style::bargraph::rect_axis_length_sml);
            addWidget(rectangle);
            rectangles.push_back(rectangle);
            addWidget(createSpace(style::bargraph::rect_axis_length_lrg, style::bargraph::spacing));
        else {
            LOG_ERROR("bargraph incremented out of size");
            return false;
        }
    }

    void VBarGraph::update(int value)
    auto BarGraph::update(int value) -> bool
    {
        if (value > 0) {
            incrementWith(value);
            return incrementWith(value);
        }
        else if (value < 0) {
            decrementWith((-value));
            return decrementWith((-value));
        }

        return false;
    }

    void VBarGraph::setValue(unsigned int value)
    bool BarGraph::setValue(unsigned int value)
    {
        if (const auto levels = static_cast<int>(value) - static_cast<int>(currentLevel); levels > 0) {
            incrementWith(levels);
            return incrementWith(levels);
        }
        else if (levels < 0) {
            decrementWith(-levels);
            return decrementWith(-levels);
        }
        return false;
    }

    void VBarGraph::incrementWith(uint32_t levels)
    VBarGraph::VBarGraph(Item *parent, Position x, Position y, uint32_t numberOfRectangles)
        : VBox(parent, x, y, style::bargraph::rect_axis_length_lrg, rectAxisLenghtFrom(numberOfRectangles))
    {
        if ((currentLevel + levels) <= numberOfRectangles) {
            for (uint32_t i = 0; i < levels; ++i) {
                rectangles[currentLevel]->setFillColor(ColorFullBlack);
                rectangles[currentLevel]->setBorderColor(ColorFullBlack);
                ++currentLevel;
            }
        }
        else {
            LOG_ERROR("bargraph incremented out of size");
        }
        setRadius(style::bargraph::radius);
        setEdges(RectangleEdge::None);
        setMaximum(numberOfRectangles);
        std::reverse(std::begin(rectangles), std::end(rectangles));
    }

    void VBarGraph::decrementWith(uint32_t levels)
    void VBarGraph::setMaximum(unsigned int value)
    {
        if (currentLevel >= levels) {
            for (uint32_t i = levels; i > 0; --i) {
                --currentLevel;
                rectangles[currentLevel]->setFillColor(ColorTray);
                rectangles[currentLevel]->setBorderColor(ColorTray);
            }
        numberOfRectangles = value;
        setSize(rectAxisLenghtFrom(numberOfRectangles), Axis::Y);
        if (currentLevel > numberOfRectangles) {
            currentLevel = numberOfRectangles;
        }
        else {
            LOG_ERROR("bargraph incremented out of size");
        if (!rectangles.empty()) {
            erase();
            rectangles.clear();
        }
        for (uint32_t i = 0; i < numberOfRectangles; ++i) {
            auto rectangle =
                createRectangle(style::bargraph::rect_axis_length_lrg, style::bargraph::rect_axis_length_sml);
            addWidget(rectangle);
            rectangles.push_back(rectangle);
            addWidget(createSpace(style::bargraph::rect_axis_length_lrg, style::bargraph::spacing));
        }
    }

    HBarGraph::HBarGraph(Item *parent, Position x, Position y, uint32_t numberOfRectangles)
        : HBox(parent, x, y, rectAxisLenghtFrom(numberOfRectangles), style::bargraph::rect_axis_length_lrg)
    HBarGraph::HBarGraph(Item *parent, Position x, Position y, uint32_t numberOfRectangles) : HBox(parent)
    {
        setMinimumSize(rectAxisLenghtFrom(numberOfRectangles), style::bargraph::rect_axis_length_lrg);
        setRadius(style::bargraph::radius);
        setEdges(RectangleEdge::None);
        setMaximum(numberOfRectangles);


@@ 141,52 148,4 @@ namespace gui
        }
    }

    void HBarGraph::update(int value)
    {
        if (value > 0) {
            incrementWith(value);
        }
        else if (value < 0) {
            decrementWith(-value);
        }
    }

    void HBarGraph::setValue(unsigned int value)
    {
        if (const auto levels = static_cast<int>(value) - static_cast<int>(currentLevel); levels > 0) {
            incrementWith(levels);
        }
        else if (levels < 0) {
            decrementWith(levels * -1);
        }
    }

    void HBarGraph::incrementWith(uint32_t levels)
    {
        if ((currentLevel + levels) <= numberOfRectangles) {
            for (uint32_t i = 0; i < levels; ++i) {
                rectangles[currentLevel]->setFillColor(ColorFullBlack);
                rectangles[currentLevel]->setBorderColor(ColorFullBlack);
                ++currentLevel;
            }
        }
        else {
            LOG_ERROR("bargraph incremented out of size");
        }
    }

    void HBarGraph::decrementWith(uint32_t levels)
    {
        if (currentLevel >= levels) {
            for (uint32_t i = levels; i > 0; --i) {
                --currentLevel;
                rectangles[currentLevel]->setFillColor(ColorFullWhite);
                rectangles[currentLevel]->setBorderColor(ColorFullBlack);
            }
        }
        else {
            LOG_ERROR("bargraph incremented out of size");
        }
    }

} /* namespace gui */

M module-apps/widgets/BarGraph.hpp => module-apps/widgets/BarGraph.hpp +13 -13
@@ 23,36 23,36 @@ namespace gui
        uint32_t numberOfRectangles;
        uint32_t currentLevel = 0;

      public:
        Rect *createRectangle(uint32_t width, uint32_t height);
        [[nodiscard]] auto createRectangle(uint32_t width, uint32_t height) const -> Rect *;
        [[nodiscard]] auto createSpace(uint32_t width, uint32_t height) const -> Rect *;

        Rect *createSpace(uint32_t width, uint32_t height);
        auto incrementWith(uint32_t levels) -> bool;
        auto decrementWith(uint32_t levels) -> bool;

      public:
        void setPercentageValue(unsigned int value) override;

        [[nodiscard]] auto getValue() const -> uint32_t
        {
            return currentLevel;
        }
        auto update(int value = 1) -> bool final;

        auto setValue(unsigned int value) -> bool override;
    };

    class VBarGraph : public VBox, public BarGraph
    {
        void incrementWith(uint32_t levels);
        void decrementWith(uint32_t levels);

      public:
        VBarGraph(Item *parent = nullptr, Position x = 0, Position y = 0, uint32_t numberOfRectangles = 0);
        void setMaximum(unsigned int value) final;
        void setValue(unsigned int value) final;
        void update(int value = 1) final;
    };

    class HBarGraph : public HBox, public BarGraph
    {
        void incrementWith(uint32_t levels);
        void decrementWith(uint32_t levels);

      public:
        HBarGraph(Item *parent = nullptr, Position x = 0, Position y = 0, uint32_t numberOfRectangles = 0);
        void setMaximum(unsigned int value) final;
        void setValue(unsigned int value) final;
        void update(int value = 1) final;
    };

} /* namespace gui */

M module-apps/windows/AppWindow.cpp => module-apps/windows/AppWindow.cpp +16 -4
@@ 49,10 49,22 @@ namespace gui
        title->setEllipsis(Ellipsis::Right);
        title->visible = false;

        topBar = new gui::TopBar(this, 0, 0, 480, 50);
        topBar->setActive(TopBar::Elements::LOCK, false);
        topBar->setActive(TopBar::Elements::BATTERY, false);
        topBar->setActive(TopBar::Elements::SIGNAL, false);
        auto config = configureTopBar(application->getTopBarConfiguration());
        topBar      = new gui::top_bar::TopBar(this, 0, 0, 480, 50);
        topBar->configure(std::move(config));
    }

    top_bar::Configuration AppWindow::configureTopBar(top_bar::Configuration appConfiguration)
    {
        return appConfiguration;
    }

    void AppWindow::applyToTopBar(TopBarConfigurationChangeFunction configChange)
    {
        if (configChange) {
            auto newConfiguration = configChange(topBar->getConfiguration());
            topBar->configure(std::move(newConfiguration));
        }
    }

    bool AppWindow::setSIM()

M module-apps/windows/AppWindow.hpp => module-apps/windows/AppWindow.hpp +21 -5
@@ 40,12 40,17 @@ namespace gui
        /**
         * Information bar for signal, battery and lock icon on the top of the screen.
         */
        gui::TopBar *topBar = nullptr;
        gui::top_bar::TopBar *topBar = nullptr;
        /**
         * Pointer to the application object that owns the window.
         */
        app::Application *application = nullptr;

        /**
         * A function that applies configuration changes to the current top bar configuration.
         */
        using TopBarConfigurationChangeFunction = std::function<top_bar::Configuration(top_bar::Configuration)>;

      public:
        AppWindow() = delete;
        AppWindow(app::Application *app, std::string name);


@@ 54,10 59,7 @@ namespace gui
        {
            return application;
        };
        void setApplication(app::Application *app)
        {
            application = app;
        };

        virtual bool onDatabaseMessage(sys::Message *msg);

        bool updateBatteryCharger(bool charging);


@@ 76,6 78,20 @@ namespace gui
        void destroyInterface() override;
        bool onInput(const InputEvent &inputEvent) override;
        void accept(GuiVisitor &visitor) override;

        /**
         * Configure the top bar using window-specific configuration.
         * @param appConfiguration      Application-wide top bar configuration that it to be modified.
         * @return window-specific configuration of the top bar.
         */
        virtual top_bar::Configuration configureTopBar(top_bar::Configuration appConfiguration);

        /**
         * Applies configuration change on the current top bar configuration.
         * @param configChange  The function that contains the top bar configuration changes.
         */
        void applyToTopBar(TopBarConfigurationChangeFunction configChange);

        /// Setting bottom bar temporary text
        /// @param text - bottomBar text
        /// @param overwriteOthers - set or not other bottomBar texts to "" (default true)

M module-apps/windows/Dialog.cpp => module-apps/windows/Dialog.cpp +0 -6
@@ 50,7 50,6 @@ Dialog::Dialog(app::Application *app, const std::string &name) : gui::AppWindow(
{
    AppWindow::buildInterface();

    topBar->setActive(TopBar::Elements::TIME, true);
    bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

    setTitle("");


@@ 77,9 76,6 @@ void Dialog::onBeforeShow(ShowMode mode, SwitchData *data)

DialogConfirm::DialogConfirm(app::Application *app, const std::string &name) : Dialog(app, name)
{
    topBar->setActive(TopBar::Elements::BATTERY, true);
    topBar->setActive(TopBar::Elements::SIGNAL, true);

    bottomBar->setActive(BottomBar::Side::RIGHT, false);
    bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::ok));
    setFocusItem(icon);


@@ 169,8 165,6 @@ void DialogYesNoIconTxt::onBeforeShow(ShowMode mode, SwitchData *data)
    if (auto metadata = dynamic_cast<DialogMetadataMessage *>(data); metadata != nullptr) {
        DialogYesNo::onBeforeShow(mode, metadata);
        iconText->setText(metadata->get().iconText);
        topBar->setActive(TopBar::Elements::BATTERY, false);
        topBar->setActive(TopBar::Elements::SIM, false);
        setFocusItem(no);
    }
}

M module-apps/windows/OptionWindow.cpp => module-apps/windows/OptionWindow.cpp +1 -2
@@ 63,8 63,6 @@ namespace gui
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::select));
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        topBar->setActive(TopBar::Elements::SIGNAL, true);
        topBar->setActive(TopBar::Elements::BATTERY, true);
        setTitle(name);

        optionsList = new gui::ListView(this,


@@ 97,4 95,5 @@ namespace gui
            resetOptions(message->takeOptions());
        }
    }

} /* namespace gui */

M module-apps/windows/OptionWindow.hpp => module-apps/windows/OptionWindow.hpp +0 -1
@@ 19,7 19,6 @@ namespace gui

    class OptionWindow : public AppWindow
    {

      protected:
        std::shared_ptr<OptionsModel> optionsModel = nullptr;
        ListView *optionsList                      = nullptr;

M module-audio/Audio/StreamQueuedEventsListener.cpp => module-audio/Audio/StreamQueuedEventsListener.cpp +2 -1
@@ 5,7 5,8 @@

using namespace audio;

StreamQueuedEventsListener::StreamQueuedEventsListener(std::shared_ptr<Queue> eventsQueue) : queue(eventsQueue)
StreamQueuedEventsListener::StreamQueuedEventsListener(std::shared_ptr<cpp_freertos::Queue> eventsQueue)
    : queue(eventsQueue)
{}

void StreamQueuedEventsListener::onEvent(Stream *stream, Stream::Event event, Stream::EventSourceMode source)

M module-audio/Audio/StreamQueuedEventsListener.hpp => module-audio/Audio/StreamQueuedEventsListener.hpp +2 -4
@@ 13,8 13,6 @@

namespace audio
{
    using namespace cpp_freertos;

    class StreamQueuedEventsListener : public Stream::EventListener
    {
      private:


@@ 29,7 27,7 @@ namespace audio
        using queuedEvent                         = std::pair<Stream *, Stream::Event>;
        static constexpr auto listenerElementSize = sizeof(EventStorage);

        StreamQueuedEventsListener(std::shared_ptr<Queue> eventsQueue);
        StreamQueuedEventsListener(std::shared_ptr<cpp_freertos::Queue> eventsQueue);

        void onEvent(Stream *stream, Stream::Event event, Stream::EventSourceMode source);



@@ 39,7 37,7 @@ namespace audio
        std::size_t getEventsCount() const;

      private:
        std::shared_ptr<Queue> queue;
        std::shared_ptr<cpp_freertos::Queue> queue;
    };

}; // namespace audio

M module-bsp/board/linux/battery-charger/battery_charger.cpp => module-bsp/board/linux/battery-charger/battery_charger.cpp +81 -95
@@ 1,21 1,5 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/*
 * battery_charger.cpp
 *
 *  Created on: Jul 1, 2019
 *      Author: kuba
 */
#include <stdint.h>

extern "C"
{
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
}

#include <sys/stat.h>
#include <fcntl.h>
#include <module-utils/common_data/EventStore.hpp>


@@ 23,114 7,116 @@ extern "C"
#include "board.h"
#include "bsp/battery-charger/battery_charger.hpp"

#define BSP_BATTERY_CHARGER_I2C_ADDR (0xD2 >> 1)
#define BSP_FUEL_GAUGE_I2C_ADDR      (0x6C >> 1)
#define BSP_TOP_CONTROLLER_I2C_ADDR  (0xCC >> 1)

static xQueueHandle qHandleIrq            = NULL;
static TaskHandle_t battery_worker_handle = NULL;

static uint8_t battLevel = 100;
static bool plugged      = false;
namespace bsp
namespace bsp::battery_charger
{
    namespace
    {
        xQueueHandle IRQQueueHandle         = nullptr;
        TaskHandle_t batteryWorkerHandle    = nullptr;
        constexpr auto batteryFIFO          = "/tmp/fifoBattKeys";
        constexpr auto fifoFileAccessRights = 0666;
        constexpr auto fifoBuffSize         = 10;
        constexpr auto queueTimeoutTicks    = 100;
        constexpr auto taskDelay            = 50;

        StateOfCharge battLevel             = 100;
        constexpr StateOfCharge fullBattery = 100;
        bool plugged                        = false;

        constexpr auto chargerPlugStateChange = 'p';
        constexpr auto batteryLevelUp         = ']';
        constexpr auto batteryLevelDown       = '[';

        void battery_worker(void *parameters)
        {
            mkfifo(batteryFIFO, fifoFileAccessRights);

            // Open FIFO for write only
            int fd = open(batteryFIFO, O_RDONLY | O_NONBLOCK);

            while (true) {
                std::uint8_t buff[fifoBuffSize];
                std::int32_t readBytes = read(fd, buff, fifoBuffSize);

                if (readBytes > 0) {
                    std::uint8_t notification = 0;
                    switch (static_cast<char>(buff[0])) {
                    case chargerPlugStateChange:
                        notification = static_cast<std::uint8_t>(batteryIRQSource::INOKB);
                        plugged      = !plugged;
                        break;
                    case batteryLevelUp:
                        notification = static_cast<std::uint8_t>(batteryIRQSource::INTB);
                        if (battLevel < fullBattery)
                            battLevel++;
                        else {
                            // second 100% in a row
                            if (plugged && Store::Battery::get().level == fullBattery) {
                                Store::Battery::modify().state = Store::Battery::State::PluggedNotCharging;
                            }
                        }
                        break;
                    case batteryLevelDown:
                        notification = static_cast<std::uint8_t>(batteryIRQSource::INTB);
                        if (battLevel >= 1)
                            battLevel--;
                        if (plugged && Store::Battery::get().level == fullBattery) {
                            // charging but not 100% anymore
                            Store::Battery::modify().state = Store::Battery::State::Charging;
                        }
                        break;
                    }
                    xQueueSend(IRQQueueHandle, &notification, queueTimeoutTicks);
                }
                vTaskDelay(taskDelay);
            }
        }
    } // namespace

    static void battery_worker(void *pvp);

    int battery_Init(xQueueHandle qHandle)
    int init(xQueueHandle queueHandle)
    {
        qHandleIrq = qHandle;
        if (xTaskCreate(battery_worker, "battery", 512, qHandle, 0, &battery_worker_handle) != pdPASS) {
        IRQQueueHandle = queueHandle;
        if (xTaskCreate(battery_worker, "battery", 512, queueHandle, 0, &batteryWorkerHandle) != pdPASS) {
            return 1;
        }
        Store::Battery::modify().level = battLevel;
        return 0;
    }

    void battery_Deinit(void)
    void deinit()
    {
        qHandleIrq = NULL;
        vTaskDelete(battery_worker_handle);
        IRQQueueHandle = nullptr;
        vTaskDelete(batteryWorkerHandle);
    }
    void battery_getBatteryLevel(uint8_t &levelPercent)

    StateOfCharge getBatteryLevel()
    {
        levelPercent                   = battLevel;
        Store::Battery::modify().level = battLevel;
        return battLevel;
    }

    void battery_getChargeStatus(bool &status)
    bool getChargeStatus()
    {
        status = plugged;
        bool status = plugged;
        if (status) {
            Store::Battery::modify().state = Store::Battery::State::Charging;
        }
        else {
            Store::Battery::modify().state = Store::Battery::State::Discharging;
        }
        return status;
    }

    // TODO function unused in linux driver, left for compatibility with target driver
    void battery_ClearAllIRQs(void)
    void clearAllIRQs()
    {}
    // TODO function unused in linux driver, left for compatibility with target driver
    void battery_clearFuelGuageIRQ(void)
    void clearFuelGuageIRQ()
    {}

    static void battery_worker(void *pvp)
    {

        const char *myfifo = "/tmp/fifoBattKeys";

        // Creating the named file(FIFO)
        // mkfifo(<pathname>, <permission>)
        mkfifo(myfifo, 0666);

        // Open FIFO for write only
        int fd;
        fd = open(myfifo, O_RDONLY | O_NONBLOCK);

        while (1) {
            uint8_t buff[10];
            int32_t readedBytes = read(fd, buff, 10);

            if (readedBytes > 0) {

                uint8_t notification = 0;
                switch (buff[0]) {
                case 'p':
                    notification = static_cast<uint8_t>(bsp::batteryIRQSource::INOKB);
                    plugged      = 1 - plugged;
                    break;
                case ']':
                    notification = static_cast<uint8_t>(bsp::batteryIRQSource::INTB);
                    if (battLevel < 100)
                        battLevel++;
                    else {
                        // second 100% in a row
                        if (plugged && Store::Battery::get().level == 100) {
                            Store::Battery::modify().state = Store::Battery::State::PluggedNotCharging;
                        }
                    }
                    break;
                case '[':
                    notification = static_cast<uint8_t>(bsp::batteryIRQSource::INTB);
                    if (battLevel >= 1)
                        battLevel--;
                    if (plugged && Store::Battery::get().level == 100) {
                        // charging but not 100% anymore
                        Store::Battery::modify().state = Store::Battery::State::Charging;
                    }
                    break;
                }
                xQueueSend(qHandleIrq, &notification, 100);
            }
            vTaskDelay(50);
        }
    }

    std::uint16_t battery_getStatusRegister()
    std::uint16_t getStatusRegister()
    {
        return static_cast<std::uint16_t>(batteryINTBSource::SOCOnePercentChange);
    }

} // namespace bsp
} // namespace bsp::battery_charger

M module-bsp/board/linux/usb_cdc/usb_cdc.cpp => module-bsp/board/linux/usb_cdc/usb_cdc.cpp +1 -2
@@ 32,7 32,6 @@ namespace bsp
    {
        LOG_INFO("[ServiceDesktop:BSP_Driver] Start reading on fd:%d", fd);
        char inputData[SERIAL_BUFFER_LEN];
        static std::string receiveMsg;

        while (1) {
            if (uxQueueSpacesAvailable(USBReceiveQueue) != 0) {


@@ 61,7 60,7 @@ namespace bsp
                        continue;
                    }
#endif
                    receiveMsg = std::string(inputData, inputData + length);
                    std::string *receiveMsg = new std::string(inputData, inputData + length);
                    xQueueSend(USBReceiveQueue, &receiveMsg, portMAX_DELAY);
                }
                else {

A module-bsp/board/rt1051/bsp/battery-charger/MAX77818.hpp => module-bsp/board/rt1051/bsp/battery-charger/MAX77818.hpp +160 -0
@@ 0,0 1,160 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once

namespace bsp::battery_charger
{

    constexpr inline auto BATTERY_CHARGER_I2C_ADDR = 0xD2 >> 1;
    constexpr inline auto FUEL_GAUGE_I2C_ADDR      = 0x6C >> 1;
    constexpr inline auto TOP_CONTROLLER_I2C_ADDR  = 0xCC >> 1;

    enum class Registers
    {
        TOP_CONTROLL_PMIC_ID_REG  = 0x20,
        TOP_CONTROLL_PMIC_VER_REG = 0x21,
        TOP_CONTROLL_IRQ_SRC_REG  = 0x22,
        TOP_CONTROLL_IRQ_MASK_REG = 0x23,
        SYSTEM_IRQ_REG            = 0x24,

        STATUS_REG     = 0x00,
        VALRT_Th_REG   = 0x01,
        TALRT_Th_REG   = 0x02,
        SALRT_Th_REG   = 0x03,
        AtRate_REG     = 0x04,
        RepCap_REG     = 0x05,
        RepSOC_REG     = 0x06,
        Age_REG        = 0x07,
        TEMP_REG       = 0x08,
        VCELL_REG      = 0x09,
        Current_REG    = 0x0A,
        AvgCurrent_REG = 0x0B,
        QResidual_REG  = 0x0C,
        MixSOC_REG     = 0x0D,
        AvSOC_REG      = 0x0E,
        MixCap_REG     = 0x0F,

        FullCAP_REG    = 0x10,
        TTE_REG        = 0x11,
        QRtable00_REG  = 0x12,
        FullSOCthr_REG = 0x13,
        RSLOW_REG      = 0x14,
        AvgTA_REG      = 0x16,
        Cycles_REG     = 0x17,
        DesignCap_REG  = 0x18,
        AvgVCELL_REG   = 0x19,
        MaxMinTemp_REG = 0x1A,
        MaxMinVolt_REG = 0x1B,
        MaxMinCurr_REG = 0x1C,
        CONFIG_REG     = 0x1D,
        CONFIG2_REG    = 0xBB,
        ICHGTERM_REG   = 0x1E,
        AvCap_REG      = 0x1F,

        TTF_REG        = 0x20,
        DevName_REG    = 0x21,
        QRtable10_REG  = 0x22,
        FullCAPNom_REG = 0x23,
        TempNom_REG    = 0x24,
        TempLim_REG    = 0x25,
        AIN0_REG       = 0x27,
        LearnCFG_REG   = 0x28,
        FilterCFG_REG  = 0x29,
        RelaxCFG_REG   = 0x2A,
        MiscCFG_REG    = 0x2B,
        TGAIN_REG      = 0x2C,
        TOFF_REG       = 0x2D,
        CGAIN_REG      = 0x2E,
        COFF_REG       = 0x2F,

        QRtable20_REG  = 0x32,
        AtTTF_REG      = 0x33,
        FullCapRep_REG = 0x35,
        lavgEmpty_REG  = 0x36,
        FCTC_REG       = 0x37,
        RCOMP0_REG     = 0x38,
        TempCo_REG     = 0x39,
        VEmpty_REG     = 0x3A,
        TIMER_REG      = 0x3E,
        SHDNTIMER_REG  = 0x3F,

        QRtable30_REG = 0x42,
        dQ_acc_REG    = 0x45,
        dP_acc_REG    = 0x46,
        ConvgCfg_REG  = 0x49,
        VFRemCap_REG  = 0x4A,
        QH_REG        = 0x4D,
        CHG_INT_REG   = 0xb0,
        CHG_INT_OK    = 0xb2
    };

    // STATUS register bits
    enum STATUS
    {
        Inm    = (1 << 0),
        POR    = (1 << 1),
        SPR_2  = (1 << 2),
        BST    = (1 << 3),
        Isysmx = (1 << 4),
        SPR_5  = (1 << 5),
        ThmHot = (1 << 6),
        dSOCi  = (1 << 7),
        Vmn    = (1 << 8),
        Tmn    = (1 << 9),
        Smn    = (1 << 10),
        Bi     = (1 << 11),
        Vmx    = (1 << 12),
        Tmx    = (1 << 13),
        Smx    = (1 << 14),
        Br     = (1 << 15),
    };

    /// CHG_INT registers from documentation
    enum class CHG_INT
    {
        BYP_I   = (1 << 0),
        RSVD    = (1 << 1),
        BATP_I  = (1 << 2),
        BAT_I   = (1 << 3),
        CHG_I   = (1 << 4),
        WCIN_I  = (1 << 5),
        CHGIN_I = (1 << 6),
        AICL_I  = (1 << 7),
    };

    // CONFIG register bits
    enum class CONFIG
    {
        Ber    = 1 << 0,
        Bei    = 1 << 1,
        Aen    = 1 << 2,
        FTHRM  = 1 << 3,
        ETHRM  = 1 << 4,
        SPR_5  = 1 << 5,
        I2CSH  = 1 << 6,
        SHDN   = 1 << 7,
        Tex    = 1 << 8,
        Ten    = 1 << 9,
        AINSH  = 1 << 10,
        SPR_11 = 1 << 11,
        Vs     = 1 << 12,
        Ts     = 1 << 13,
        Ss     = 1 << 14,
        SPR_15 = 1 << 15
    };

    // CONFIG2 register bits
    enum class CONFIG2
    {
        ISysNCurr    = 1 << 0,
        OCVQen       = 1 << 4,
        LdMdl        = 1 << 5,
        TAlrtEn      = 1 << 6,
        dSOCen       = 1 << 7,
        ThmHotAlrtEn = 1 << 8,
        ThmHotEn     = 1 << 9,
        FCThmHot     = 1 << 10,
        SPR          = 1 << 11
    };

} // namespace bsp::battery_charger

M module-bsp/board/rt1051/bsp/battery-charger/battery_charger.cpp => module-bsp/board/rt1051/bsp/battery-charger/battery_charger.cpp +337 -478
@@ 1,585 1,444 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/*
 * battery_charger.cpp
 *
 *  Created on: Jun 28, 2019
 *      Author: kuba
 */

extern "C"
{
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
}

#include "bsp/battery-charger/battery_charger.hpp"
#include "MAX77818.hpp"
#include "vfs.hpp"

#include "bsp/BoardDefinitions.hpp"
#include "common_data/EventStore.hpp"
#include "drivers/gpio/DriverGPIO.hpp"
#include "drivers/i2c/DriverI2C.hpp"
#include <cstdio>
#include <purefs/filesystem_paths.hpp>
#include <utility>

#define BSP_BATTERY_CHARGER_I2C_ADDR (0xD2 >> 1)
#define BSP_FUEL_GAUGE_I2C_ADDR      (0x6C >> 1)
#define BSP_TOP_CONTROLLER_I2C_ADDR  (0xCC >> 1)
namespace bsp::battery_charger
{
    namespace
    {
        constexpr std::uint32_t i2cSubaddresSize = 1;

static const uint32_t i2cSubaddresSize = 1;
        const auto cfgFile     = purefs::dir::getCurrentOSPath() / "batteryAdjustementConfig.cfg";
        const auto cfgFilePrev = purefs::dir::getCurrentOSPath() / "batteryAdjustementConfig_old.cfg";

namespace configs
{
    const auto battery_cfgFile     = purefs::dir::getCurrentOSPath() / "batteryAdjustementConfig.cfg";
    const auto battery_cfgFilePrev = purefs::dir::getCurrentOSPath() / "batteryAdjustementConfig_old.cfg";
} // namespace configs
        constexpr std::uint16_t BATT_SERVICE_AVG_CURRENT_PERIOD =
            0x00; //< 0.1758 ms * 2^(2 + BATT_SERVICE_AVG_CURRENT_PERIOD)         == 700ms
        constexpr std::uint16_t BATT_SERVICE_AVG_CELL_VOLTAGE_PERIOD =
            0x00; //< 0.1758 ms * 2^(6 + BATT_SERVICE_AVG_CELL_VOLTAGE_PERIOD)    == 11.25 s
        constexpr std::uint16_t BATT_SERVICE_AVG_MIXING_PERIOD =
            0x0D; //< 0.1758 ms * 2^(5 + BATT_SERVICE_AVG_MIXING_PERIOD)          == 12.8 h
        constexpr std::uint16_t BATT_SERVICE_AVG_TEMP_PERIOD =
            0x01; //< 0.1758 ms * 2^(11 + BATT_SERVICE_AVG_TEMP_PERIOD)           == 12 min
        constexpr std::uint16_t BATT_SERVICE_AVG_NEMPTY_PERIOD = 0x00;

static const uint16_t BATT_SERVICE_AVG_CURRENT_PERIOD =
    0x00; //< 0.1758 ms * 2^(2 + BATT_SERVICE_AVG_CURRENT_PERIOD)         == 700ms
static const uint16_t BATT_SERVICE_AVG_CELL_VOLTAGE_PERIOD =
    0x00; //< 0.1758 ms * 2^(6 + BATT_SERVICE_AVG_CELL_VOLTAGE_PERIOD)    == 11.25 s
static const uint16_t BATT_SERVICE_AVG_MIXING_PERIOD =
    0x0D; //< 0.1758 ms * 2^(5 + BATT_SERVICE_AVG_MIXING_PERIOD)          == 12.8 h
static const uint16_t BATT_SERVICE_AVG_TEMP_PERIOD =
    0x01; //< 0.1758 ms * 2^(11 + BATT_SERVICE_AVG_TEMP_PERIOD)           == 12 min
static const uint16_t BATT_SERVICE_AVG_NEMPTY_PERIOD = 0x00;
        constexpr auto ENABLE_ALL_IRQ_MASK = 0xf8;

static const uint16_t battery_nominalCapacitymAh = 3000;
        constexpr std::uint16_t nominalCapacitymAh = 3000;

static const uint8_t battery_fullyChargedPercent = 100;
static const uint8_t battery_DischargedPercent   = 15;
        constexpr std::uint8_t fullyChargedPercent = 100;
        constexpr std::uint8_t DischargedPercent   = 15;

static const uint8_t battery_maxTemperatureDegrees = 50;
static const uint8_t battery_minTemperatureDegrees = 5;
        constexpr std::uint8_t maxTemperatureDegrees = 50;
        constexpr std::uint8_t minTemperatureDegrees = 5;

static constexpr inline uint16_t battery_maxVoltagemV = 4200;
static constexpr inline uint16_t battery_minVoltagemV = 3600;
        constexpr std::uint16_t maxVoltagemV = 4200;
        constexpr std::uint16_t minVoltagemV = 3600;

using namespace drivers;
        std::shared_ptr<drivers::DriverI2C> i2c;
        std::shared_ptr<drivers::DriverGPIO> gpio;

static std::shared_ptr<drivers::DriverI2C> i2c;
static std::shared_ptr<drivers::DriverGPIO> gpio;
        drivers::I2CAddress fuelGaugeAddress      = {FUEL_GAUGE_I2C_ADDR, 0, i2cSubaddresSize};
        drivers::I2CAddress batteryChargerAddress = {BATTERY_CHARGER_I2C_ADDR, 0, i2cSubaddresSize};
        drivers::I2CAddress topControllerAddress  = {TOP_CONTROLLER_I2C_ADDR, 0, i2cSubaddresSize};

static bsp::batteryRetval battery_loadConfiguration(void);
        xQueueHandle IRQQueueHandle = nullptr;

static bsp::batteryRetval battery_storeConfiguration(void);
        int fuelGaugeWrite(Registers registerAddress, std::uint16_t value)
        {
            fuelGaugeAddress.subAddress = static_cast<std::uint32_t>(registerAddress);
            auto ret = i2c->Write(fuelGaugeAddress, reinterpret_cast<std::uint8_t *>(&value), sizeof(std::uint16_t));

static int battery_fuelGaugeWrite(bsp::batteryChargerRegisters registerAddress, uint16_t value);
            if (ret != sizeof(std::uint16_t)) {
                return kStatus_Fail;
            }
            return kStatus_Success;
        }

static int battery_fuelGaugeRead(bsp::batteryChargerRegisters registerAddress, uint16_t *value);
        std::pair<int, std::uint16_t> fuelGaugeRead(Registers registerAddress)
        {
            std::uint16_t value;
            int status                  = kStatus_Success;
            fuelGaugeAddress.subAddress = static_cast<std::uint32_t>(registerAddress);
            auto ret = i2c->Read(fuelGaugeAddress, reinterpret_cast<std::uint8_t *>(&value), sizeof(std::uint16_t));

            if (ret != sizeof(std::uint16_t)) {
                status = kStatus_Fail;
            }
            return std::make_pair(status, value);
        }

static int battery_chargerWrite(bsp::batteryChargerRegisters registerAddress, uint8_t value);
        int chargerWrite(Registers registerAddress, std::uint8_t value)
        {
            batteryChargerAddress.subAddress = static_cast<std::uint32_t>(registerAddress);
            auto ret =
                i2c->Write(batteryChargerAddress, reinterpret_cast<std::uint8_t *>(&value), sizeof(std::uint8_t));

static int battery_chargerRead(bsp::batteryChargerRegisters registerAddress, uint8_t *value);
            if (ret != sizeof(std::uint8_t)) {
                return kStatus_Fail;
            }
            return kStatus_Success;
        }

static int battery_chargerTopControllerWrite(bsp::batteryChargerRegisters registerAddress, uint8_t value);
        std::pair<int, std::uint8_t> chargerRead(Registers registerAddress)
        {
            std::uint8_t value;
            int status                       = kStatus_Success;
            batteryChargerAddress.subAddress = static_cast<std::uint32_t>(registerAddress);
            auto ret                         = i2c->Read(batteryChargerAddress, &value, sizeof(std::uint8_t));

            if (ret != sizeof(std::uint8_t)) {
                status = kStatus_Fail;
            }
            return std::make_pair(status, value);
        }

static int battery_chargerTopControllerRead(bsp::batteryChargerRegisters registerAddress, uint8_t *value);
        int chargerTopControllerWrite(Registers registerAddress, std::uint8_t value)
        {
            topControllerAddress.subAddress = static_cast<std::uint32_t>(registerAddress);
            auto ret = i2c->Write(topControllerAddress, reinterpret_cast<std::uint8_t *>(&value), sizeof(std::uint8_t));

static bsp::batteryRetval battery_setAvgCalcPeriods(void);
            if (ret != sizeof(std::uint8_t)) {
                return kStatus_Fail;
            }
            return kStatus_Success;
        }

static bsp::batteryRetval battery_setAvgCalcPeriods(void);
        std::pair<int, std::uint8_t> chargerTopControllerRead(Registers registerAddress)
        {
            std::uint8_t value;
            int status                      = kStatus_Success;
            topControllerAddress.subAddress = static_cast<std::uint32_t>(registerAddress);
            auto ret                        = i2c->Read(topControllerAddress, &value, sizeof(std::uint8_t));
            if (ret != sizeof(std::uint8_t)) {
                status = kStatus_Fail;
            }
            return std::make_pair(status, value);
        }

static bsp::batteryRetval battery_setNominalBatteryCapacity(uint16_t capacity);
        batteryRetval loadConfiguration()
        {
            auto fd = std::fopen(cfgFile.c_str(), "r");
            if (fd == nullptr) {
                LOG_WARN("Configuration file [%s] could not be opened. Trying to open file [%s]",
                         cfgFile.c_str(),
                         cfgFilePrev.c_str());
                fd = std::fopen(cfgFilePrev.c_str(), "r");
                if (fd == nullptr) {
                    LOG_WARN("Configuration file [%s] could not be opened.", cfgFilePrev.c_str());
                    return batteryRetval::ChargerError;
                }
            }

            std::uint16_t regValue = 0;
            for (auto i = 0; i < 0xff; ++i) {
                if (std::fread(&regValue, sizeof(regValue), 1, fd) != sizeof(regValue)) {
                    LOG_ERROR("Reading register 0x%x failed.", i);
                    std::fclose(fd);
                    return batteryRetval::ChargerError;
                }

                if (fuelGaugeWrite(static_cast<Registers>(i), regValue) != kStatus_Success) {
                    LOG_ERROR("Writing register 0x%x failed.", i);
                    std::fclose(fd);
                    return batteryRetval::ChargerError;
                }
            }

static bsp::batteryRetval battery_setChargingDischargingThresholds(uint8_t chargedThresholdPercent,
                                                                   uint8_t dischargedThresholdPercent);
            std::fclose(fd);
            return batteryRetval::OK;
        }

static bsp::batteryRetval battery_setTemperatureThresholds(uint8_t maxTemperatureDegrees,
                                                           uint8_t minTemperatureDegrees);
        batteryRetval storeConfiguration()
        {
            // TODO:M.P procedure below seems to crash system, it should be fixed.
            if (ff_rename(cfgFile.c_str(), cfgFilePrev.c_str(), false) != 0) {
                LOG_ERROR("Could not move configuration file");
                return batteryRetval::ChargerError;
            }

            auto fd = std::fopen(cfgFile.c_str(), "w");
            if (fd == nullptr) {
                LOG_ERROR("Could not open configuration file");
                return batteryRetval::ChargerError;
            }

            for (unsigned int i = 0; i < 0xff; ++i) {
                auto regVal = fuelGaugeRead(static_cast<Registers>(i));
                if (regVal.first != kStatus_Success) {
                    LOG_ERROR("Reading register 0x%x failed.", i);
                    std::fclose(fd);
                    return batteryRetval::ChargerError;
                }

                if (std::fwrite(&regVal.second, sizeof(regVal.second), 1, fd) != sizeof(regVal.second)) {
                    LOG_ERROR("Storing register 0x%x failed.", i);
                    std::fclose(fd);
                    std::remove(cfgFile.c_str());
                    return batteryRetval::ChargerError;
                }
            }

static bsp::batteryRetval battery_setServiceVoltageThresholds(uint16_t maxVoltage_mV, uint16_t minVoltage_mV);
            std::fclose(fd);
            return batteryRetval::OK;
        }

static bsp::batteryRetval battery_enableFuelGuageIRQs(void);
        batteryRetval setAvgCalcPeriods()
        {
            std::uint16_t regVal = 0;
            regVal |= (BATT_SERVICE_AVG_CURRENT_PERIOD << 0);
            regVal |= (BATT_SERVICE_AVG_CELL_VOLTAGE_PERIOD << 4);
            regVal |= (BATT_SERVICE_AVG_MIXING_PERIOD << 7);
            regVal |= (BATT_SERVICE_AVG_TEMP_PERIOD << 11);
            regVal |= (BATT_SERVICE_AVG_NEMPTY_PERIOD << 14);

            if (fuelGaugeWrite(Registers::FilterCFG_REG, regVal) != kStatus_Success) {
                LOG_ERROR("setAvgCalcPeriods failed.");
                return batteryRetval::ChargerError;
            }
            return batteryRetval::OK;
        }

static bsp::batteryRetval battery_enableTopIRQs(void);
        batteryRetval setNominalBatteryCapacity(std::uint16_t capacity)
        {
            std::uint16_t regVal = capacity * 2;

static bsp::batteryRetval battery_configureAlerts();
            if (fuelGaugeWrite(Registers::DesignCap_REG, regVal) != kStatus_Success) {
                LOG_ERROR("setNominalBatteryCapacity failed.");
                return batteryRetval::ChargerError;
            }
            return batteryRetval::OK;
        }

static void s_BSP_BatteryChargerIrqPinsInit();
        batteryRetval setChargingDischargingThresholds(std::uint8_t chargedThresholdPercent,
                                                       std::uint8_t dischargedThresholdPercent)
        {
            uint16_t regVal = (chargedThresholdPercent << 8) | dischargedThresholdPercent;

static xQueueHandle qHandleIrq = NULL;
            if (fuelGaugeWrite(Registers::SALRT_Th_REG, regVal) != kStatus_Success) {
                LOG_ERROR("setChargingDischargingThresholds failed.");
                return batteryRetval::ChargerError;
            }
            return batteryRetval::OK;
        }

namespace bsp
{
        batteryRetval setTemperatureThresholds(std::uint8_t maxTemperatureDegrees, std::uint8_t minTemperatureDegrees)
        {
            std::uint16_t regVal = (maxTemperatureDegrees << 8) | minTemperatureDegrees;

    // STATUS register bits
    enum B_STATUS
    {
        Inm    = (1 << 0),
        POR    = (1 << 1),
        SPR_2  = (1 << 2),
        BST    = (1 << 3),
        Isysmx = (1 << 4),
        SPR_5  = (1 << 5),
        ThmHot = (1 << 6),
        dSOCi  = (1 << 7),
        Vmn    = (1 << 8),
        Tmn    = (1 << 9),
        Smn    = (1 << 10),
        Bi     = (1 << 11),
        Vmx    = (1 << 12),
        Tmx    = (1 << 13),
        Smx    = (1 << 14),
        Br     = (1 << 15),
    };

    /// CHG_INT registers from documentation
    enum B_CHG_INT
    {
        BYP_I   = (1 << 0),
        RSVD    = (1 << 1),
        BATP_I  = (1 << 2),
        BAT_I   = (1 << 3),
        CHG_I   = (1 << 4),
        WCIN_I  = (1 << 5),
        CHGIN_I = (1 << 6),
        AICL_I  = (1 << 7),
    };

    // CONFIG register bits
    enum class B_CONFIG
    {
        Ber    = 1 << 0,
        Bei    = 1 << 1,
        Aen    = 1 << 2,
        FTHRM  = 1 << 3,
        ETHRM  = 1 << 4,
        SPR_5  = 1 << 5,
        I2CSH  = 1 << 6,
        SHDN   = 1 << 7,
        Tex    = 1 << 8,
        Ten    = 1 << 9,
        AINSH  = 1 << 10,
        SPR_11 = 1 << 11,
        Vs     = 1 << 12,
        Ts     = 1 << 13,
        Ss     = 1 << 14,
        SPR_15 = 1 << 15
    };

    uint16_t battery_get_CHG_INT_OK();

    int battery_Init(xQueueHandle qHandle)
            if (fuelGaugeWrite(Registers::TALRT_Th_REG, regVal) != kStatus_Success) {
                LOG_ERROR("setTemperatureThresholds failed.");
                return batteryRetval::ChargerError;
            }
            return batteryRetval::OK;
        }

        batteryRetval setServiceVoltageThresholds(std::uint16_t maxVoltage_mV, std::uint16_t minVoltage_mV)
        {
            std::uint16_t regVal = ((maxVoltage_mV / 20) << 8) | (minVoltage_mV / 20);

            if (fuelGaugeWrite(Registers::VALRT_Th_REG, regVal) != kStatus_Success) {

                LOG_ERROR("setServiceVoltageThresholds failed.");
                return batteryRetval::ChargerError;
            }
            return batteryRetval::OK;
        }

        batteryRetval enableFuelGuageIRQs()
        {
            std::uint16_t regVal = static_cast<std::uint16_t>(CONFIG2::dSOCen);

            if (fuelGaugeWrite(Registers::CONFIG2_REG, regVal) != kStatus_Success) {
                LOG_ERROR("enableFuelGuageIRQs failed.");
                return batteryRetval::ChargerError;
            }

            return batteryRetval::OK;
        }

        batteryRetval configureAlerts()
        {
            std::uint16_t regVal = static_cast<std::uint16_t>(CONFIG::Aen);

            if (fuelGaugeWrite(Registers::CONFIG_REG, regVal) != kStatus_Success) {
                LOG_ERROR("configureAlerts failed.");
                return batteryRetval::ChargerError;
            }

            return batteryRetval::OK;
        }

        batteryRetval enableTopIRQs()
        {
            std::uint8_t val = ENABLE_ALL_IRQ_MASK;

            if (chargerTopControllerWrite(Registers::TOP_CONTROLL_IRQ_MASK_REG, val) != kStatus_Success) {
                LOG_ERROR("enableIRQs read failed.");
                return batteryRetval::ChargerError;
            }

            return batteryRetval::OK;
        }

        void IRQPinsInit()
        {
            gpio =
                drivers::DriverGPIO::Create(static_cast<drivers::GPIOInstances>(BoardDefinitions::BATTERY_CHARGER_GPIO),
                                            drivers::DriverGPIOParams{});

            drivers::DriverGPIOPinParams INOKBPinConfig;
            INOKBPinConfig.dir      = drivers::DriverGPIOPinParams::Direction::Input;
            INOKBPinConfig.irqMode  = drivers::DriverGPIOPinParams::InterruptMode::IntRisingOrFallingEdge;
            INOKBPinConfig.defLogic = 0;
            INOKBPinConfig.pin      = static_cast<std::uint32_t>(BoardDefinitions::BATTERY_CHARGER_INOKB_PIN);
            gpio->ConfPin(INOKBPinConfig);

            drivers::DriverGPIOPinParams INTBPinConfig;
            INTBPinConfig.dir      = drivers::DriverGPIOPinParams::Direction::Input;
            INTBPinConfig.irqMode  = drivers::DriverGPIOPinParams::InterruptMode::IntFallingEdge;
            INTBPinConfig.defLogic = 0;
            INTBPinConfig.pin      = static_cast<std::uint32_t>(BoardDefinitions::BATTERY_CHARGER_INTB_PIN);
            gpio->ConfPin(INTBPinConfig);

            gpio->EnableInterrupt(1 << static_cast<std::uint32_t>(BoardDefinitions::BATTERY_CHARGER_INOKB_PIN));
            gpio->EnableInterrupt(1 << static_cast<std::uint32_t>(BoardDefinitions::BATTERY_CHARGER_INTB_PIN));
        }
    } // namespace

    int init(xQueueHandle queueHandle)
    {
        i2c = DriverI2C::Create(
            static_cast<I2CInstances>(BoardDefinitions::BATTERY_CHARGER_I2C),
            DriverI2CParams{.baudrate = static_cast<uint32_t>(BoardDefinitions::BATTERY_CHARGER_I2C_BAUDRATE)});
        drivers::DriverI2CParams i2cParams;
        i2cParams.baudrate = static_cast<std::uint32_t>(BoardDefinitions::BATTERY_CHARGER_I2C_BAUDRATE);
        i2c = drivers::DriverI2C::Create(static_cast<drivers::I2CInstances>(BoardDefinitions::BATTERY_CHARGER_I2C),
                                         i2cParams);

        qHandleIrq = qHandle;
        IRQQueueHandle = queueHandle;

        // check Power-On reset bit
        uint16_t status        = 0;
        const uint16_t porMask = 0x0002;
        battery_fuelGaugeRead(bsp::batteryChargerRegisters::STATUS_REG, &status);
        std::uint16_t status = fuelGaugeRead(Registers::STATUS_REG).second;

        if (status & porMask) {
        if (status & static_cast<std::uint16_t>(STATUS::POR)) {
            LOG_INFO("Initializing battery charger");
            battery_loadConfiguration();
            battery_setAvgCalcPeriods();
            battery_setNominalBatteryCapacity(battery_nominalCapacitymAh);
            battery_setChargingDischargingThresholds(battery_fullyChargedPercent, battery_DischargedPercent);
            battery_setTemperatureThresholds(battery_maxTemperatureDegrees, battery_minTemperatureDegrees);
            battery_setServiceVoltageThresholds(battery_maxVoltagemV, battery_minVoltagemV);
            loadConfiguration();
            setAvgCalcPeriods();
            setNominalBatteryCapacity(nominalCapacitymAh);
            setChargingDischargingThresholds(fullyChargedPercent, DischargedPercent);
            setTemperatureThresholds(maxTemperatureDegrees, minTemperatureDegrees);
            setServiceVoltageThresholds(maxVoltagemV, minVoltagemV);
        }

        battery_configureAlerts();
        battery_enableFuelGuageIRQs();
        configureAlerts();
        enableFuelGuageIRQs();

        uint8_t level = 0;
        bool charging = false;
        battery_getBatteryLevel(level);
        battery_getChargeStatus(charging);
        StateOfCharge level = getBatteryLevel();
        bool charging       = getChargeStatus();
        LOG_INFO("Phone battery start state: %d %d", level, charging);

        battery_ClearAllIRQs();
        battery_enableTopIRQs();
        clearAllIRQs();
        enableTopIRQs();

        s_BSP_BatteryChargerIrqPinsInit();
        IRQPinsInit();

        return 0;
    }

    void battery_Deinit(void)
    void deinit()
    {
        battery_storeConfiguration();
        storeConfiguration();

        gpio->DisableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::BATTERY_CHARGER_INTB_PIN));
        gpio->DisableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::BATTERY_CHARGER_INOKB_PIN));
        gpio->DisableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::BATTERY_CHARGER_WCINOKB));

        qHandleIrq = NULL;
        IRQQueueHandle = nullptr;

        i2c.reset();
        gpio.reset();
    }

    void battery_getBatteryLevel(uint8_t &levelPercent)
    StateOfCharge getBatteryLevel()
    {
        uint16_t val = 0;
        if (battery_fuelGaugeRead(bsp::batteryChargerRegisters::RepSOC_REG, &val) != kStatus_Success) {
        auto readout = fuelGaugeRead(Registers::RepSOC_REG);
        if (readout.first != kStatus_Success) {
            LOG_ERROR("failed to get battery percent");
        }
        levelPercent                   = (val & 0xff00) >> 8;
        StateOfCharge levelPercent     = (readout.second & 0xff00) >> 8;
        Store::Battery::modify().level = levelPercent;
        return levelPercent;
    }

    void battery_getChargeStatus(bool &status)
    bool getChargeStatus()
    {
        uint8_t val = 0;
        std::uint8_t val = 0;
        // read clears state
        if (battery_chargerRead(bsp::batteryChargerRegisters::CHG_INT_OK, &val) != kStatus_Success) {
        auto value = chargerRead(Registers::CHG_INT_OK);
        if (value.first != kStatus_Success) {
            LOG_ERROR("failed to read charge status");
        }
        status = val & B_CHG_INT::CHGIN_I;
        bool status = value.second & static_cast<std::uint8_t>(CHG_INT::CHGIN_I);
        if (status) {
            Store::Battery::modify().state = Store::Battery::State::Charging;
        }
        else {
            Store::Battery::modify().state = Store::Battery::State::Discharging;
        }
        return status;
    }

    std::uint16_t battery_getStatusRegister()
    std::uint16_t getStatusRegister()
    {
        uint16_t status = 0;
        battery_fuelGaugeRead(bsp::batteryChargerRegisters::STATUS_REG, &status);
        return status;
        auto status = fuelGaugeRead(Registers::STATUS_REG);
        return status.second;
    }

    void battery_ClearAllIRQs(void)
    void clearAllIRQs()
    {
        uint8_t val = 0;
        battery_chargerRead(bsp::batteryChargerRegisters::CHG_INT_REG, &val);
        if (val != 0) {
        auto value = chargerRead(Registers::CHG_INT_REG);
        if (value.second != 0) {
            // write zero to clear irq source
            battery_chargerWrite(bsp::batteryChargerRegisters::CHG_INT_REG, 0);
            chargerWrite(Registers::CHG_INT_REG, 0);
        }

        uint16_t status = battery_getStatusRegister();
        std::uint16_t status = getStatusRegister();
        if (status != 0) {
            // write zero to clear irq source
            battery_fuelGaugeWrite(bsp::batteryChargerRegisters::STATUS_REG, 0);
            fuelGaugeWrite(Registers::STATUS_REG, 0);
        }
    }

    void battery_clearFuelGuageIRQ(void)
    void clearFuelGuageIRQ()
    {
        // write zero to clear interrupt source
        battery_fuelGaugeWrite(bsp::batteryChargerRegisters::STATUS_REG, 0x0000);
        fuelGaugeWrite(Registers::STATUS_REG, 0x0000);
    }

} // namespace bsp

static int battery_fuelGaugeWrite(bsp::batteryChargerRegisters registerAddress, uint16_t value)
{
    I2CAddress addr{.deviceAddress  = BSP_FUEL_GAUGE_I2C_ADDR,
                    .subAddress     = static_cast<uint32_t>(registerAddress),
                    .subAddressSize = i2cSubaddresSize};
    auto ret = i2c->Write(addr, reinterpret_cast<uint8_t *>(&value), sizeof(uint16_t));

    if (ret != sizeof(uint16_t)) {
        return kStatus_Fail;
    }
    else {
        return kStatus_Success;
    }
}

static int battery_fuelGaugeRead(bsp::batteryChargerRegisters registerAddress, uint16_t *value)
{
    if (value == NULL) {
        return -1;
    }

    I2CAddress addr{.deviceAddress  = BSP_FUEL_GAUGE_I2C_ADDR,
                    .subAddress     = static_cast<uint32_t>(registerAddress),
                    .subAddressSize = i2cSubaddresSize};
    auto ret = i2c->Read(addr, reinterpret_cast<uint8_t *>(value), sizeof(uint16_t));

    if (ret != sizeof(uint16_t)) {
        return kStatus_Fail;
    }
    else {
        return kStatus_Success;
    }
}

static int battery_chargerWrite(bsp::batteryChargerRegisters registerAddress, uint8_t value)
{

    I2CAddress addr{.deviceAddress  = BSP_BATTERY_CHARGER_I2C_ADDR,
                    .subAddress     = static_cast<uint32_t>(registerAddress),
                    .subAddressSize = i2cSubaddresSize};
    auto ret = i2c->Write(addr, reinterpret_cast<uint8_t *>(&value), sizeof(uint8_t));

    if (ret != sizeof(uint8_t)) {
        return kStatus_Fail;
    }
    else {
        return kStatus_Success;
    }
}

static int battery_chargerRead(bsp::batteryChargerRegisters registerAddress, uint8_t *value)
{
    if (value == NULL) {
        return -1;
    }

    I2CAddress addr{.deviceAddress  = BSP_BATTERY_CHARGER_I2C_ADDR,
                    .subAddress     = static_cast<uint32_t>(registerAddress),
                    .subAddressSize = i2cSubaddresSize};
    auto ret = i2c->Read(addr, value, sizeof(uint8_t));
    if (ret != sizeof(uint8_t)) {
        return kStatus_Fail;
    }
    else {
        return kStatus_Success;
    }
}

static int battery_chargerTopControllerWrite(bsp::batteryChargerRegisters registerAddress, uint8_t value)
{

    I2CAddress addr{.deviceAddress  = BSP_TOP_CONTROLLER_I2C_ADDR,
                    .subAddress     = static_cast<uint32_t>(registerAddress),
                    .subAddressSize = i2cSubaddresSize};
    auto ret = i2c->Write(addr, reinterpret_cast<uint8_t *>(&value), sizeof(uint8_t));
    if (ret != sizeof(uint8_t)) {
        return kStatus_Fail;
    }
    else {
        return kStatus_Success;
    }
}

static int battery_chargerTopControllerRead(bsp::batteryChargerRegisters registerAddress, uint8_t *value)
{
    if (value == NULL) {
        return -1;
    }

    I2CAddress addr{.deviceAddress  = BSP_TOP_CONTROLLER_I2C_ADDR,
                    .subAddress     = static_cast<uint32_t>(registerAddress),
                    .subAddressSize = i2cSubaddresSize};
    auto ret = i2c->Read(addr, reinterpret_cast<uint8_t *>(value), sizeof(uint8_t));
    if (ret != sizeof(uint8_t)) {
        return kStatus_Fail;
    }
    else {
        return kStatus_Success;
    }
}

static bsp::batteryRetval battery_loadConfiguration(void)
{
    auto fd = std::fopen(configs::battery_cfgFile.c_str(), "r");
    if (fd == NULL) {
        LOG_WARN("Configuration file [%s] not found. Searching for file [%s]",
                 configs::battery_cfgFile.c_str(),
                 configs::battery_cfgFilePrev.c_str());
        fd = std::fopen(configs::battery_cfgFilePrev.c_str(), "r");
        if (fd == NULL) {
            LOG_WARN("Configuration file [%s] not found.", configs::battery_cfgFilePrev.c_str());
            return bsp::batteryRetval::battery_ChargerError;
        }
    }

    uint16_t regValue = 0;
    for (uint8_t i = 0; i < 0xff; ++i) {
        if (std::fread(&regValue, sizeof(regValue), 1, fd) != sizeof(regValue)) {
            LOG_ERROR("Reading register 0x%x failed.", i);
            std::fclose(fd);
            return bsp::batteryRetval::battery_ChargerError;
        }

        if (battery_fuelGaugeWrite(static_cast<bsp::batteryChargerRegisters>(i), regValue) != kStatus_Success) {
            LOG_ERROR("Writing register 0x%x failed.", i);
            std::fclose(fd);
            return bsp::batteryRetval::battery_ChargerError;
    BaseType_t INOKB_IRQHandler()
    {
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
        if (IRQQueueHandle != nullptr) {
            std::uint8_t val = static_cast<std::uint8_t>(batteryIRQSource::INOKB);
            xQueueSendFromISR(IRQQueueHandle, &val, &xHigherPriorityTaskWoken);
        }
        return xHigherPriorityTaskWoken;
    }

    return bsp::batteryRetval::battery_OK;
}

static bsp::batteryRetval battery_storeConfiguration(void)
{
    // TODO:M.P procedure below seems to crash system, it should be fixed.
    if (ff_rename(configs::battery_cfgFile.c_str(), configs::battery_cfgFilePrev.c_str(), false) != 0) {
        LOG_ERROR("Could not move configuration file");
        return bsp::batteryRetval::battery_ChargerError;
    }

    auto fd = std::fopen(configs::battery_cfgFile.c_str(), "w");
    if (fd == NULL) {
        LOG_ERROR("Could not open configuration file");
        return bsp::batteryRetval::battery_ChargerError;
    }

    uint16_t regVal = 0;
    for (unsigned int i = 0; i < 0xff; ++i) {
        if (battery_fuelGaugeRead(static_cast<bsp::batteryChargerRegisters>(i), &regVal) != kStatus_Success) {
            LOG_ERROR("Reading register 0x%x failed.", i);
            std::fclose(fd);
            return bsp::batteryRetval::battery_ChargerError;
        }

        if (std::fwrite(&regVal, sizeof(regVal), 1, fd) != sizeof(regVal)) {
            LOG_ERROR("Storing register 0x%x failed.", i);
            std::fclose(fd);
            std::remove(configs::battery_cfgFile.c_str());
            return bsp::batteryRetval::battery_ChargerError;
    BaseType_t INTB_IRQHandler()
    {
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
        if (IRQQueueHandle != nullptr) {
            std::uint8_t val = static_cast<std::uint8_t>(batteryIRQSource::INTB);
            xQueueSendFromISR(IRQQueueHandle, &val, &xHigherPriorityTaskWoken);
        }
        return xHigherPriorityTaskWoken;
    }
    return bsp::batteryRetval::battery_OK;
}

static bsp::batteryRetval battery_setAvgCalcPeriods(void)
{
    uint16_t regVal = 0;
    regVal |= (BATT_SERVICE_AVG_CURRENT_PERIOD << 0);
    regVal |= (BATT_SERVICE_AVG_CELL_VOLTAGE_PERIOD << 4);
    regVal |= (BATT_SERVICE_AVG_MIXING_PERIOD << 7);
    regVal |= (BATT_SERVICE_AVG_TEMP_PERIOD << 11);
    regVal |= (BATT_SERVICE_AVG_NEMPTY_PERIOD << 14);

    if (battery_fuelGaugeWrite(bsp::batteryChargerRegisters::FilterCFG_REG, regVal) != kStatus_Success) {
        LOG_ERROR("battery_setAvgCalcPeriods failed.");
        return bsp::batteryRetval::battery_ChargerError;
    }
    return bsp::batteryRetval::battery_OK;
}

static bsp::batteryRetval battery_setNominalBatteryCapacity(uint16_t capacity)
{
    uint16_t regVal = capacity * 2;

    if (battery_fuelGaugeWrite(bsp::batteryChargerRegisters::DesignCap_REG, regVal) != kStatus_Success) {
        LOG_ERROR("battery_setNominalBatteryCapacity failed.");
        return bsp::batteryRetval::battery_ChargerError;
    }
    return bsp::batteryRetval::battery_OK;
}

static bsp::batteryRetval battery_setChargingDischargingThresholds(uint8_t chargedThresholdPercent,
                                                                   uint8_t dischargedThresholdPercent)
{
    uint16_t regVal = (chargedThresholdPercent << 8) | dischargedThresholdPercent;

    if (battery_fuelGaugeWrite(bsp::batteryChargerRegisters::SALRT_Th_REG, regVal) != kStatus_Success) {
        LOG_ERROR("battery_setChargingDischargingThresholds failed.");
        return bsp::batteryRetval::battery_ChargerError;
    }
    return bsp::batteryRetval::battery_OK;
}

static bsp::batteryRetval battery_setTemperatureThresholds(uint8_t maxTemperatureDegrees, uint8_t minTemperatureDegrees)
{
    uint16_t regVal = (maxTemperatureDegrees << 8) | minTemperatureDegrees;

    if (battery_fuelGaugeWrite(bsp::batteryChargerRegisters::TALRT_Th_REG, regVal) != kStatus_Success) {
        LOG_ERROR("battery_setTemperatureThresholds failed.");
        return bsp::batteryRetval::battery_ChargerError;
    }
    return bsp::batteryRetval::battery_OK;
}

static bsp::batteryRetval battery_setServiceVoltageThresholds(uint16_t maxVoltage_mV, uint16_t minVoltage_mV)
{
    uint16_t regVal = ((maxVoltage_mV / 20) << 8) | (minVoltage_mV / 20);

    if (battery_fuelGaugeWrite(bsp::batteryChargerRegisters::VALRT_Th_REG, regVal) != kStatus_Success) {

        LOG_ERROR("battery_setServiceVoltageThresholds failed.");
        return bsp::batteryRetval::battery_ChargerError;
    }
    return bsp::batteryRetval::battery_OK;
}

static bsp::batteryRetval battery_enableFuelGuageIRQs(void)
{
    uint16_t regVal = 0;
    // set dSOCen bit
    regVal |= (1 << 7);
    if (battery_fuelGaugeWrite(bsp::batteryChargerRegisters::CONFIG2_REG, regVal) != kStatus_Success) {
        LOG_ERROR("battery_enableFuelGuageIRQs failed.");
        return bsp::batteryRetval::battery_ChargerError;
    }

    return bsp::batteryRetval::battery_OK;
}

static bsp::batteryRetval battery_configureAlerts()
{
    auto regVal = static_cast<std::uint16_t>(bsp::B_CONFIG::Aen); // Enable alerts

    if (battery_fuelGaugeWrite(bsp::batteryChargerRegisters::CONFIG_REG, regVal) != kStatus_Success) {
        LOG_ERROR("battery_configureAlerts failed.");
        return bsp::batteryRetval::battery_ChargerError;
    }

    return bsp::batteryRetval::battery_OK;
}

static bsp::batteryRetval battery_enableTopIRQs(void)
{
    uint8_t val = 0xf8;

    if (battery_chargerTopControllerWrite(bsp::batteryChargerRegisters::TOP_CONTROLL_IRQ_MASK_REG, val) !=
        kStatus_Success) {
        LOG_ERROR("battery_enableIRQs read failed.");
        return bsp::batteryRetval::battery_ChargerError;
    }

    return bsp::batteryRetval::battery_OK;
}

BaseType_t BSP_BatteryChargerINOKB_IRQHandler()
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    if (qHandleIrq != NULL) {
        uint8_t val = static_cast<uint8_t>(bsp::batteryIRQSource::INOKB);
        xQueueSendFromISR(qHandleIrq, &val, &xHigherPriorityTaskWoken);
    }
    return xHigherPriorityTaskWoken;
}

BaseType_t BSP_BatteryChargerINTB_IRQHandler()
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    if (qHandleIrq != NULL) {
        uint8_t val = static_cast<uint8_t>(bsp::batteryIRQSource::INTB);
        xQueueSendFromISR(qHandleIrq, &val, &xHigherPriorityTaskWoken);
    }
    return xHigherPriorityTaskWoken;
}

static void s_BSP_BatteryChargerIrqPinsInit()
{

    gpio = DriverGPIO::Create(static_cast<GPIOInstances>(BoardDefinitions::BATTERY_CHARGER_GPIO), DriverGPIOParams{});

    gpio->ConfPin(DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Input,
                                      .irqMode  = DriverGPIOPinParams::InterruptMode::IntRisingOrFallingEdge,
                                      .defLogic = 0,
                                      .pin      = static_cast<uint32_t>(BoardDefinitions::BATTERY_CHARGER_INOKB_PIN)});

    gpio->ConfPin(DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Input,
                                      .irqMode  = DriverGPIOPinParams::InterruptMode::IntRisingOrFallingEdge,
                                      .defLogic = 0,
                                      .pin      = static_cast<uint32_t>(BoardDefinitions::BATTERY_CHARGER_WCINOKB)});

    gpio->ConfPin(DriverGPIOPinParams{.dir      = DriverGPIOPinParams::Direction::Input,
                                      .irqMode  = DriverGPIOPinParams::InterruptMode::IntFallingEdge,
                                      .defLogic = 0,
                                      .pin      = static_cast<uint32_t>(BoardDefinitions::BATTERY_CHARGER_INTB_PIN)});

    gpio->EnableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::BATTERY_CHARGER_WCINOKB));
    gpio->EnableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::BATTERY_CHARGER_INOKB_PIN));
    gpio->EnableInterrupt(1 << static_cast<uint32_t>(BoardDefinitions::BATTERY_CHARGER_INTB_PIN));
}
} // namespace bsp::battery_charger

M module-bsp/board/rt1051/common/irq/irq_gpio.cpp => module-bsp/board/rt1051/common/irq/irq_gpio.cpp +2 -3
@@ 19,7 19,6 @@
#if 0 // TODO:M.P implement the rest of BSP drivers

#include "bsp_cellular.h"
#include "bsp_battery_charger.h"

#include "bsp_usbc.h"
#include "log.h"


@@ 114,13 113,13 @@ namespace bsp
            }

            if (irq_mask & (1 << BOARD_BATTERY_CHARGER_INOKB_PIN)) {
                xHigherPriorityTaskWoken |= BSP_BatteryChargerINOKB_IRQHandler();
                xHigherPriorityTaskWoken |= bsp::battery_charger::INOKB_IRQHandler();
            }

            if (irq_mask & (1 << BOARD_BATTERY_CHARGER_WCINOKB_PIN)) {}

            if (irq_mask & (1 << BOARD_BATTERY_CHARGER_INTB_PIN)) {
                xHigherPriorityTaskWoken |= BSP_BatteryChargerINTB_IRQHandler();
                xHigherPriorityTaskWoken |= bsp::battery_charger::INTB_IRQHandler();
            }

            if (irq_mask & (1 << BSP_CELLULAR_SIM_TRAY_INSERTED_PIN)) {

M module-bsp/bsp/battery-charger/battery_charger.hpp => module-bsp/bsp/battery-charger/battery_charger.hpp +28 -102
@@ 1,99 1,25 @@
/*
 * battery_charger.hpp
 *
 *  Created on: Jun 28, 2019
 *      Author: kuba
 */
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#ifndef MODULE_BSP_BSP_BATTERY_CHARGER_BATTERY_CHARGER_HPP_
#define MODULE_BSP_BSP_BATTERY_CHARGER_BATTERY_CHARGER_HPP_
#pragma once

#include <cstdint>
namespace bsp{

	enum class batteryChargerRegisters{
		TOP_CONTROLL_PMIC_ID_REG = 0x20,
		TOP_CONTROLL_PMIC_VER_REG = 0x21,
		TOP_CONTROLL_IRQ_SRC_REG = 0x22,
		TOP_CONTROLL_IRQ_MASK_REG = 0x23,
		SYSTEM_IRQ_REG = 0x24,

		STATUS_REG = 0x00,
		VALRT_Th_REG = 0x01,
		TALRT_Th_REG = 0x02,
		SALRT_Th_REG = 0x03,
		AtRate_REG = 0x04,
		RepCap_REG = 0x05,
		RepSOC_REG = 0x06,
		Age_REG = 0x07,
		TEMP_REG = 0x08,
		VCELL_REG = 0x09,
		Current_REG = 0x0A,
		AvgCurrent_REG = 0x0B,
		QResidual_REG = 0x0C,
		MixSOC_REG = 0x0D,
		AvSOC_REG = 0x0E,
		MixCap_REG = 0x0F,

		FullCAP_REG = 0x10,
		TTE_REG = 0x11,
		QRtable00_REG = 0x12,
		FullSOCthr_REG = 0x13,
		RSLOW_REG = 0x14,
		AvgTA_REG = 0x16,
		Cycles_REG = 0x17,
		DesignCap_REG = 0x18,
		AvgVCELL_REG = 0x19,
		MaxMinTemp_REG = 0x1A,
		MaxMinVolt_REG = 0x1B,
		MaxMinCurr_REG = 0x1C,
		CONFIG_REG = 0x1D,
		CONFIG2_REG = 0xBB,
		ICHGTERM_REG = 0x1E,
		AvCap_REG = 0x1F,

		TTF_REG = 0x20,
		DevName_REG = 0x21,
		QRtable10_REG = 0x22,
		FullCAPNom_REG = 0x23,
		TempNom_REG = 0x24,
		TempLim_REG = 0x25,
		AIN0_REG = 0x27,
		LearnCFG_REG = 0x28,
		FilterCFG_REG = 0x29,
		RelaxCFG_REG = 0x2A,
		MiscCFG_REG = 0x2B,
		TGAIN_REG = 0x2C,
		TOFF_REG = 0x2D,
		CGAIN_REG = 0x2E,
		COFF_REG = 0x2F,

		QRtable20_REG = 0x32,
		AtTTF_REG = 0x33,
		FullCapRep_REG = 0x35,
		lavgEmpty_REG = 0x36,
		FCTC_REG = 0x37,
		RCOMP0_REG = 0x38,
		TempCo_REG = 0x39,
		VEmpty_REG = 0x3A,
		TIMER_REG = 0x3E,
		SHDNTIMER_REG = 0x3F,

		QRtable30_REG = 0x42,
		dQ_acc_REG = 0x45,
		dP_acc_REG = 0x46,
		ConvgCfg_REG = 0x49,
		VFRemCap_REG = 0x4A,
		QH_REG = 0x4D,
		CHG_INT_REG = 0xb0,
		CHG_INT_OK = 0xb2
	};
extern "C"
{
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
}

namespace bsp::battery_charger
{
	using StateOfCharge = std::uint8_t;

	enum class batteryRetval{
		battery_OK = 0,
		battery_ChargerError,
		battery_ChargerNotCharging,
		battery_ChargerCharging
		OK,
		ChargerError,
		ChargerNotCharging,
		ChargerCharging
	};

	enum class batteryIRQSource{


@@ 107,24 33,24 @@ namespace bsp{
		SOCOnePercentChange = 1 << 7
	};

	int battery_Init(xQueueHandle qHandle);
	int init(xQueueHandle queueHandle);

	void battery_Deinit(void);
	void deinit();

	void battery_getBatteryLevel(uint8_t& levelPercent);
	StateOfCharge getBatteryLevel();

	void battery_getChargeStatus( bool& status);
	bool getChargeStatus();

	void battery_ClearAllIRQs(void);
	void clearAllIRQs();

	void battery_clearFuelGuageIRQ(void);
	void clearFuelGuageIRQ();

	std::uint16_t battery_getStatusRegister();
}
	std::uint16_t getStatusRegister();

	BaseType_t INOKB_IRQHandler();

BaseType_t BSP_BatteryChargerINOKB_IRQHandler();
	BaseType_t INTB_IRQHandler();
} // bsp::battery_charger

BaseType_t BSP_BatteryChargerINTB_IRQHandler();


#endif /* MODULE_BSP_BSP_BATTERY_CHARGER_BATTERY_CHARGER_HPP_*/

M module-db/Common/Query.cpp => module-db/Common/Query.cpp +1 -1
@@ 21,7 21,7 @@ bool QueryCallback::handleQueryResponse(QueryResult *response)
    return callback(response);
}

EndpointListener::EndpointListener(EndpointQueryCallbackFunction &&_callback, Context &_context)
EndpointListener::EndpointListener(EndpointQueryCallbackFunction &&_callback, parserFSM::Context &_context)
    : callback{std::move(_callback)}, context{_context}
{}


M module-db/Common/Query.hpp => module-db/Common/Query.hpp +3 -5
@@ 9,13 9,11 @@
#include <log/log.hpp>
#include <module-services/service-desktop/endpoints/Context.hpp>

using namespace parserFSM;

namespace db
{
    class QueryResult; // Forward declaration
    using QueryCallbackFunction         = std::function<bool(db::QueryResult *)>;
    using EndpointQueryCallbackFunction = std::function<bool(db::QueryResult *, Context &)>;
    using EndpointQueryCallbackFunction = std::function<bool(db::QueryResult *, parserFSM::Context &)>;

    class QueryListener
    {


@@ 42,13 40,13 @@ namespace db
    {
      public:
        EndpointListener() = default;
        EndpointListener(EndpointQueryCallbackFunction &&_callback, Context &_context);
        EndpointListener(EndpointQueryCallbackFunction &&_callback, parserFSM::Context &_context);

        bool handleQueryResponse(db::QueryResult *result) override;

      private:
        EndpointQueryCallbackFunction callback;
        Context context;
        parserFSM::Context context;
    };

    /// virtual query input interface

M module-db/Interface/AlarmsRecord.hpp => module-db/Interface/AlarmsRecord.hpp +1 -1
@@ 28,7 28,7 @@ namespace db::query::alarms

struct AlarmsRecord : public Record
{
    TimePoint time     = TIME_POINT_INVALID;
    calendar::TimePoint time = TIME_POINT_INVALID;
    uint32_t snooze    = 0;
    AlarmStatus status = AlarmStatus::On;
    uint32_t repeat    = 0;

M module-db/Interface/EventsRecord.cpp => module-db/Interface/EventsRecord.cpp +5 -4
@@ 70,8 70,8 @@ bool EventsRecordInterface::Add(const EventsRecord &rec)
    return false;
}

std::vector<EventsRecord> EventsRecordInterface::Select(TimePoint filter_from,
                                                        TimePoint filter_till,
std::vector<EventsRecord> EventsRecordInterface::Select(calendar::TimePoint filter_from,
                                                        calendar::TimePoint filter_till,
                                                        uint32_t offset,
                                                        uint32_t limit)
{


@@ 265,12 265,13 @@ uint32_t EventsRecordInterface::GetCount()
    return eventsDb->events.count();
}

uint32_t EventsRecordInterface::GetCountFiltered(TimePoint from, TimePoint till)
uint32_t EventsRecordInterface::GetCountFiltered(calendar::TimePoint from, calendar::TimePoint till)
{
    return eventsDb->events.countFromFilter(from, till);
}

std::vector<EventsRecord> EventsRecordInterface::SelectFirstUpcoming(TimePoint filter_from, TimePoint filter_till)
std::vector<EventsRecord> EventsRecordInterface::SelectFirstUpcoming(calendar::TimePoint filter_from,
                                                                     calendar::TimePoint filter_till)
{
    auto rows = eventsDb->events.SelectFirstUpcoming(filter_from, filter_till);


M module-db/Interface/EventsRecord.hpp => module-db/Interface/EventsRecord.hpp +9 -6
@@ 41,11 41,11 @@ struct EventsRecord : public Record
{
    std::string UID;
    std::string title;
    TimePoint date_from;
    TimePoint date_till;
    calendar::TimePoint date_from;
    calendar::TimePoint date_till;
    uint32_t reminder = 0;
    uint32_t repeat   = 0;
    TimePoint reminder_fired;
    calendar::TimePoint reminder_fired;
    std::string provider_type;
    std::string provider_id;
    std::string provider_iCalUid;


@@ 77,15 77,18 @@ class EventsRecordInterface : public RecordInterface<EventsRecord, EventsRecordF
    EventsRecord GetByID(uint32_t id) override final;
    EventsRecord GetByUID(const std::string &uid);
    uint32_t GetCount() override final;
    uint32_t GetCountFiltered(TimePoint from, TimePoint till);
    std::vector<EventsRecord> Select(TimePoint filter_from, TimePoint filter_till, uint32_t offset, uint32_t limit);
    uint32_t GetCountFiltered(calendar::TimePoint from, calendar::TimePoint till);
    std::vector<EventsRecord> Select(calendar::TimePoint filter_from,
                                     calendar::TimePoint filter_till,
                                     uint32_t offset,
                                     uint32_t limit);
    std::unique_ptr<std::vector<EventsRecord>> GetLimitOffset(uint32_t offset, uint32_t limit) override final;
    std::unique_ptr<std::vector<EventsRecord>> GetLimitOffsetByField(uint32_t offset,
                                                                     uint32_t limit,
                                                                     EventsRecordField field,
                                                                     const char *str) override final;
    std::vector<EventsRecord> GetLimitOffsetByDate(uint32_t offset, uint32_t limit);
    std::vector<EventsRecord> SelectFirstUpcoming(TimePoint filter_from, TimePoint filter_till);
    std::vector<EventsRecord> SelectFirstUpcoming(calendar::TimePoint filter_from, calendar::TimePoint filter_till);

    std::unique_ptr<db::QueryResult> runQuery(std::shared_ptr<db::Query> query) override;


M module-db/Tables/AlarmsTable.cpp => module-db/Tables/AlarmsTable.cpp +1 -1
@@ 9,7 9,7 @@ AlarmsTableRow::AlarmsTableRow(const AlarmsRecord &rec)
{}

AlarmsTableRow::AlarmsTableRow(
    uint32_t id, TimePoint time, uint32_t snooze, AlarmStatus status, uint32_t repeat, UTF8 path)
    uint32_t id, calendar::TimePoint time, uint32_t snooze, AlarmStatus status, uint32_t repeat, UTF8 path)
    : Record{id}, time{time}, snooze{snooze}, status{status}, repeat{repeat}, path{std::move(path)}
{}


M module-db/Tables/AlarmsTable.hpp => module-db/Tables/AlarmsTable.hpp +3 -2
@@ 25,14 25,15 @@ enum class AlarmStatus

struct AlarmsTableRow : public Record
{
    TimePoint time     = TIME_POINT_INVALID;
    calendar::TimePoint time = TIME_POINT_INVALID;
    uint32_t snooze    = 0;
    AlarmStatus status = AlarmStatus::On;
    uint32_t repeat    = 0;
    UTF8 path;

    AlarmsTableRow() = default;
    AlarmsTableRow(uint32_t id, TimePoint time, uint32_t snooze, AlarmStatus status, uint32_t repeat, UTF8 path);
    AlarmsTableRow(
        uint32_t id, calendar::TimePoint time, uint32_t snooze, AlarmStatus status, uint32_t repeat, UTF8 path);
    explicit AlarmsTableRow(const AlarmsRecord &rec);
    explicit AlarmsTableRow(const QueryResult &result);
};

M module-db/Tables/EventsTable.cpp => module-db/Tables/EventsTable.cpp +5 -4
@@ 643,8 643,8 @@ EventsTableRow EventsTable::getByUID(const std::string &UID)
    };
}

std::vector<EventsTableRow> EventsTable::selectByDatePeriod(TimePoint date_filter,
                                                            TimePoint filter_till,
std::vector<EventsTableRow> EventsTable::selectByDatePeriod(calendar::TimePoint date_filter,
                                                            calendar::TimePoint filter_till,
                                                            uint32_t offset,
                                                            uint32_t limit)
{


@@ 770,7 770,7 @@ uint32_t EventsTable::count()
    return (*queryRet)[0].getUInt32();
}

uint32_t EventsTable::countFromFilter(TimePoint from, TimePoint till)
uint32_t EventsTable::countFromFilter(calendar::TimePoint from, calendar::TimePoint till)
{
    auto queryRet = db->query(
        "SELECT COUNT(*) FROM events WHERE date_from >= date('%q') AND date_from < date('%q', 'start of day');",


@@ 791,7 791,8 @@ uint32_t EventsTable::countByFieldId(const char *field, uint32_t id)
    return 0;
}

std::vector<EventsTableRow> EventsTable::SelectFirstUpcoming(TimePoint filter_from, TimePoint filter_till)
std::vector<EventsTableRow> EventsTable::SelectFirstUpcoming(calendar::TimePoint filter_from,
                                                             calendar::TimePoint filter_till)
{
    auto retQuery = db->query("SELECT DATETIME(date_from, '-' || reminder || ' minutes') AS calc_dt, * "
                              "FROM events "

M module-db/Tables/EventsTable.hpp => module-db/Tables/EventsTable.hpp +7 -7
@@ 14,11 14,11 @@ struct EventsTableRow : public Record
{
    std::string UID;
    std::string title;
    TimePoint date_from      = TIME_POINT_INVALID;
    TimePoint date_till      = TIME_POINT_INVALID;
    calendar::TimePoint date_from      = TIME_POINT_INVALID;
    calendar::TimePoint date_till      = TIME_POINT_INVALID;
    uint32_t reminder        = 0;
    uint32_t repeat          = 0;
    TimePoint reminder_fired = TIME_POINT_INVALID;
    calendar::TimePoint reminder_fired = TIME_POINT_INVALID;
    std::string provider_type;
    std::string provider_id;
    std::string provider_iCalUid;


@@ 53,12 53,12 @@ class EventsTable : public Table<EventsTableRow, EventsTableFields>
    bool drop();
    EventsTableRow getByUID(const std::string &UID);
    EventsTableRow getById(uint32_t id) override final;
    std::vector<EventsTableRow> selectByDatePeriod(TimePoint filter_from,
                                                   TimePoint filter_till,
    std::vector<EventsTableRow> selectByDatePeriod(calendar::TimePoint filter_from,
                                                   calendar::TimePoint filter_till,
                                                   uint32_t offset,
                                                   uint32_t limit);
    uint32_t count() override final;
    uint32_t countFromFilter(TimePoint from, TimePoint till);
    uint32_t countFromFilter(calendar::TimePoint from, calendar::TimePoint till);
    uint32_t countByFieldId(const char *field, uint32_t id) override final;
    std::vector<EventsTableRow> getLimitOffset(uint32_t offset, uint32_t limit) override final;
    std::vector<EventsTableRow> getLimitOffsetByField(uint32_t offset,


@@ 67,7 67,7 @@ class EventsTable : public Table<EventsTableRow, EventsTableFields>
                                                      const char *str) override final;

    std::vector<EventsTableRow> getLimitOffsetByDate(uint32_t offset, uint32_t limit);
    std::vector<EventsTableRow> SelectFirstUpcoming(TimePoint filter_from, TimePoint filter_till);
    std::vector<EventsTableRow> SelectFirstUpcoming(calendar::TimePoint filter_from, calendar::TimePoint filter_till);

  private:
    const char *createTableQuery = "CREATE TABLE IF NOT EXISTS events("

M module-db/queries/calendar/QueryEventsGetFiltered.cpp => module-db/queries/calendar/QueryEventsGetFiltered.cpp +4 -1
@@ 5,7 5,10 @@

namespace db::query::events
{
    GetFiltered::GetFiltered(TimePoint filter_from, TimePoint filter_till, uint32_t offset, uint32_t limit)
    GetFiltered::GetFiltered(calendar::TimePoint filter_from,
                             calendar::TimePoint filter_till,
                             uint32_t offset,
                             uint32_t limit)
        : Query(Query::Type::Read), filter_from(filter_from), filter_till(filter_till), offset(offset), limit(limit)
    {}


M module-db/queries/calendar/QueryEventsGetFiltered.hpp => module-db/queries/calendar/QueryEventsGetFiltered.hpp +6 -3
@@ 13,11 13,14 @@ namespace db::query::events
    class GetFiltered : public Query
    {
      public:
        GetFiltered(TimePoint filter_from, TimePoint filter_till, uint32_t offset = 0, uint32_t limit = UINT32_MAX);
        GetFiltered(calendar::TimePoint filter_from,
                    calendar::TimePoint filter_till,
                    uint32_t offset = 0,
                    uint32_t limit  = UINT32_MAX);
        [[nodiscard]] auto debugInfo() const -> std::string override;

        TimePoint filter_from;
        TimePoint filter_till;
        calendar::TimePoint filter_from;
        calendar::TimePoint filter_till;
        uint32_t offset;
        uint32_t limit;
    };

M module-db/queries/calendar/QueryEventsSelectFirstUpcoming.cpp => module-db/queries/calendar/QueryEventsSelectFirstUpcoming.cpp +1 -1
@@ 5,7 5,7 @@

namespace db::query::events
{
    SelectFirstUpcoming::SelectFirstUpcoming(TimePoint filter_from, TimePoint filter_till)
    SelectFirstUpcoming::SelectFirstUpcoming(calendar::TimePoint filter_from, calendar::TimePoint filter_till)
        : Query(Query::Type::Read), filter_from(filter_from), filter_till(filter_till)
    {}


M module-db/queries/calendar/QueryEventsSelectFirstUpcoming.hpp => module-db/queries/calendar/QueryEventsSelectFirstUpcoming.hpp +3 -3
@@ 14,11 14,11 @@ namespace db::query::events
    class SelectFirstUpcoming : public Query
    {
      public:
        SelectFirstUpcoming(TimePoint filter_from, TimePoint filter_till);
        SelectFirstUpcoming(calendar::TimePoint filter_from, calendar::TimePoint filter_till);
        [[nodiscard]] auto debugInfo() const -> std::string override;

        TimePoint filter_from;
        TimePoint filter_till;
        calendar::TimePoint filter_from;
        calendar::TimePoint filter_till;
    };

    /// Result of SelectFirstUpcoming query

M module-db/tests/AlarmsRecord_tests.cpp => module-db/tests/AlarmsRecord_tests.cpp +1 -1
@@ 184,7 184,7 @@ TEST_CASE("Alarms Record tests")
    }

    auto getQuery = [&](uint32_t id,
                        TimePoint alarmTime,
                        calendar::TimePoint alarmTime,
                        uint32_t snooze,
                        AlarmStatus status,
                        uint32_t repeat,

M module-db/tests/AlarmsTable_tests.cpp => module-db/tests/AlarmsTable_tests.cpp +5 -5
@@ 139,11 139,11 @@ TEST_CASE("Alarms Table tests")
        REQUIRE(alarmsTbl.add(
            AlarmsTableRow(5, TimePointFromString("2020-12-11 07:15:00"), 1, AlarmStatus::On, 1, "file2.mp3")));

        const std::array<TimePoint, 5> paramTime{TimePointFromString("2020-12-11 07:15:00"),
                                                 TimePointFromString("2020-11-11 15:10:00"),
                                                 TimePointFromString("2020-11-11 15:15:00"),
                                                 TimePointFromString("2020-11-12 17:10:00"),
                                                 TimePointFromString("2020-11-11 19:25:00")};
        const std::array<calendar::TimePoint, 5> paramTime{TimePointFromString("2020-12-11 07:15:00"),
                                                           TimePointFromString("2020-11-11 15:10:00"),
                                                           TimePointFromString("2020-11-11 15:15:00"),
                                                           TimePointFromString("2020-11-12 17:10:00"),
                                                           TimePointFromString("2020-11-11 19:25:00")};

        REQUIRE(alarmsTbl.count() == 5);
        auto entries   = alarmsTbl.getLimitOffset(0, 5);

M module-db/tests/EventsRecord_tests.cpp => module-db/tests/EventsRecord_tests.cpp +8 -3
@@ 24,6 24,8 @@
#include <algorithm>
#include <iostream>

using namespace std::chrono_literals;

static auto remove_events(EventsDB &db) -> bool
{
    auto count   = db.events.count();


@@ 728,7 730,7 @@ TEST_CASE("Events Record tests")

    SECTION("Select first upcoming event")
    {
        TimePoint start_date = TimePointFromString("2019-10-19 14:24:00");
        calendar::TimePoint start_date = TimePointFromString("2019-10-19 14:24:00");
        auto nextUpcoming    = eventsRecordInterface.SelectFirstUpcoming(start_date, start_date);
        REQUIRE(nextUpcoming.size() == 1);
        EventsRecord nextEventsRecord = nextUpcoming.at(0);


@@ 797,7 799,9 @@ TEST_CASE("Events Record tests")
        getAll(expectedRecords, numberOfEvents);
    }

    auto getFiltered = [&](TimePoint filter_from, TimePoint filter_till, std::vector<EventsRecord> expected_records) {
    auto getFiltered = [&](calendar::TimePoint filter_from,
                           calendar::TimePoint filter_till,
                           std::vector<EventsRecord> expected_records) {
        auto query  = std::make_shared<db::query::events::GetFiltered>(filter_from, filter_till);
        auto ret    = eventsRecordInterface.runQuery(query);
        auto result = dynamic_cast<db::query::events::GetFilteredResult *>(ret.get());


@@ 1009,7 1013,8 @@ TEST_CASE("Events Record tests")
        EditQueryICS(testRecord6.UID, testRecord6);
    }

    [[maybe_unused]] auto selectFirstUpcomingEvent = [&](TimePoint filter_from, TimePoint filter_till) {
    [[maybe_unused]] auto selectFirstUpcomingEvent = [&](calendar::TimePoint filter_from,
                                                         calendar::TimePoint filter_till) {
        auto query  = std::make_shared<db::query::events::SelectFirstUpcoming>(filter_from, filter_till);
        auto ret    = eventsRecordInterface.runQuery(query);
        auto result = dynamic_cast<db::query::events::SelectFirstUpcomingResult *>(ret.get());

M module-db/tests/EventsTable_tests.cpp => module-db/tests/EventsTable_tests.cpp +39 -37
@@ 15,6 15,8 @@
#include <purefs/filesystem_paths.hpp>
#include <unistd.h>

using namespace std::chrono_literals;

static auto remove_events(EventsDB &db) -> bool
{
    auto count   = db.events.count();


@@ 164,8 166,8 @@ TEST_CASE("Events Table tests")
        CHECK(eventsTbl.count() == 0);

        uint32_t numberOfEvents = 7;
        TimePoint startDate     = TimePointFromString("2019-10-20 14:30:00");
        TimePoint endDate       = TimePointFromString("2019-10-20 15:30:00");
        calendar::TimePoint startDate = TimePointFromString("2019-10-20 14:30:00");
        calendar::TimePoint endDate   = TimePointFromString("2019-10-20 15:30:00");
        testRow1.date_from      = startDate;
        testRow1.date_till      = endDate;
        CHECK(eventsTbl.addDaily(testRow1));


@@ 199,8 201,8 @@ TEST_CASE("Events Table tests")
        CHECK(eventsTbl.count() == 0);

        uint32_t numberOfEvents = 4;
        TimePoint startDate     = TimePointFromString("2019-10-20 14:30:00");
        TimePoint endDate       = TimePointFromString("2019-10-20 15:30:00");
        calendar::TimePoint startDate = TimePointFromString("2019-10-20 14:30:00");
        calendar::TimePoint endDate   = TimePointFromString("2019-10-20 15:30:00");
        testRow1.date_from      = startDate;
        testRow1.date_till      = endDate;
        CHECK(eventsTbl.addWeekly(testRow1));


@@ 234,8 236,8 @@ TEST_CASE("Events Table tests")
        CHECK(eventsTbl.count() == 0);

        uint32_t numberOfEvents = 4;
        TimePoint startDate     = TimePointFromString("2019-10-20 14:30:00");
        TimePoint endDate       = TimePointFromString("2019-10-20 15:30:00");
        calendar::TimePoint startDate = TimePointFromString("2019-10-20 14:30:00");
        calendar::TimePoint endDate   = TimePointFromString("2019-10-20 15:30:00");
        testRow1.date_from      = startDate;
        testRow1.date_till      = endDate;
        CHECK(eventsTbl.addTwoWeeks(testRow1));


@@ 269,7 271,7 @@ TEST_CASE("Events Table tests")
        CHECK(eventsTbl.count() == 0);

        uint32_t numberOfEvents = 12;
        const std::array<TimePoint, 24> dates{
        const std::array<calendar::TimePoint, 24> dates{
            TimePointFromString("2019-01-20 14:30:00"), TimePointFromString("2019-01-20 15:30:00"),
            TimePointFromString("2019-02-20 14:30:00"), TimePointFromString("2019-02-20 15:30:00"),
            TimePointFromString("2019-03-20 14:30:00"), TimePointFromString("2019-03-20 15:30:00"),


@@ 316,14 318,14 @@ TEST_CASE("Events Table tests")
        REQUIRE(eventsTbl.count() == 0);

        uint32_t numberOfEvents = 4;
        std::array<TimePoint, 8> dates{TimePointFromString("2019-02-20 14:30:00"),
                                       TimePointFromString("2019-02-20 15:30:00"),
                                       TimePointFromString("2020-02-20 14:30:00"),
                                       TimePointFromString("2020-02-20 15:30:00"),
                                       TimePointFromString("2021-02-20 14:30:00"),
                                       TimePointFromString("2021-02-20 15:30:00"),
                                       TimePointFromString("2022-02-20 14:30:00"),
                                       TimePointFromString("2022-02-20 15:30:00")};
        std::array<calendar::TimePoint, 8> dates{TimePointFromString("2019-02-20 14:30:00"),
                                                 TimePointFromString("2019-02-20 15:30:00"),
                                                 TimePointFromString("2020-02-20 14:30:00"),
                                                 TimePointFromString("2020-02-20 15:30:00"),
                                                 TimePointFromString("2021-02-20 14:30:00"),
                                                 TimePointFromString("2021-02-20 15:30:00"),
                                                 TimePointFromString("2022-02-20 14:30:00"),
                                                 TimePointFromString("2022-02-20 15:30:00")};

        testRow1.date_from = dates[0];
        testRow1.date_till = dates[1];


@@ 365,8 367,8 @@ TEST_CASE("Events Table tests")
    {
        auto check_custom_repeat = [&](uint32_t customRepeatOption,
                                       uint32_t numberOfEvents,
                                       TimePoint originalStartDate,
                                       TimePoint originalEndDate) {
                                       calendar::TimePoint originalStartDate,
                                       calendar::TimePoint originalEndDate) {
            if (eventsTbl.count() > 0) {
                REQUIRE(remove_events(eventsDb));
            }


@@ 394,8 396,8 @@ TEST_CASE("Events Table tests")
                }
            }

            TimePoint expectedStartDate = TimePointFromString("2020-12-07 14:30:00"); // monday
            TimePoint expectedEndDate   = TimePointFromString("2020-12-07 15:30:00"); // monday
            calendar::TimePoint expectedStartDate = TimePointFromString("2020-12-07 14:30:00"); // monday
            calendar::TimePoint expectedEndDate   = TimePointFromString("2020-12-07 15:30:00"); // monday

            uint32_t i = 0;
            for (uint32_t l = 0; l < numberOfWeeks; l++) {


@@ 437,8 439,8 @@ TEST_CASE("Events Table tests")
            uint32_t customRepeatOption =
                static_cast<uint32_t>(weekDayOption::monday) + static_cast<uint32_t>(weekDayOption::wednesday);
            uint32_t numberOfEvents     = 9;
            TimePoint originalStartDate = TimePointFromString("2020-12-10 14:30:00"); // thursday
            TimePoint originalEndDate   = TimePointFromString("2020-12-10 15:30:00"); // thursday
            calendar::TimePoint originalStartDate = TimePointFromString("2020-12-10 14:30:00"); // thursday
            calendar::TimePoint originalEndDate   = TimePointFromString("2020-12-10 15:30:00"); // thursday

            check_custom_repeat(customRepeatOption, numberOfEvents, originalStartDate, originalEndDate);
        }


@@ 449,8 451,8 @@ TEST_CASE("Events Table tests")
                static_cast<uint32_t>(weekDayOption::monday) + static_cast<uint32_t>(weekDayOption::wednesday) +
                static_cast<uint32_t>(weekDayOption::tuesday) + static_cast<uint32_t>(weekDayOption::sunday);
            uint32_t numberOfEvents     = 17;
            TimePoint originalStartDate = TimePointFromString("2020-12-10 14:30:00"); // thursday
            TimePoint originalEndDate   = TimePointFromString("2020-12-10 15:30:00"); // thursday
            calendar::TimePoint originalStartDate = TimePointFromString("2020-12-10 14:30:00"); // thursday
            calendar::TimePoint originalEndDate   = TimePointFromString("2020-12-10 15:30:00"); // thursday

            check_custom_repeat(customRepeatOption, numberOfEvents, originalStartDate, originalEndDate);
        }


@@ 459,8 461,8 @@ TEST_CASE("Events Table tests")
        {
            uint32_t customRepeatOption = static_cast<uint32_t>(weekDayOption::saturday);
            uint32_t numberOfEvents     = 5;
            TimePoint originalStartDate = TimePointFromString("2020-12-10 14:30:00"); // thursday
            TimePoint originalEndDate   = TimePointFromString("2020-12-10 15:30:00"); // thursday
            calendar::TimePoint originalStartDate = TimePointFromString("2020-12-10 14:30:00"); // thursday
            calendar::TimePoint originalEndDate   = TimePointFromString("2020-12-10 15:30:00"); // thursday

            check_custom_repeat(customRepeatOption, numberOfEvents, originalStartDate, originalEndDate);
        }


@@ 468,8 470,8 @@ TEST_CASE("Events Table tests")

    SECTION("Check count from filter")
    {
        TimePoint from = TimePointFromString("2019-10-20 14:30:00");
        TimePoint till = TimePointFromString("2019-10-24 14:20:00");
        calendar::TimePoint from = TimePointFromString("2019-10-20 14:30:00");
        calendar::TimePoint till = TimePointFromString("2019-10-24 14:20:00");

        CHECK(eventsTbl.countFromFilter(from, till) == 4);
    }


@@ 514,8 516,8 @@ TEST_CASE("Events Table tests")
        CHECK(eventsTbl.count() == 6);

        std::string newTitle = "Updated Title", newProviderID = "PurePhoneUpdated";
        TimePoint newDateFrom    = TimePointFromString("2020-10-20 15:00:00"),
                  newDateTill    = TimePointFromString("2020-10-20 16:00:00");
        calendar::TimePoint newDateFrom = TimePointFromString("2020-10-20 15:00:00"),
                            newDateTill = TimePointFromString("2020-10-20 16:00:00");
        uint32_t newReminder     = static_cast<uint32_t>(Reminder::one_week_before);
        uint32_t newRepeatOption = static_cast<uint32_t>(Repeat::biweekly);



@@ 570,8 572,8 @@ TEST_CASE("Events Table tests")

        std::string newTitle = "Updated Title", newProviderType = "PurePhoneUpdate", newProviderID = "newID",
                    newProvideriCalUid = "new iCalUid";
        TimePoint newDateFrom          = TimePointFromString("2020-10-20 15:00:00"),
                  newDateTill          = TimePointFromString("2020-10-20 16:00:00");
        calendar::TimePoint newDateFrom = TimePointFromString("2020-10-20 15:00:00"),
                            newDateTill = TimePointFromString("2020-10-20 16:00:00");
        uint32_t newReminder           = static_cast<uint32_t>(Reminder::one_week_before);
        uint32_t newRepeatOption       = static_cast<uint32_t>(Repeat::biweekly);



@@ 628,8 630,8 @@ TEST_CASE("Events Table tests")

        std::string newTitle = "Updated Title", newProviderType = "PurePhoneUpdate", newProviderID = "newID",
                    newProvideriCalUid = "new iCalUid";
        TimePoint newDateFrom          = TimePointFromString("2020-10-20 15:00:00"),
                  newDateTill          = TimePointFromString("2020-10-20 16:00:00");
        calendar::TimePoint newDateFrom = TimePointFromString("2020-10-20 15:00:00"),
                            newDateTill = TimePointFromString("2020-10-20 16:00:00");
        uint32_t newReminder           = static_cast<uint32_t>(Reminder::one_week_before);
        uint32_t newRepeatOption       = static_cast<uint32_t>(Repeat::biweekly);



@@ 727,11 729,11 @@ TEST_CASE("Events Table tests")
        }
        CHECK(eventsTbl.count() == 0);

        TimePoint startDate1 = TimePointFromString("2018-10-20 14:24:00");
        TimePoint startDate2 = TimePointFromString("2020-10-20 14:24:00");
        calendar::TimePoint startDate1 = TimePointFromString("2018-10-20 14:24:00");
        calendar::TimePoint startDate2 = TimePointFromString("2020-10-20 14:24:00");

        TimePoint tillDate  = TimePointFromString("2030-10-20 15:24:00");
        TimePoint firedDate = TimePointFromString("2018-10-20 14:24:00");
        calendar::TimePoint tillDate  = TimePointFromString("2030-10-20 15:24:00");
        calendar::TimePoint firedDate = TimePointFromString("2018-10-20 14:24:00");

        EventsTableRow testEvent1 = {{1},
                                     .UID              = "test1",

M module-db/tests/QueryInterface.cpp => module-db/tests/QueryInterface.cpp +2 -2
@@ 75,9 75,9 @@ TEST_CASE("Query interface")
        auto msgJson = json11::Json::parse(testMessage, err);
        REQUIRE(err.empty());

        Context context(msgJson);
        parserFSM::Context context(msgJson);
        auto listener = std::make_unique<db::EndpointListener>(
            [=](db::QueryResult *result, Context &context) {
            [=](db::QueryResult *result, parserFSM::Context &context) {
                if (auto SMSResult = dynamic_cast<db::query::SMSGetCountResult *>(result)) {
                    auto id   = SMSResult->getResults();
                    auto body = json11::Json::object{{"count", static_cast<int>(id)}};

M module-gui/gui/dom/Item2JsonSerializingVisitor.cpp => module-gui/gui/dom/Item2JsonSerializingVisitor.cpp +1 -1
@@ 85,7 85,7 @@ void Item2JsonSerializingVisitor::visit(gui::BottomBar &item)
    visit(static_cast<gui::Item &>(item));
}

void Item2JsonSerializingVisitor::visit(gui::TopBar &item)
void Item2JsonSerializingVisitor::visit(gui::top_bar::TopBar &item)
{
    if (itemName.empty()) {
        itemName = magic_enum::enum_name(visitor::Names::TopBar);

M module-gui/gui/dom/Item2JsonSerializingVisitor.hpp => module-gui/gui/dom/Item2JsonSerializingVisitor.hpp +1 -1
@@ 29,7 29,7 @@ namespace gui
        void visit(gui::Window &item) override;
        void visit(gui::Label &item) override;
        void visit(gui::BottomBar &item) override;
        void visit(gui::TopBar &item) override;
        void visit(gui::top_bar::TopBar &item) override;

      public:
        /// retrieves current state of the `sink`. The state of the `sink` after call is default-initialized

M module-gui/gui/widgets/BoxLayout.cpp => module-gui/gui/widgets/BoxLayout.cpp +6 -6
@@ 110,7 110,7 @@ namespace gui
                /// this if back / front is crappy :|
                if (previous) {
                    for (auto el = children.rbegin(); el != children.rend(); ++el) {
                        if ((*el)->visible && (*el)->activeItem) {
                        if ((*el)->isActive()) {
                            setFocusItem(*el);
                            break;
                        }


@@ 118,7 118,7 @@ namespace gui
                }
                else {
                    for (auto &el : children) {
                        if (el->visible && el->activeItem) {
                        if (el->isActive()) {
                            setFocusItem(el);
                            break;
                        }


@@ 375,7 375,7 @@ namespace gui
    std::list<Item *>::iterator BoxLayout::nextNavigationItem(std::list<Item *>::iterator from)
    {
        return std::find_if(from, this->children.end(), [](auto &el) -> bool {
            if (el->visible && el->activeItem) {
            if (el->isActive()) {
                return true;
            }
            return false;


@@ 474,7 474,7 @@ namespace gui
        bool success   = false;

        for (auto child : children) {
            if (child->activeItem && child->visible) {
            if (child->isActive()) {

                if (elementNumber == i) {
                    child->setFocus(true);


@@ 496,7 496,7 @@ namespace gui
        auto last = true;
        for (auto child = children.rbegin(); child != children.rend(); child++) {

            if ((*child)->activeItem && (*child)->visible && last) {
            if ((*child)->isActive() && last) {
                (*child)->setFocus(true);
                focusItem = (*child);
                last      = false;


@@ 516,7 516,7 @@ namespace gui
            if (child == focusItem) {
                break;
            }
            if (child->activeItem && child->visible) {
            if (child->isActive()) {
                index++;
            }
        }

M module-gui/gui/widgets/GridLayout.cpp => module-gui/gui/widgets/GridLayout.cpp +44 -47
@@ 22,25 22,34 @@ GridLayout::GridLayout(

        auto it       = this->getNavigationFocusedItem();
        auto distance = std::distance(children.begin(), it);

        switch (inputEvent.keyCode) {
        case KeyCode::KEY_UP: {
            auto realRowSize = calculateRowSizeForBorderTransition(distance);
            this->setFocusItem((*std::next(it, (realRowSize - 1) * this->colSize)));
            auto col   = static_cast<uint32_t>(distance % colSize);
            Item *item = getFirstActiveItem(getLastColumnIndex(col), (-1) * static_cast<int>(colSize));
            if (item)
                this->setFocusItem(item);
            return true;
        }
        case KeyCode::KEY_DOWN: {
            auto realRowSize = calculateRowSizeForBorderTransition(distance);
            this->setFocusItem((*std::prev(it, (realRowSize - 1) * this->colSize)));
            auto col   = static_cast<uint32_t>(distance % colSize);
            Item *item = getFirstActiveItem(col, static_cast<int>(colSize));
            if (item)
                this->setFocusItem(item);
            return true;
        }
        case KeyCode::KEY_LEFT: {
            auto realColSize = calculateColumnSizeForBorderTransition(distance);
            this->setFocusItem((*std::next(it, realColSize - 1)));
            auto row   = static_cast<uint32_t>(distance / colSize);
            Item *item = getFirstActiveItem(getLastRowIndex(row), -1);
            if (item)
                this->setFocusItem(item);
            return true;
        }
        case KeyCode::KEY_RIGHT: {
            auto realColSize = calculateColumnSizeForBorderTransition(distance);
            this->setFocusItem((*std::prev(it, realColSize - 1)));
            auto row   = static_cast<uint32_t>(distance / colSize);
            Item *item = getFirstActiveItem(colSize * row, 1);
            if (item)
                this->setFocusItem(item);
            return true;
        }
        default: {


@@ 50,25 59,6 @@ GridLayout::GridLayout(
    };
}

uint32_t GridLayout::calculateColumnSizeForBorderTransition(const uint32_t currentPosition)
{
    auto realColSize = colSize;
    if (elementsInIncompletedLastRow) {
        if (((currentPosition / colSize) + 1) >= rowSize)
            realColSize = elementsInIncompletedLastRow;
    }
    return realColSize;
}
uint32_t GridLayout::calculateRowSizeForBorderTransition(const uint32_t currentPosition)
{
    auto realRowSize = rowSize;
    if (elementsInIncompletedLastRow) {
        if (((currentPosition % (colSize)) + 1) > elementsInIncompletedLastRow)
            realRowSize--;
    }
    return realRowSize;
}

void GridLayout::handleItemsOutOfGridLayoutArea(uint32_t maxItemsInArea)
{
    for (auto i = maxItemsInArea; i < children.size(); i++) {


@@ 88,16 78,6 @@ void GridLayout::resizeItems()
    uint32_t el_in_x = area().w / grid.x;
    uint32_t el_in_y = area().h / grid.y;

    elementsInIncompletedLastRow = 0;
    colSize = children.size() < area().w / grid.x ? children.size() : area().w / grid.x;
    rowSize = colSize != 0 ? (children.size() / colSize) : 1;
    if (colSize > 1 && (static_cast<double>(children.size()) / colSize) > 1.0) {
        elementsInIncompletedLastRow = children.size() % colSize;
    }
    if (elementsInIncompletedLastRow > 0) {
        rowSize++;
    }

    uint32_t strech_x     = 0;
    uint32_t strech_y     = 0;
    uint32_t max_elements = el_in_x * el_in_y;


@@ 113,6 93,13 @@ void GridLayout::resizeItems()
        handleItemsOutOfGridLayoutArea(max_elements);
        return;
    }

    colSize = children.size() < area().w / grid.x ? children.size() : area().w / grid.x;
    rowSize = colSize != 0 ? (children.size() / colSize) : 1;
    if (colSize > 1 && (static_cast<double>(children.size()) / colSize) > 1.0 && (children.size() % colSize)) {
        rowSize++;
    }

    if (el_in_x > 2)
        strech_x = (area().w - grid.x * el_in_x) / (el_in_x - 1);
    if (el_in_y > 2)


@@ 149,28 136,38 @@ void GridLayout::setNavigation()
    for (auto it = children.begin(); it != children.end(); ++it, ++i) {

        if (it != children.begin() && (i + 1) % colSize != 1) {
            (*it)->setNavigationItem(NavigationDirection::LEFT, nextNavigationItem(std::prev(it)));
            (*it)->setNavigationItem(NavigationDirection::LEFT, getFirstActiveItem(i - 1, -1));
        }

        if (it != std::prev(children.end()) && (i + 1) % colSize != 0) {
            (*it)->setNavigationItem(NavigationDirection::RIGHT, nextNavigationItem(std::next(it)));
            (*it)->setNavigationItem(NavigationDirection::RIGHT, getFirstActiveItem(i + 1, 1));
        }

        if ((i - offset) >= 0) {
            (*it)->setNavigationItem(NavigationDirection::UP, nextNavigationItem(std::prev(it, offset)));
            (*it)->setNavigationItem(NavigationDirection::UP, getFirstActiveItem(i - offset, (-1) * offset));
        }
        if ((i + offset) < static_cast<int>(children.size())) {
            (*it)->setNavigationItem(NavigationDirection::DOWN, nextNavigationItem(std::next(it, offset)));
            (*it)->setNavigationItem(NavigationDirection::DOWN, getFirstActiveItem(i + offset, offset));
        }
    }
}

Item *GridLayout::nextNavigationItem(std::list<Item *>::iterator it)
Item *GridLayout::getFirstActiveItem(uint32_t startposition, int step)
{
    if (it != this->children.end() && (*it)->visible && (*it)->activeItem) {
        return *it;
    }
    else {
        return nullptr;
    Item *retItem = nullptr;
    int index     = static_cast<int>(startposition);
    uint32_t row  = startposition / colSize;
    while (index >= 0 && index < static_cast<int>(children.size())) {
        ///> condition for movement along row (+1,-1 step)
        if ((step == 1 || step == -1) && (index / colSize != row)) {
            break;
        }
        std::list<Item *>::iterator tmpit = std::next(children.begin(), index);
        if ((*tmpit)->isActive()) {
            retItem = *tmpit;
            break;
        }
        index += step;
    }
    return retItem;
}

M module-gui/gui/widgets/GridLayout.hpp => module-gui/gui/widgets/GridLayout.hpp +15 -9
@@ 26,23 26,29 @@ namespace gui
        {}
        GridLayout() : GridLayout(0, 0, 0, 0, {0, 0})
        {}
        /// when reached top -> start from bottom. When reached left, start from right.
        bool navigationRotate = true;
        void resizeItems() override;
        void setNavigation() override;
        Item *nextNavigationItem(std::list<Item *>::iterator it);

        uint32_t rowSize = 0;
        uint32_t colSize = 0;
        ///> elementsInIncompletedLastRow describes how many items has been put to last row,
        /// in case when items for last row is not equal to colSize
        uint32_t elementsInIncompletedLastRow = 0;

      private:
        uint32_t calculateColumnSizeForBorderTransition(const uint32_t currentPosition);
        uint32_t calculateRowSizeForBorderTransition(const uint32_t currentPosition);

        void handleItemsOutOfGridLayoutArea(uint32_t maxItemsInArea);
        Item *getFirstActiveItem(uint32_t startposition, int step);
        inline uint32_t getLastColumnIndex(uint32_t col)
        {
            auto lastcolumnindex = col;
            while ((lastcolumnindex + colSize) < children.size())
                lastcolumnindex += colSize;
            return lastcolumnindex;
        }
        inline uint32_t getLastRowIndex(uint32_t row)
        {
            uint32_t lastrowindex = colSize * row + (colSize - 1);
            while (lastrowindex >= children.size())
                lastrowindex--;
            return lastrowindex;
        }
    };

}; // namespace gui

M module-gui/gui/widgets/Item.hpp => module-gui/gui/widgets/Item.hpp +5 -0
@@ 344,6 344,11 @@ namespace gui
        /// remove timer from item and as a result - destory it
        void detachTimer(Timer &timer);

        /// simple check function to determine if item is active && visible
        inline bool isActive()
        {
            return (activeItem && visible);
        }
        virtual void accept(GuiVisitor &visitor);

      protected:

M module-gui/gui/widgets/ProgressBar.cpp => module-gui/gui/widgets/ProgressBar.cpp +8 -6
@@ 35,14 35,15 @@ namespace gui
        }
    }

    void ProgressBar::setValue(unsigned int value) noexcept
    bool ProgressBar::setValue(unsigned int value) noexcept
    {
        currentValue = std::clamp(value, 0U, maxValue);
        return currentValue == value;
    }

    void ProgressBar::update(int value) noexcept
    bool ProgressBar::update(int value) noexcept
    {
        setValue(currentValue + value);
        return setValue(currentValue + value);
    }

    void ProgressBar::setPercentageValue(unsigned int value) noexcept


@@ 110,14 111,15 @@ namespace gui
        }
    }

    void CircularProgressBar::setValue(unsigned int value) noexcept
    bool CircularProgressBar::setValue(unsigned int value) noexcept
    {
        currentValue = std::clamp(value, 0U, maxValue);
        return value == currentValue;
    }

    void CircularProgressBar::update(int value) noexcept
    bool CircularProgressBar::update(int value) noexcept
    {
        setValue(currentValue + value);
        return setValue(currentValue + value);
    }

    void CircularProgressBar::setPercentageValue(unsigned int value) noexcept

M module-gui/gui/widgets/ProgressBar.hpp => module-gui/gui/widgets/ProgressBar.hpp +6 -6
@@ 17,8 17,8 @@ namespace gui
        virtual ~Progress() noexcept = default;

        virtual void setMaximum(unsigned int value)         = 0;
        virtual void setValue(unsigned int value)           = 0;
        virtual void update(int value = 1)                  = 0;
        virtual auto setValue(unsigned int value) -> bool   = 0;
        virtual auto update(int value = 1) -> bool          = 0;
        virtual void setPercentageValue(unsigned int value) = 0;
    };



@@ 28,8 28,8 @@ namespace gui
        ProgressBar(Item *parent, std::uint32_t x, std::uint32_t y, std::uint32_t w, std::uint32_t h);

        void setMaximum(unsigned int value) noexcept override;
        void setValue(unsigned int value) noexcept override;
        void update(int value = 1) noexcept override;
        auto setValue(unsigned int value) noexcept -> bool override;
        auto update(int value = 1) noexcept -> bool override;
        void setPercentageValue(unsigned int value) noexcept override;

        void buildDrawListImplementation(std::list<Command> &commands) override;


@@ 49,8 49,8 @@ namespace gui
        CircularProgressBar(Item *parent, const Circle::ShapeParams &shape);

        void setMaximum(unsigned int value) noexcept override;
        void setValue(unsigned int value) noexcept override;
        void update(int value = 1) noexcept override;
        auto setValue(unsigned int value) noexcept -> bool override;
        auto update(int value = 1) noexcept -> bool override;
        void setPercentageValue(unsigned int value) noexcept override;

        void buildDrawListImplementation(std::list<Command> &commands) override;

M module-gui/gui/widgets/Style.hpp => module-gui/gui/widgets/Style.hpp +1 -0
@@ 138,6 138,7 @@ namespace style
            inline constexpr auto set            = "common_set";
            inline constexpr auto yes            = "common_yes";
            inline constexpr auto no             = "common_no";
            inline constexpr auto check          = "common_check";
            inline constexpr auto Switch         = "common_switch";
            inline constexpr auto options        = "common_options";
            inline constexpr auto information    = "common_information";

M module-gui/gui/widgets/TopBar.cpp => module-gui/gui/widgets/TopBar.cpp +90 -46
@@ 11,7 11,7 @@

#include "common_data/EventStore.hpp"

namespace gui
namespace gui::top_bar
{
    namespace networkTechnology
    {


@@ 20,14 20,47 @@ namespace gui
        constexpr uint32_t w = 130;
        constexpr uint32_t h = 20;
    } // namespace networkTechnology
    const uint32_t TopBar::signalOffset    = 35;
    const uint32_t TopBar::batteryOffset   = 413;
    gui::TopBar::TimeMode TopBar::timeMode = TimeMode::TIME_24H;

    static constexpr uint32_t signalOffset  = 35;
    static constexpr uint32_t batteryOffset = 413;

    TopBar::TimeMode TopBar::timeMode      = TimeMode::TIME_24H;
    uint32_t TopBar::time                  = 0;

    TopBar::TopBar(Item *parent, uint32_t x, uint32_t y, uint32_t w, uint32_t h) : Rect{parent, x, y, w, h}
    void Configuration::enable(Indicator indicator)
    {
        set(indicator, true);
    }

    void Configuration::enable(const Indicators &indicators)
    {
        for (auto indicator : indicators) {
            enable(indicator);
        }
    }

    void Configuration::disable(Indicator indicator)
    {
        set(indicator, false);
    }

    void Configuration::set(Indicator indicator, bool enabled)
    {
        indicatorStatuses[indicator] = enabled;
    }

    auto Configuration::isEnabled(Indicator indicator) const -> bool
    {
        return indicatorStatuses.at(indicator);
    }

    auto Configuration::getIndicatorsConfiguration() const noexcept -> const IndicatorStatuses &
    {
        return indicatorStatuses;
    }

    TopBar::TopBar(Item *parent, uint32_t x, uint32_t y, uint32_t w, uint32_t h) : Rect{parent, x, y, w, h}
    {
        prepareWidget();

        setFillColor(ColorFullWhite);


@@ 48,7 81,7 @@ namespace gui
            val = batteryBars.size();
        }
        for (unsigned int i = 0; i < batteryBars.size(); ++i) {
            if (elements.battery) {
            if (configuration.isEnabled(Indicator::Battery)) {
                batteryBars[i]->setVisible(i == val);
            }
            else {


@@ 59,7 92,6 @@ namespace gui

    void TopBar::prepareWidget()
    {

        signal[0] = new gui::Image(this, signalOffset, 17, 0, 0, "signal0");
        signal[1] = new gui::Image(this, signalOffset, 17, 0, 0, "signal1");
        signal[2] = new gui::Image(this, signalOffset, 17, 0, 0, "signal2");


@@ 111,48 143,56 @@ namespace gui
        updateNetworkAccessTechnology();
    }

    void TopBar::setActive(std::list<std::pair<TopBar::Elements, bool>> elements)
    auto TopBar::getConfiguration() const noexcept -> const Configuration &
    {
        return configuration;
    }

    void TopBar::configure(Configuration &&config)
    {
        for (auto el : elements) {
            setActive(el.first, el.second);
        if (config.isEnabled(Indicator::Lock)) {
            // In current implementation, lock and time indicators are mutually exclusive.
            // I.e. enabling the lock indicator disables the time indicator.
            config.disable(Indicator::Time);
        }

        for (auto [indicator, enabled] : config.getIndicatorsConfiguration()) {
            setIndicatorStatus(indicator, enabled);
        }
        configuration = std::move(config);
    }

    void TopBar::setActive(TopBar::Elements element, bool active)
    void TopBar::setIndicatorStatus(Indicator indicator, bool enabled)
    {
        switch (element) {
        case Elements::BATTERY: {
            elements.battery = active;
            showBattery(elements.battery);
        } break;
        case Elements::LOCK: {
            elements.lock = active;
            lock->setVisible(active);
            if (active)
                timeLabel->setVisible(false);
        } break;
        case Elements::SIGNAL: {
            elements.signal = active;
        switch (indicator) {
        case Indicator::Signal:
            updateSignalStrength();
        } break;
        case Elements::TIME: {
            elements.time = active;
            timeLabel->setVisible(active);
            if (active)
            break;
        case Indicator::Time:
            timeLabel->setVisible(enabled);
            if (enabled) {
                lock->setVisible(false);
        } break;
        case Elements::SIM:
            elements.sim = active;
            }
            break;
        case Indicator::Lock:
            lock->setVisible(enabled);
            if (enabled) {
                timeLabel->setVisible(false);
            }
            break;
        case Indicator::Battery:
            showBattery(enabled);
            break;
        case Indicator::SimCard:
            simSet();
            break;
        case Elements::NETWORK_ACCESS_TECHNOLOGY:
            elements.networkAccessTechnology = active;
        case Indicator::NetworkAccessTechnology:
            updateNetworkAccessTechnology();
            break;
        };
        }
    }

    uint32_t calculateBatteryBars(uint32_t percentage)
    uint32_t TopBar::calculateBatteryBars(uint32_t percentage)
    {
        uint32_t level = 0;
        if (percentage <= 5) // level critical


@@ 177,13 217,13 @@ namespace gui

    bool TopBar::updateBattery(uint32_t percent)
    {
        showBattery(elements.battery);
        showBattery(configuration.isEnabled(Indicator::Battery));
        return true;
    }

    bool TopBar::updateBattery(bool plugged)
    {
        showBattery(elements.battery);
        showBattery(configuration.isEnabled(Indicator::Battery));
        return true;
    }



@@ 216,7 256,7 @@ namespace gui
        for (uint32_t i = 0; i < signalImgCount; i++) {
            signal[i]->setVisible(false);
        }
        if (elements.signal) {
        if (configuration.isEnabled(Indicator::Signal)) {
            auto rssiBar = Store::GSM::get()->getSignalStrength().rssiBar;
            if (rssiBar < Store::RssiBar::noOfSupprtedBars) {
                signal[static_cast<size_t>(rssiBar)]->setVisible(true);


@@ 229,7 269,7 @@ namespace gui

    bool TopBar::updateNetworkAccessTechnology()
    {
        if (elements.networkAccessTechnology) {
        if (configuration.isEnabled(Indicator::NetworkAccessTechnology)) {
            auto accessTechnology = Store::GSM::get()->getNetwork().accessTechnology;

            constexpr auto text2g  = "2G";


@@ 258,16 298,16 @@ namespace gui
        return true;
    }

    void TopBar::setTime(const UTF8 &time)
    void TopBar::setTime(const UTF8 &value)
    {
        timeLabel->setText(time);
        timeLabel->setText(value);
    }

    void TopBar::setTime(const uint32_t &time, bool mode24H)
    void TopBar::setTime(uint32_t value, bool mode24H)
    {
        setTime(utils::time::Time());
        timeMode   = (mode24H ? TimeMode::TIME_24H : TimeMode::TIME_12H);
        this->time = time;
        time       = value;
    }

    UTF8 TopBar::getTimeString()


@@ 276,13 316,17 @@ namespace gui
        return timeLabel->getText();
    }

    uint32_t TopBar::getTime() const noexcept
    {
        return time;
    }

    void TopBar::simSet()
    {
        if (!sim) {
        if (sim == nullptr) {
            return;
        }
        else if (elements.sim) {
        if (configuration.isEnabled(Indicator::SimCard)) {
            return sim->show(Store::GSM::get()->sim);
        }
        sim->visible = false;

M module-gui/gui/widgets/TopBar.hpp => module-gui/gui/widgets/TopBar.hpp +61 -41
@@ 1,21 1,52 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#ifndef MODULE_GUI_GUI_WIDGETS_TOPBAR_HPP_
#define MODULE_GUI_GUI_WIDGETS_TOPBAR_HPP_
#pragma once

#include "Image.hpp"
#include "Label.hpp"
#include "Rect.hpp"
#include "TopBar/SIM.hpp"
#include <common_data/EventStore.hpp>

#include <vector>
#include <map>

namespace gui
namespace gui::top_bar
{
    enum class Indicator
    {
        Signal,
        Time,
        Lock,
        Battery,
        SimCard,
        NetworkAccessTechnology
    };
    using Indicators        = std::vector<Indicator>;
    using IndicatorStatuses = std::map<Indicator, bool>;

    static const uint32_t batteryBarsCount  = 6;
    static const uint32_t signalImgCount    = 6;
    /**
     * Carries the top bar configuration.
     */
    class Configuration
    {
      public:
        void enable(Indicator indicator);
        void enable(const Indicators &indicators);
        void disable(Indicator indicator);
        void set(Indicator indicator, bool enabled);
        [[nodiscard]] auto isEnabled(Indicator indicator) const -> bool;
        [[nodiscard]] auto getIndicatorsConfiguration() const noexcept -> const IndicatorStatuses &;

      private:
        IndicatorStatuses indicatorStatuses = {{Indicator::Signal, false},
                                               {Indicator::Time, false},
                                               {Indicator::Lock, false},
                                               {Indicator::Battery, false},
                                               {Indicator::SimCard, false},
                                               {Indicator::NetworkAccessTechnology, false}};
    };

    /// Header of most of design Windows
    ///


@@ 31,19 62,10 @@ namespace gui
    /// [signal]    [title ] [sim] [battery]
    class TopBar : public Rect
    {
        static const uint32_t signalOffset;
        static const uint32_t batteryOffset;
        static constexpr uint32_t batteryBarsCount = 6;
        static constexpr uint32_t signalImgCount   = 6;

      public:
        enum class Elements
        {
            SIGNAL = 0x01,
            LOCK,
            BATTERY,
            TIME,
            SIM,
            NETWORK_ACCESS_TECHNOLOGY
        };
        enum class TimeMode
        {
            TIME_12H,


@@ 60,32 82,32 @@ namespace gui
        std::map<const Store::Battery::State, Image *> batteryChargings = {
            {Store::Battery::State::Charging, nullptr}, {Store::Battery::State::PluggedNotCharging, nullptr}};
        gui::SIM *sim = nullptr;
        void prepareWidget();
        Configuration configuration;
        static TimeMode timeMode;

        void prepareWidget();

        /// show bars in number - 0 bars, 1 bar, 2 bars...
        void batteryShowBars(uint32_t val);

        /// elements shown on TopBar
        struct
        {
            bool signal : 1;
            bool lock : 1;
            bool battery : 1;
            bool time : 1;
            bool sim : 1;
            bool networkAccessTechnology : 1;
        } elements = {false, false, false, false, true, true};
        static uint32_t calculateBatteryBars(uint32_t percentage);

        /**
         * Sets the status of the top bar indicator.
         * @param indicator     Indicator
         */
        void setIndicatorStatus(Indicator indicator, bool enabled);

      public:
        TopBar(Item *parent, uint32_t x, uint32_t y, uint32_t w, uint32_t h);

        /**
         * @brief Hides or shows images.
         * @note LOCK and TIME are located in the same place so only 1 can be active at the same time.
         * Configures the top bar.
         * @param configuration     Top bar configuration
         */
        void setActive(TopBar::Elements element, bool active);
        void setActive(std::list<std::pair<TopBar::Elements, bool>> elements);
        void configure(Configuration &&config);
        [[nodiscard]] auto getConfiguration() const noexcept -> const Configuration &;

        /**
         * @brief Sets charge level of the battery based on percent value. This will cause appropriate image to be
         * displayed.


@@ 103,16 125,14 @@ namespace gui
        bool updateNetworkAccessTechnology();

        void simSet();
        void setTime(const UTF8 &time);
        void setTime(const uint32_t &time, bool mode24H);

        void setTime(const UTF8 &value);
        void setTime(uint32_t value, bool mode24H);

        UTF8 getTimeString();
        uint32_t getTime()
        {
            return time;
        };
        uint32_t getTime() const noexcept;

        void accept(GuiVisitor &visitor) override;
    };

} /* namespace gui */

#endif /* MODULE_GUI_GUI_WIDGETS_TOPBAR_HPP_ */
} // namespace gui::top_bar

M module-gui/gui/widgets/visitor/GuiVisitor.hpp => module-gui/gui/widgets/visitor/GuiVisitor.hpp +5 -2
@@ 11,7 11,10 @@ namespace gui
    class Window;
    class Label;
    class BottomBar;
    class TopBar;
    namespace top_bar
    {
        class TopBar;
    }

    /// The general purpose abstract interface for enabling Double-Dispatch behavior throughout `gui::Item`'s
    /// inheritance hierarchy.


@@ 24,7 27,7 @@ namespace gui
        virtual void visit(gui::Window &item)    = 0;
        virtual void visit(gui::Label &item)     = 0;
        virtual void visit(gui::BottomBar &item) = 0;
        virtual void visit(gui::TopBar &item)    = 0;
        virtual void visit(gui::top_bar::TopBar &item) = 0;
        virtual ~GuiVisitor()                    = default;
    };
} // namespace gui

M module-gui/test/test-google/test-gui-gridlayout.cpp => module-gui/test/test-google/test-gui-gridlayout.cpp +150 -2
@@ 67,7 67,20 @@ class GridLayoutTesting : public ::testing::Test
            Box->addWidget(item);
        }
    }

    void addItem(gui::BoxLayout *Box,
                 uint32_t item_w,
                 uint32_t item_h,
                 uint32_t id,
                 bool active                 = true,
                 const gui::Margins &margins = gui::Margins())
    {
        auto item     = new TestItem(nullptr, 0, 0, item_w, item_h);
        item->ID      = id;
        item->visible = true;
        item->setMargins(margins);
        item->activeItem = active;
        Box->addWidget(item);
    }
    gui::GridLayout *gridLayout = nullptr;

    ///> GridLayout test constants


@@ 120,6 133,139 @@ TEST_F(GridLayoutTesting, Navigate_Test)
    ASSERT_EQ(1 + expColSize, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 1 + expColSize << " should have focus";
}

TEST_F(GridLayoutTesting, Navigate_Test_ActiveItems_1)
{
    ///> Test for grid layout with 48 elements (A - active item, N - non active item, NV - non visible item)
    ///> | 1   A | 2  NA | 3   A | 4  NA | 5   A | 6  NA | 7  A  | 8  NA | 9   A | 10 NA | 11 A  | 12 NA |
    ///> | 13 NA | 14  A | 15 NA | 16  A | 17 NA | 18  A | 19 NA | 20  A | 21 NA | 22  A | 23 NA | 24  A |
    ///> | 25  A | 26 NA | 27  A | 28 NA | 29  A | 30 NA | 31 A  | 32 NA | 33  A | 34 NA | 35 A  | 36 NA |
    ///> | 37 NA | 38  A | 39 NA | 40  A | 41 NA | 42  A | 43 NA | 44  A | 45 NA | 46  A | 47 NA | 48  A |
    ///> | 49 NV | 50 NV | 51 NV | 52 NV |
    for (uint32_t i = 1; i <= 12; i++) {
        addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, (i % 2) ? true : false);
    }
    for (uint32_t i = 13; i <= 24; i++) {
        addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, ((i + 1) % 2) ? true : false);
    }
    for (uint32_t i = 25; i <= 36; i++) {
        addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, (i % 2) ? true : false);
    }
    for (uint32_t i = 37; i <= 48; i++) {
        addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, ((i + 1) % 2) ? true : false);
    }
    ///> Add some items to exceed grid layout area
    for (uint32_t i = 49; i <= 52; i++) {
        addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, true);
    }
    gridLayout->setFocus(true);
    ASSERT_EQ(gridLayout->rowSize, 4) << "row size is not " << 4 << " as expected";
    ASSERT_EQ(gridLayout->colSize, 12) << "col size is not " << 12 << " as expected";
    ASSERT_EQ(52, gridLayout->children.size()) << "GridLayout should contain " << 52 << " elements";

    ASSERT_EQ(1, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 1 << " should have focus";
    moveNTimes(gridLayout, 2, gui::KeyCode::KEY_RIGHT);
    ASSERT_EQ(5, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 5 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN);
    ASSERT_EQ(5 + (2 * expColSize), dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 5 + (2 * expColSize) << " should have focus";
    moveNTimes(gridLayout, 2, gui::KeyCode::KEY_LEFT);
    ASSERT_EQ(1 + (2 * expColSize), dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 1 + (2 * expColSize) << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN);
    ASSERT_EQ(1, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 1 << " should have focus";
}

TEST_F(GridLayoutTesting, Navigate_Test_ActiveItems_2_BorderCallback)
{
    ///> Test for grid layout with 48 elements
    ///> | 1   A | 2  NA | 3   A | 4  NA | 5   A | 6  NA | 7  A  | 8  NA | 9   A | 10 NA | 11 A  | 12 NA |
    ///> | 13 NA | 14  A | 15 NA | 16  A | 17 NA | 18  A | 19 NA | 20  A | 21 NA | 22  A | 23 NA | 24  A |
    ///> | 25  A | 26 NA | 27  A | 28 NA | 29  A | 30 NA | 31 A  | 32 NA | 33  A | 34 NA | 35 A  | 36 NA |
    ///> | 37 NA | 38  A | 39 NA |
    for (uint32_t i = 1; i <= 12; i++) {
        addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, (i % 2) ? true : false);
    }
    for (uint32_t i = 13; i <= 24; i++) {
        addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, ((i + 1) % 2) ? true : false);
    }
    for (uint32_t i = 25; i <= 36; i++) {
        addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, (i % 2) ? true : false);
    }
    for (uint32_t i = 37; i <= 39; i++) {
        addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, ((i + 1) % 2) ? true : false);
    }

    gridLayout->setFocus(true);
    ASSERT_EQ(gridLayout->rowSize, 4) << "row size is not " << 4 << " as expected";
    ASSERT_EQ(gridLayout->colSize, 12) << "col size is not " << 12 << " as expected";
    ASSERT_EQ(39, gridLayout->children.size()) << "GridLayout should contain " << 39 << " elements";

    ASSERT_EQ(1, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 1 << " should have focus";
    moveNTimes(gridLayout, 2, gui::KeyCode::KEY_LEFT);
    ASSERT_EQ(9, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 9 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_UP);
    ASSERT_EQ(33, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 33 << " should have focus";
    moveNTimes(gridLayout, 3, gui::KeyCode::KEY_LEFT);
    ASSERT_EQ(27, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 27 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN);
    ASSERT_EQ(3, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 3 << " should have focus";
    moveNTimes(gridLayout, 5, gui::KeyCode::KEY_RIGHT);
    ASSERT_EQ(1, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 1 << " should have focus";

    ///> Test for grid layout with 1 element
    ///> | 1NA |
    gridLayout->erase();
    addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, 1, false);
    ASSERT_EQ(gridLayout->children.size(), 1) << "elements size is not " << 1 << " as expected";
    ASSERT_EQ(gridLayout->rowSize, 1) << "row size is not " << 1 << " as expected";
    ASSERT_EQ(gridLayout->colSize, 1) << "col size is not " << 1 << " as expected";
    gridLayout->setFocus(false);
    gridLayout->setFocus(true);
    ASSERT_EQ(nullptr, gridLayout->getFocusItem()) << "no element shall be focused";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_LEFT);
    ASSERT_EQ(nullptr, gridLayout->getFocusItem()) << "no element shall be focused";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_RIGHT);
    ASSERT_EQ(nullptr, gridLayout->getFocusItem()) << "no element shall be focused";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_UP);
    ASSERT_EQ(nullptr, gridLayout->getFocusItem()) << "no element shall be focused";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN);
    ASSERT_EQ(nullptr, gridLayout->getFocusItem()) << "no element shall be focused";
    ///> Test for grid layout with 1 element
    ///> | 1NA | 1A |
    gridLayout->erase();
    addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, 1, false);
    addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, 2, true);
    ASSERT_EQ(gridLayout->children.size(), 2) << "elements size is not " << 2 << " as expected";
    ASSERT_EQ(gridLayout->rowSize, 1) << "row size is not " << 1 << " as expected";
    ASSERT_EQ(gridLayout->colSize, 2) << "col size is not " << 2 << " as expected";
    gridLayout->setFocus(false);
    gridLayout->setFocus(true);
    ASSERT_EQ(2, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 2 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_LEFT);
    ASSERT_EQ(2, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 2 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_RIGHT);
    ASSERT_EQ(2, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 2 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_UP);
    ASSERT_EQ(2, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 2 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN);
    ASSERT_EQ(2, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 2 << " should have focus";
}

///> TODO: Enable this test when issue with setFocus will be resolved
TEST_F(GridLayoutTesting, DISABLED_Border_Callback_Test)
{


@@ 149,7 295,7 @@ TEST_F(GridLayoutTesting, DISABLED_Border_Callback_Test)
        << "element with ID " << 37 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_LEFT);
    ASSERT_EQ(46, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 37 << " should have focus";
        << "element with ID " << 46 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN);
    ASSERT_EQ(10, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 10 << " should have focus";


@@ 170,6 316,7 @@ TEST_F(GridLayoutTesting, DISABLED_Border_Callback_Test)
    ASSERT_EQ(gridLayout->children.size(), 1) << "elements size is not " << 1 << " as expected";
    ASSERT_EQ(gridLayout->rowSize, 1) << "row size is not " << 1 << " as expected";
    ASSERT_EQ(gridLayout->colSize, 1) << "col size is not " << 1 << " as expected";

    gridLayout->setFocus(true);

    ASSERT_EQ(1, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)


@@ 194,6 341,7 @@ TEST_F(GridLayoutTesting, DISABLED_Border_Callback_Test)
    ASSERT_EQ(gridLayout->children.size(), 2) << "elements size is not " << 2 << " as expected";
    ASSERT_EQ(gridLayout->rowSize, 1) << "row size is not " << 1 << " as expected";
    ASSERT_EQ(gridLayout->colSize, 2) << "col size is not " << 2 << " as expected";

    gridLayout->setFocus(true);

    ASSERT_EQ(1, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)

M module-gui/test/test-google/test-gui-visitor-call.cpp => module-gui/test/test-google/test-gui-visitor-call.cpp +1 -1
@@ 25,7 25,7 @@ class VisitorMock : public gui::GuiVisitor
    MOCK_METHOD1(visit, void(gui::Window &item));
    MOCK_METHOD1(visit, void(gui::Label &item));
    MOCK_METHOD1(visit, void(gui::BottomBar &item));
    MOCK_METHOD1(visit, void(gui::TopBar &item));
    MOCK_METHOD1(visit, void(gui::top_bar::TopBar &item));
};

class CustomRect : public gui::Rect

M module-services/service-appmgr/model/ApplicationManager.cpp => module-services/service-appmgr/model/ApplicationManager.cpp +16 -8
@@ 106,12 106,6 @@ namespace app::manager
    {
        registerMessageHandlers();
        blockingTimer->connect([this](sys::Timer &) { onPhoneLocked(); });
        settings->registerValueChange(settings::SystemProperties::displayLanguage,
                                      [this](std::string value) { displayLanguageChanged(value); });
        settings->registerValueChange(settings::SystemProperties::inputLanguage,
                                      [this](std::string value) { inputLanguageChanged(value); });
        settings->registerValueChange(settings::SystemProperties::lockTime,
                                      [this](std::string value) { lockTimeChanged(value); });
    }

    sys::ReturnCodes ApplicationManager::InitHandler()


@@ 120,6 114,18 @@ namespace app::manager
        utils::localize.setFallbackLanguage(utils::localize.DefaultLanguage);
        utils::localize.setDisplayLanguage(displayLanguage);
        utils::localize.setInputLanguage(inputLanguage);
        settings->registerValueChange(
            settings::SystemProperties::displayLanguage,
            [this](std::string value) { displayLanguageChanged(value); },
            settings::SettingsScope::Global);
        settings->registerValueChange(
            settings::SystemProperties::inputLanguage,
            [this](std::string value) { inputLanguageChanged(value); },
            settings::SettingsScope::Global);
        settings->registerValueChange(
            settings::SystemProperties::lockTime,
            [this](std::string value) { lockTimeChanged(value); },
            settings::SettingsScope::Global);

        startSystemServices();
        startBackgroundApplications();


@@ 161,6 167,7 @@ namespace app::manager

    sys::ReturnCodes ApplicationManager::DeinitHandler()
    {
        settings->unregisterValueChange();
        closeApplications();
        closeServices();
        return sys::ReturnCodes::Success;


@@ 540,7 547,8 @@ namespace app::manager
            return false;
        }
        displayLanguage = requestedLanguage;
        settings->setValue(settings::SystemProperties::displayLanguage, displayLanguage);
        settings->setValue(
            settings::SystemProperties::displayLanguage, displayLanguage, settings::SettingsScope::Global);
        utils::localize.setDisplayLanguage(displayLanguage);
        rebuildActiveApplications();
        return true;


@@ 555,7 563,7 @@ namespace app::manager
            return false;
        }
        inputLanguage = requestedLanguage;
        settings->setValue(settings::SystemProperties::inputLanguage, inputLanguage);
        settings->setValue(settings::SystemProperties::inputLanguage, inputLanguage, settings::SettingsScope::Global);
        utils::localize.setInputLanguage(inputLanguage);
        return true;
    }

M module-services/service-cellular/CellularRequestHandler.cpp => module-services/service-cellular/CellularRequestHandler.cpp +2 -0
@@ 22,6 22,8 @@

#include <module-cellular/at/response.hpp>

using namespace cellular;

void CellularRequestHandler::handle(ImeiRequest &request, at::Result &result)
{
    if (!request.checkModemResponse(result)) {

M module-services/service-cellular/CellularUrcHandler.cpp => module-services/service-cellular/CellularUrcHandler.cpp +2 -0
@@ 11,6 11,8 @@
#include <service-evtmgr/Constants.hpp>
#include <service-appmgr/Controller.hpp>

using namespace at::urc;

// this static function will be replaced by Settings API
static bool isSettingsAutomaticTimeSyncEnabled()
{

M module-services/service-cellular/CellularUrcHandler.hpp => module-services/service-cellular/CellularUrcHandler.hpp +11 -13
@@ 18,27 18,25 @@
#include <module-cellular/at/UrcResponse.hpp>
#include <module-cellular/at/UrcQiurc.hpp>

using namespace at::urc;

/**
 * ServiceCellular helper for handling Urc messages
 */
class CellularUrcHandler : public UrcHandler
class CellularUrcHandler : public at::urc::UrcHandler
{
  public:
    CellularUrcHandler(ServiceCellular &cellularService) : cellularService(cellularService)
    {}

    void Handle(Clip &urc) final;
    void Handle(Creg &urc) final;
    void Handle(Cmti &urc) final;
    void Handle(Cusd &urc) final;
    void Handle(Ctze &urc) final;
    void Handle(Qind &urc) final;
    void Handle(Cpin &urc) final;
    void Handle(Qiurc &urc) final;
    void Handle(PoweredDown &urc) final;
    void Handle(UrcResponse &urc) final;
    void Handle(at::urc::Clip &urc) final;
    void Handle(at::urc::Creg &urc) final;
    void Handle(at::urc::Cmti &urc) final;
    void Handle(at::urc::Cusd &urc) final;
    void Handle(at::urc::Ctze &urc) final;
    void Handle(at::urc::Qind &urc) final;
    void Handle(at::urc::Cpin &urc) final;
    void Handle(at::urc::Qiurc &urc) final;
    void Handle(at::urc::PoweredDown &urc) final;
    void Handle(at::urc::UrcResponse &urc) final;

    /**
     * Gets the response that should be returned after handling Urc

M module-services/service-cellular/ServiceCellular.cpp => module-services/service-cellular/ServiceCellular.cpp +10 -8
@@ 204,8 204,6 @@ ServiceCellular::ServiceCellular() : sys::Service(serviceName, "", cellularStack
        sys::Bus::SendMulticast(msg.value(), sys::BusChannels::ServiceCellularNotifications, this);
    };
    registerMessageHandlers();
    settings->registerValueChange(settings::Cellular::volte_on,
                                  [this](const std::string &value) { volteChanged(value); });
    packetData = std::make_unique<packet_data::PacketData>(*this);
    packetData->loadAPNSettings();
}


@@ 235,6 233,8 @@ sys::ReturnCodes ServiceCellular::InitHandler()
    board = EventManagerServiceAPI::GetBoard(this);

    state.set(this, State::ST::WaitForStartPermission);
    settings->registerValueChange(settings::Cellular::volte_on,
                                  [this](const std::string &value) { volteChanged(value); });
    return sys::ReturnCodes::Success;
}



@@ 297,12 297,12 @@ void ServiceCellular::registerMessageHandlers()
        return handleCellularGetActiveContextsMessage(msg);
    });

    connect(typeid(CellularGetAPNMessage), [&](sys::Message *request) -> sys::MessagePointer {
        connect(typeid(CellularGetCurrentOperatorMessage), [&](sys::Message *request) -> sys::MessagePointer {
            auto msg = static_cast<CellularGetCurrentOperatorMessage *>(request);
            return handleCellularGetCurrentOperator(msg);
        });
    connect(typeid(CellularGetCurrentOperatorMessage), [&](sys::Message *request) -> sys::MessagePointer {
        auto msg = static_cast<CellularGetCurrentOperatorMessage *>(request);
        return handleCellularGetCurrentOperator(msg);
    });

    connect(typeid(CellularGetAPNMessage), [&](sys::Message *request) -> sys::MessagePointer {
        auto msg = static_cast<CellularGetAPNMessage *>(request);
        return handleCellularGetAPNMessage(msg);
    });


@@ 1284,7 1284,9 @@ bool ServiceCellular::handleSimState(at::SimState state, const std::string messa
    switch (state) {
    case at::SimState::Ready:
        Store::GSM::get()->sim = Store::GSM::get()->selected;
        settings->setValue(settings::SystemProperties::activeSim, utils::enumToString(Store::GSM::get()->selected));
        settings->setValue(settings::SystemProperties::activeSim,
                           utils::enumToString(Store::GSM::get()->selected),
                           settings::SettingsScope::Global);
        // SIM causes SIM INIT, only on ready
        response =
            std::move(std::make_unique<CellularNotificationMessage>(CellularNotificationMessage::Type::SIM_READY));

M module-services/service-cellular/service-cellular/CellularRequestHandler.hpp => module-services/service-cellular/service-cellular/CellularRequestHandler.hpp +8 -10
@@ 6,21 6,19 @@
#include "RequestHandler.hpp"
#include "service-cellular/ServiceCellular.hpp"

using namespace cellular;

class CellularRequestHandler : public RequestHandler
class CellularRequestHandler : public cellular::RequestHandler
{
  public:
    CellularRequestHandler(ServiceCellular &serviceCellular) : cellular(serviceCellular)
    {}

    void handle(ImeiRequest &request, at::Result &result) final;
    void handle(UssdRequest &request, at::Result &result) final;
    void handle(CallRequest &request, at::Result &result) final;
    void handle(PasswordRegistrationRequest &request, at::Result &result) final;
    void handle(SupplementaryServicesRequest &request, at::Result &result) final;
    void handle(PinChangeRequest &request, at::Result &result) final;
    void handle(ClirRequest &request, at::Result &result) final;
    void handle(cellular::ImeiRequest &request, at::Result &result) final;
    void handle(cellular::UssdRequest &request, at::Result &result) final;
    void handle(cellular::CallRequest &request, at::Result &result) final;
    void handle(cellular::PasswordRegistrationRequest &request, at::Result &result) final;
    void handle(cellular::SupplementaryServicesRequest &request, at::Result &result) final;
    void handle(cellular::PinChangeRequest &request, at::Result &result) final;
    void handle(cellular::ClirRequest &request, at::Result &result) final;

  private:
    ServiceCellular &cellular;

M module-services/service-cellular/service-cellular/PacketDataTypes.hpp => module-services/service-cellular/service-cellular/PacketDataTypes.hpp +64 -2
@@ 5,6 5,10 @@

#include <string>
#include <memory>
#include <unordered_map>
#include <map>

#include <Utils.hpp>

namespace packet_data
{


@@ 22,10 26,11 @@ namespace packet_data
         */
        enum class APNType
        {
            Default, ///< for data traffic
            Default, ///< only one APN is set as default
            IMS,     ///< IP Multimedia Subsystem for eg VoLTE
            MMS,     ///< for MMS service
            Fota     ///< for Firmware Update
            Fota,    ///< for Firmware Update
            Internet //< for data traffic
        };

        /**


@@ 81,6 86,63 @@ namespace packet_data
            std::string password;
            std::string ip; /// set after connection

            std::string getAuthMethod()
            {
                return utils::enumToString(authMethod);
            }

            void setAuthMethod(const std::string &str)
            {
                if (str == "NONE")
                    authMethod = AuthMethod::NONE;
                else if (str == "AUTO")
                    authMethod = AuthMethod::AUTO;
                else if (str == "CHAP")
                    authMethod = AuthMethod::CHAP;
                else if (str == "PAP")
                    authMethod = AuthMethod::PAP;
                else
                    authMethod = AuthMethod::NONE;
            }

            std::string getApnType()
            {
                return utils::enumToString(apnType);
            }

            void setApnType(const std::string &str)
            {
                if (str == "Default")
                    apnType = APNType::Default;
                else if (str == "Fota")
                    apnType = APNType::Fota;
                else if (str == "IMS")
                    apnType = APNType::IMS;
                else if (str == "Internet")
                    apnType = APNType::Internet;
                else if (str == "MMS")
                    apnType = APNType::MMS;
                else
                    apnType = APNType::Internet;
            }

            std::string getApnProtocol()
            {
                return utils::enumToString(contextType);
            }

            void setApnProtocol(const std::string &str)
            {
                if (str == "ipv4")
                    contextType = ContextType::ipv4;
                else if (str == "ipv6")
                    contextType = ContextType::ipv6;
                else if (str == "ipv4v6")
                    contextType = ContextType::ipv4v6;
                else
                    contextType = ContextType::ipv4;
            }

            bool isEmpty() const noexcept
            {
                return apn.empty();

M module-services/service-db/DBServiceAPI.cpp => module-services/service-db/DBServiceAPI.cpp +48 -12
@@ 60,7 60,10 @@ auto DBServiceAPI::ThreadGetCount(sys::Service *serv, EntryState state) -> uint3

    auto ret            = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto threadResponse = dynamic_cast<DBThreadResponseMessage *>(ret.second.get());
    assert(threadResponse != nullptr);
    if (threadResponse == nullptr) {
        LOG_ERROR("DB response error, return code: %s", c_str(ret.first));
        return 0;
    }
    if ((ret.first == sys::ReturnCodes::Success) && (threadResponse->retCode == 1)) {
        return threadResponse->count;
    }


@@ 91,7 94,10 @@ auto DBServiceAPI::ContactGetByIDCommon(sys::Service *serv, std::shared_ptr<DBCo
{
    auto ret             = sys::Bus::SendUnicast(contactMsg, service::name::db, serv, DefaultTimeoutInMs);
    auto contactResponse = dynamic_cast<DBContactResponseMessage *>(ret.second.get());
    assert(contactResponse != nullptr);
    if (contactResponse == nullptr) {
        LOG_ERROR("DB response error, return code: %s", c_str(ret.first));
        return nullptr;
    }
    if ((ret.first == sys::ReturnCodes::Success) && (contactResponse->retCode != 0)) {
        return std::move(contactResponse->records);
    }


@@ 133,7 139,10 @@ auto DBServiceAPI::MatchContactByPhoneNumber(sys::Service *serv, const utils::Ph

    auto ret             = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto contactResponse = dynamic_cast<DBContactNumberResponseMessage *>(ret.second.get());
    assert(contactResponse);
    if (contactResponse == nullptr) {
        LOG_ERROR("DB response error, return code: %s", c_str(ret.first));
        return nullptr;
    }
    return std::move(contactResponse->contact);
}



@@ 180,7 189,10 @@ auto DBServiceAPI::ContactAdd(sys::Service *serv, const ContactRecord &rec) -> b

    auto ret             = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto contactResponse = dynamic_cast<DBContactResponseMessage *>(ret.second.get());
    assert(contactResponse != nullptr);
    if (contactResponse == nullptr) {
        LOG_ERROR("DB response error, return code: %s", c_str(ret.first));
        return false;
    }
    if ((ret.first == sys::ReturnCodes::Success) && (contactResponse->retCode != 0)) {
        return true;
    }


@@ 194,7 206,10 @@ auto DBServiceAPI::ContactRemove(sys::Service *serv, uint32_t id) -> bool

    auto ret             = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto contactResponse = dynamic_cast<DBContactResponseMessage *>(ret.second.get());
    assert(contactResponse != nullptr);
    if (contactResponse == nullptr) {
        LOG_ERROR("DB response error, return code: %s", c_str(ret.first));
        return false;
    }
    if ((ret.first == sys::ReturnCodes::Success) && (contactResponse->retCode != 0)) {
        return true;
    }


@@ 207,7 222,10 @@ auto DBServiceAPI::ContactUpdate(sys::Service *serv, const ContactRecord &rec) -

    auto ret             = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto contactResponse = dynamic_cast<DBContactResponseMessage *>(ret.second.get());
    assert(contactResponse != nullptr);
    if (contactResponse == nullptr) {
        LOG_ERROR("DB response error, return code: %s", c_str(ret.first));
        return false;
    }
    if ((ret.first == sys::ReturnCodes::Success) && (contactResponse->retCode != 0)) {
        return true;
    }


@@ 225,7 243,10 @@ auto DBServiceAPI::ContactSearch(sys::Service *serv, UTF8 primaryName, UTF8 alte

    auto ret             = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto contactResponse = dynamic_cast<DBContactResponseMessage *>(ret.second.get());
    assert(contactResponse != nullptr);
    if (contactResponse == nullptr) {
        LOG_ERROR("DB response error, return code: %s", c_str(ret.first));
        return nullptr;
    }
    if ((ret.first == sys::ReturnCodes::Success) && (contactResponse->retCode != 0)) {
        return std::move(contactResponse->records);
    }


@@ 240,7 261,10 @@ auto DBServiceAPI::CalllogAdd(sys::Service *serv, const CalllogRecord &rec) -> C

    auto ret             = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto calllogResponse = dynamic_cast<DBCalllogResponseMessage *>(ret.second.get());
    assert(calllogResponse != nullptr);
    if (calllogResponse == nullptr) {
        LOG_ERROR("DB response error, return code: %s", c_str(ret.first));
        return CalllogRecord();
    }
    if ((ret.first == sys::ReturnCodes::Success) && (calllogResponse->retCode != 0)) {
        auto records = *calllogResponse->records;
        if (!records.empty()) {


@@ 258,7 282,10 @@ auto DBServiceAPI::CalllogRemove(sys::Service *serv, uint32_t id) -> bool

    auto ret             = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto calllogResponse = dynamic_cast<DBCalllogResponseMessage *>(ret.second.get());
    assert(calllogResponse != nullptr);
    if (calllogResponse == nullptr) {
        LOG_ERROR("DB response error, return code: %s", c_str(ret.first));
        return false;
    }
    if ((ret.first == sys::ReturnCodes::Success) && (calllogResponse->retCode != 0)) {
        return true;
    }


@@ 273,7 300,10 @@ auto DBServiceAPI::CalllogUpdate(sys::Service *serv, const CalllogRecord &rec) -

    auto ret             = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto calllogResponse = dynamic_cast<DBCalllogResponseMessage *>(ret.second.get());
    assert(calllogResponse != nullptr);
    if (calllogResponse == nullptr) {
        LOG_ERROR("DB response error, return code: %s", c_str(ret.first));
        return false;
    }
    if ((ret.first == sys::ReturnCodes::Success) && (calllogResponse->retCode != 0)) {
        return true;
    }


@@ 286,7 316,10 @@ auto DBServiceAPI::CalllogGetCount(sys::Service *serv, EntryState state) -> uint

    auto ret             = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto calllogResponse = dynamic_cast<DBCalllogResponseMessage *>(ret.second.get());
    assert(calllogResponse != nullptr);
    if (calllogResponse == nullptr) {
        LOG_ERROR("DB response error, return code: %s", c_str(ret.first));
        return 0;
    }
    if ((ret.first == sys::ReturnCodes::Success) && (calllogResponse->retCode != 0)) {
        return calllogResponse->count;
    }


@@ 310,7 343,10 @@ auto DBServiceAPI::GetCountryCodeByMCC(sys::Service *serv, uint32_t mcc) -> uint

    auto ret      = sys::Bus::SendUnicast(msg, service::name::db, serv, DefaultTimeoutInMs);
    auto response = dynamic_cast<DBCountryCodeResponseMessage *>(ret.second.get());
    assert(response != nullptr);
    if (response == nullptr) {
        LOG_ERROR("DB response error, return code: %s", c_str(ret.first));
        return 0;
    }
    if (ret.first == sys::ReturnCodes::Success) {
        return (response->row.country_code);
    }

M module-services/service-db/agents/settings/Settings.cpp => module-services/service-db/agents/settings/Settings.cpp +46 -23
@@ 52,9 52,9 @@ namespace settings
    {
        LOG_DEBUG("handleVariableChanged");
        if (auto msg = dynamic_cast<settings::Messages::VariableChanged *>(req)) {
            auto key = msg->getPath().variable;
            auto key = msg->getPath();
            auto val = msg->getValue();
            LOG_DEBUG("handleVariableChanged: (k=v): (%s=%s)", key.c_str(), val.value_or("").c_str());
            LOG_DEBUG("handleVariableChanged: (k=v): (%s=%s)", key.to_string().c_str(), val.value_or("").c_str());
            ValueCb::iterator it_cb = cbValues.find(key);
            if (cbValues.end() != it_cb) {
                auto [cb, cbWithName] = it_cb->second;


@@ 62,13 62,13 @@ namespace settings
                    // in case of two callbacks there is a need to duplicate the value
                    auto value = std::move(val.value_or(""));
                    cb(std::string{value});
                    cbWithName(key, std::move(value));
                    cbWithName(key.variable, std::move(value));
                }
                else if (nullptr != cb) {
                    cb(std::move(val.value_or("")));
                }
                else {
                    cbWithName(key, std::move(val.value_or("")));
                    cbWithName(key.variable, std::move(val.value_or("")));
                }
            }
        }


@@ 115,56 115,79 @@ namespace settings
        return std::make_shared<sys::ResponseMessage>();
    }

    void Settings::registerValueChange(const std::string &variableName, ValueChangedCallback cb)
    void Settings::registerValueChange(const std::string &variableName, ValueChangedCallback cb, SettingsScope scope)
    {
        ValueCb::iterator it_cb = cbValues.find(variableName);
        if (cbValues.end() != it_cb && nullptr != it_cb->second.first) {
            LOG_INFO("Callback function on value change (%s) already exists, rewriting", variableName.c_str());
        }
        cbValues[variableName].first = cb;
        EntryPath path;
        path.variable = variableName;
        path.service  = app->GetName();
        path.scope    = scope;

        auto it_cb = cbValues.find(path);
        if (cbValues.end() != it_cb && nullptr != it_cb->second.first) {
            LOG_INFO("Callback function on value change (%s) already exists, rewriting", path.to_string().c_str());
        }
        cbValues[path].first = cb;

        auto msg      = std::make_shared<settings::Messages::RegisterOnVariableChange>(path);
        sendMsg(std::move(msg));
    }

    void Settings::registerValueChange(const std::string &variableName, ValueChangedCallbackWithName cb)
    void Settings::registerValueChange(const std::string &variableName,
                                       ValueChangedCallbackWithName cb,
                                       SettingsScope scope)
    {
        auto it_cb = cbValues.find(variableName);
        if (cbValues.end() != it_cb && nullptr != it_cb->second.second) {
            LOG_INFO("Callback function on value change (%s) already exists, rewriting", variableName.c_str());
        }
        cbValues[variableName].second = cb;
        EntryPath path;
        path.variable = variableName;
        path.service  = app->GetName();
        path.scope    = scope;

        auto it_cb = cbValues.find(path);
        if (cbValues.end() != it_cb && nullptr != it_cb->second.second) {
            LOG_INFO("Callback function on value change (%s) already exists, rewriting", path.to_string().c_str());
        }
        cbValues[path].second = cb;

        auto msg      = std::make_shared<settings::Messages::RegisterOnVariableChange>(path);
        sendMsg(std::move(msg));
    }

    void Settings::unregisterValueChange(const std::string &variableName)
    void Settings::unregisterValueChange(const std::string &variableName, SettingsScope scope)
    {
        ValueCb::iterator it_cb = cbValues.find(variableName);
        EntryPath path;
        path.variable = variableName;
        path.service  = app->GetName();
        path.scope    = scope;

        auto it_cb = cbValues.find(path);
        if (cbValues.end() == it_cb) {
            LOG_INFO("Callback function on value change (%s) does not exist", variableName.c_str());
            LOG_INFO("Callback function on value change (%s) does not exist", path.to_string().c_str());
        }
        else {
            LOG_DEBUG("[Settings::unregisterValueChange] %s", path.to_string().c_str());
            cbValues.erase(it_cb);
        }

        EntryPath path;
        path.variable = variableName;
        path.service  = app->GetName();
        auto msg      = std::make_shared<settings::Messages::UnregisterOnVariableChange>(path);
        sendMsg(std::move(msg));
    }

    void Settings::setValue(const std::string &variableName, const std::string &variableValue)
    void Settings::unregisterValueChange()
    {
        for (auto it_cb : cbValues) {
            LOG_DEBUG("[Settings::unregisterValueChange] %s", it_cb.first.to_string().c_str());
            auto msg = std::make_shared<settings::Messages::UnregisterOnVariableChange>(it_cb.first);
            sendMsg(std::move(msg));
        }
        cbValues.clear();
        LOG_INFO("Unregistered all settings variable change on application (%s)", app->GetName().c_str());
    }

    void Settings::setValue(const std::string &variableName, const std::string &variableValue, SettingsScope scope)
    {
        EntryPath path;
        path.variable = variableName;
        path.service  = app->GetName();
        path.scope    = scope;
        auto msg      = std::make_shared<settings::Messages::SetVariable>(path, variableValue);
        sendMsg(std::move(msg));
    }

M module-services/service-db/agents/settings/SettingsAgent.cpp => module-services/service-db/agents/settings/SettingsAgent.cpp +20 -26
@@ 4,8 4,6 @@
#include "SettingsAgent.hpp"
#include "Settings_queries.hpp"

#include <service-db/SettingsMessages.hpp>

#include <Database/Database.hpp>
#include <Service/Service.hpp>
#include <module-sys/Service/Bus.hpp>


@@ 24,16 22,6 @@ SettingsAgent::SettingsAgent(sys::Service *parentService) : DatabaseAgent(parent

void SettingsAgent::initDb()
{
    auto notifications = database->query(settings::Statements::getAllNotifications);
    if (nullptr == notifications || 0 == notifications->getRowCount()) {
        return;
    }
    do {
        variableChangeRecipents[(*notifications)[0].getString()].insert((*notifications)[1].getString());
        /*what about mode/profile
        modeChangeRecipents;
        profileChangeRecipents;*/
    } while (notifications->nextRow());
}

void SettingsAgent::deinitDb()


@@ 95,8 83,7 @@ auto SettingsAgent::getAgentName() -> const std::string
// dbSingleVar
auto SettingsAgent::dbGetValue(settings::EntryPath path) -> std::optional<std::string>
{
    // auto retQuery = database->query(settings::Statements::getValue, path.to_string());
    auto retQuery = database->query(settings::Statements::getValue, path.variable.c_str());
    auto retQuery = database->query(settings::Statements::getValue, path.to_string().c_str());
    if (nullptr == retQuery || 1 != retQuery->getRowCount()) {
        return std::string{};
    }


@@ 106,17 93,18 @@ auto SettingsAgent::dbGetValue(settings::EntryPath path) -> std::optional<std::s
auto SettingsAgent::dbSetValue(settings::EntryPath path, std::string value) -> bool
{
    /// insert or update
    return database->execute(settings::Statements::insertValue, path.variable.c_str(), value.c_str());
    return database->execute(settings::Statements::insertValue, path.to_string().c_str(), value.c_str());
}

auto SettingsAgent::dbRegisterValueChange(settings::EntryPath path) -> bool
{
    return database->execute(settings::Statements::setNotification, path.variable.c_str(), path.service.c_str());
    return database->execute(settings::Statements::setNotification, path.to_string().c_str(), path.service.c_str());
}

auto SettingsAgent::dbUnregisterValueChange(settings::EntryPath path) -> bool
{
    return database->execute(settings::Statements::clearNotificationdRow, path.variable.c_str());
    return database->execute(
        settings::Statements::clearNotificationdRow, path.to_string().c_str(), path.service.c_str());
}

// db Profile


@@ 223,12 211,13 @@ auto SettingsAgent::handleSetVariable(sys::Message *req) -> sys::MessagePointer
        auto oldValue = dbGetValue(path);
        if (oldValue.has_value() && oldValue.value() != value) {
            dbSetValue(path, value);
            // for (auto service : variableChangeRecipents[path.to_string()]) {
            for (auto service : variableChangeRecipents[path.variable]) {
                if (service != path.service) {
            LOG_DEBUG("[SettingsAgent::handleSetVariable] %s=%s", path.to_string().c_str(), value.c_str());
            for (auto regPath : variableChangeRecipents[path.to_string()]) {
                if (regPath.service != path.service) {
                    auto updateMsg =
                        std::make_shared<settings::Messages::VariableChanged>(path, value, oldValue.value_or(""));
                    sys::Bus::SendUnicast(std::move(updateMsg), service, parentService);
                        std::make_shared<settings::Messages::VariableChanged>(regPath, value, oldValue.value_or(""));
                    sys::Bus::SendUnicast(std::move(updateMsg), regPath.service, parentService);
                    LOG_DEBUG("[SettingsAgent::handleSetVariable] notified service: %s", regPath.service.c_str());
                }
            }
        }


@@ 242,14 231,18 @@ auto SettingsAgent::handleRegisterOnVariableChange(sys::Message *req) -> sys::Me
        auto path = msg->getPath();
        if (dbRegisterValueChange(path)) {
            auto it = variableChangeRecipents.find(path.to_string());
            if (variableChangeRecipents.end() == it || it->second.end() == it->second.find(path.service)) {
                variableChangeRecipents[path.to_string()] = {path.service};
            if (variableChangeRecipents.end() == it || it->second.end() == it->second.find(path)) {
                variableChangeRecipents[path.to_string()] = {path};
                auto currentValue                         = dbGetValue(path).value_or("");
                auto msgValue = std::make_shared<::settings::Messages::VariableChanged>(path, currentValue, "");
                sys::Bus::SendUnicast(std::move(msgValue), msg->sender, parentService);
                LOG_DEBUG("[SettingsAgent::handleRegisterOnVariableChange] %s=%s to %s",
                          path.to_string().c_str(),
                          currentValue.c_str(),
                          msg->sender.c_str());
            }
            else {
                it->second.insert(path.service);
                it->second.insert(path);
            }
        }
    }


@@ 263,7 256,8 @@ auto SettingsAgent::handleUnregisterOnVariableChange(sys::Message *req) -> sys::
        if (dbUnregisterValueChange(path)) {
            auto it = variableChangeRecipents.find(path.to_string());
            if (variableChangeRecipents.end() != it) {
                it->second.erase(path.service);
                it->second.erase(path);
                LOG_DEBUG("[SettingsAgent::handleUnregisterOnVariableChange] %s", path.to_string().c_str());
            }
        }
    }

M module-services/service-db/agents/settings/SettingsAgent.hpp => module-services/service-db/agents/settings/SettingsAgent.hpp +2 -1
@@ 32,7 32,8 @@ class SettingsAgent : public DatabaseAgent
    auto getAgentName() -> const std::string override;

  private:
    using MapOfRecipentsToBeNotified = std::map<std::string, std::set<std::string>>;
    // using MapOfRecipentsToBeNotified = std::map<std::string, std::set<std::string>>;
    using MapOfRecipentsToBeNotified = std::map<std::string, std::set<settings::EntryPath>>;
    MapOfRecipentsToBeNotified variableChangeRecipents;
    using SetOfRecipents = std::set<std::string>;
    SetOfRecipents profileChangedRecipents;

M module-services/service-db/agents/settings/SystemSettings.hpp => module-services/service-db/agents/settings/SystemSettings.hpp +7 -0
@@ 24,6 24,13 @@ namespace settings
        constexpr inline auto bondedDevices    = "bt_bonded_devices";
        constexpr inline auto btKeys           = "bt_keys";
    } // namespace Bluetooth
    namespace Brightness
    {
        constexpr inline auto state           = "br_state";
        constexpr inline auto brightnessLevel = "br_level";
        constexpr inline auto gammaFactor     = "br_gamma_Factor";
        constexpr inline auto autoMode        = "br_auto_mode";
    } // namespace Brightness

    namespace Cellular
    {

M module-services/service-db/service-db/Settings.hpp => module-services/service-db/service-db/Settings.hpp +15 -10
@@ 5,6 5,8 @@

#include <module-sys/Service/Message.hpp>
#include <service-db/DBServiceName.hpp>
#include "SettingsScope.hpp"
#include "SettingsMessages.hpp"

#include <cstdint>
#include <functional>


@@ 16,11 18,6 @@

namespace settings
{
    namespace Messages
    {
        class SettingsMessage;
    }

    class Settings
    {
      public:


@@ 36,10 33,18 @@ namespace settings
        Settings(sys::Service *app, const std::string &dbAgentName = service::name::db);
        virtual ~Settings();

        void setValue(const std::string &variableName, const std::string &variableValue);
        void registerValueChange(const std::string &variableName, ValueChangedCallback cb);
        void registerValueChange(const std::string &variableName, ValueChangedCallbackWithName cb);
        void unregisterValueChange(const std::string &variableName);
        void setValue(const std::string &variableName,
                      const std::string &variableValue,
                      SettingsScope scope = SettingsScope::AppLocal);
        void registerValueChange(const std::string &variableName,
                                 ValueChangedCallback cb,
                                 SettingsScope scope = SettingsScope::AppLocal);
        void registerValueChange(const std::string &variableName,
                                 ValueChangedCallbackWithName cb,
                                 SettingsScope scope = SettingsScope::AppLocal);
        void unregisterValueChange(const std::string &variableName, SettingsScope scope = SettingsScope::AppLocal);
        /// unregisters all registered variables (both global and local)
        void unregisterValueChange();

        void getAllProfiles(OnAllProfilesRetrievedCallback cb);
        void setCurrentProfile(const std::string &profile);


@@ 61,7 66,7 @@ namespace settings
        std::string phoneMode;
        std::string profile;

        using ValueCb = std::map<std::string, std::pair<ValueChangedCallback, ValueChangedCallbackWithName>>;
        using ValueCb = std::map<EntryPath, std::pair<ValueChangedCallback, ValueChangedCallbackWithName>>;
        ValueCb cbValues;
        ModeChangedCallback cbMode;
        OnAllModesRetrievedCallback cbAllModes;

M module-services/service-db/service-db/SettingsMessages.hpp => module-services/service-db/service-db/SettingsMessages.hpp +30 -0
@@ 5,6 5,7 @@

#include <MessageType.hpp>
#include <Service/Message.hpp>
#include <service-db/SettingsScope.hpp>

#include <list>
#include <memory>


@@ 20,11 21,40 @@ namespace settings
        std::string service;
        std::string profile;
        std::string variable;
        SettingsScope scope;

        [[nodiscard]] auto to_string(std::string sep = "\\") const -> std::string
        {
            if (SettingsScope::Global == scope) {
                return variable;
            }
            return mode + sep + service + sep + profile + sep + variable;
        }

        bool operator<(const EntryPath &other) const
        {
            if (mode < other.mode)
                return true;
            if (mode > other.mode)
                return false;
            if (service < other.service)
                return true;
            if (service > other.service)
                return false;
            if (profile < other.profile)
                return true;
            if (profile > other.profile)
                return false;
            if (variable < other.variable)
                return true;
            if (variable > other.variable)
                return false;
            if (scope < other.scope)
                return true;
            if (scope > other.scope)
                return false;
            return false;
        }
    };

    namespace Messages

A module-services/service-db/service-db/SettingsScope.hpp => module-services/service-db/service-db/SettingsScope.hpp +12 -0
@@ 0,0 1,12 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once
namespace settings
{
    enum class SettingsScope
    {
        Global,
        AppLocal
    };
}

M module-services/service-db/test/test-service-db-settings-messages.cpp => module-services/service-db/test/test-service-db-settings-messages.cpp +4 -4
@@ 118,13 118,13 @@ TEST_CASE("Settings Messages")
        settings::Service settings("settings");
        settings.InitHandler();

        sys::Bus::SendUnicast(std::make_shared<settings::Messages::RegisterOnVariableChange>(
                                  settings::EntryPath({"mode", "service", "profile", "variable"})),
        sys::Bus::SendUnicast(std::make_shared<settings::Messages::RegisterOnVariableChange>(settings::EntryPath(
                                  {"mode", "service", "profile", "variable", settings::SettingsScope::AppLocal})),
                              "db-worker",
                              &settings);

        sys::Bus::SendUnicast(std::make_shared<settings::Messages::UnregisterOnVariableChange>(
                                  settings::EntryPath({"mode", "service", "profile", "variable"})),
        sys::Bus::SendUnicast(std::make_shared<settings::Messages::UnregisterOnVariableChange>(settings::EntryPath(
                                  {"mode", "service", "profile", "variable", settings::SettingsScope::AppLocal})),
                              "db-worker",
                              &settings);
    }

M module-services/service-db/test/test-service-db-settings-testservices.hpp => module-services/service-db/test/test-service-db-settings-testservices.hpp +6 -4
@@ 28,26 28,28 @@ namespace settings
            if (auto msg = dynamic_cast<settings::UTMsg::ReqRegValChg *>(req)) {
                debug("ReqRegValChg", msg->name, msg->value);
                whoRequestedNotifyOnChange = msg->sender;
                mySettings->registerValueChange(msg->name, ([this](std::string value) {
                mySettings->registerValueChange(msg->name,
                                                ([this](std::string value) {
                                                    ValueChanged(value);
                                                    auto cnf = std::make_shared<settings::UTMsg::CnfValChg>("", value);
                                                    sys::Bus::SendUnicast(
                                                        std::move(cnf), whoRequestedNotifyOnChange, this);
                                                }));
                                                }),
                                                settings::SettingsScope::Global);
                auto cnf = std::make_shared<settings::UTMsg::CnfRegValChg>(msg->name, msg->value);
                sys::Bus::SendUnicast(std::move(cnf), whoRequestedNotifyOnChange, this);
            }
            else if (auto msg = dynamic_cast<settings::UTMsg::ReqUnRegValChg *>(req)) {
                // unregister
                debug("ReqUnRegValChg", msg->name, msg->value);
                mySettings->unregisterValueChange(msg->name);
                mySettings->unregisterValueChange(msg->name, settings::SettingsScope::Global);
                auto cnf = std::make_shared<settings::UTMsg::CnfUnRegValChg>(msg->name, msg->value);
                sys::Bus::SendUnicast(std::move(cnf), msg->sender, this);
            }
            else if (auto msg = dynamic_cast<settings::UTMsg::ReqSetVal *>(req)) {
                // set value
                debug("ReqSetVal", msg->name, msg->value);
                mySettings->setValue(msg->name, msg->value);
                mySettings->setValue(msg->name, msg->value, settings::SettingsScope::Global);
                auto cnf = std::make_shared<settings::UTMsg::CnfReqSetVal>(msg->name, msg->value);
                sys::Bus::SendUnicast(std::move(cnf), msg->sender, this);
            }

M module-services/service-desktop/DesktopMessages.cpp => module-services/service-desktop/DesktopMessages.cpp +1 -0
@@ 6,6 6,7 @@

namespace sdesktop::developerMode
{
    using namespace parserFSM;
    void Event::send()
    {
        MessageHandler::putToSendQueue(context.createSimpleResponse());

M module-services/service-desktop/ServiceDesktop.cpp => module-services/service-desktop/ServiceDesktop.cpp +4 -3
@@ 29,8 29,6 @@ ServiceDesktop::ServiceDesktop() : sys::Service(service::name::service_desktop, 
    updateOS = std::make_unique<UpdateMuditaOS>(this);
    settings = std::make_unique<settings::Settings>(this);

    settings->registerValueChange(updateos::settings::history,
                                  [this](const std::string &value) { updateOS->setInitialHistory(value); });
}

ServiceDesktop::~ServiceDesktop()


@@ 42,7 40,7 @@ sys::ReturnCodes ServiceDesktop::InitHandler()
{
    desktopWorker = std::make_unique<WorkerDesktop>(this);
    const bool ret = desktopWorker->init(
        {{sdesktop::RECEIVE_QUEUE_BUFFER_NAME, sizeof(std::string), sdesktop::cdc_queue_len},
        {{sdesktop::RECEIVE_QUEUE_BUFFER_NAME, sizeof(std::string *), sdesktop::cdc_queue_len},
         {sdesktop::SEND_QUEUE_BUFFER_NAME, sizeof(std::string *), sdesktop::cdc_queue_object_size}});

    if (ret == false) {


@@ 115,6 113,9 @@ sys::ReturnCodes ServiceDesktop::InitHandler()
        return std::make_shared<sys::ResponseMessage>();
    });

    settings->registerValueChange(updateos::settings::history,
                                  [this](const std::string &value) { updateOS->setInitialHistory(value); });

    return (sys::ReturnCodes::Success);
}


M module-services/service-desktop/WorkerDesktop.cpp => module-services/service-desktop/WorkerDesktop.cpp +5 -6
@@ 30,7 30,7 @@ bool WorkerDesktop::init(std::list<sys::WorkerQueueInfo> queues)
    Worker::init(queues);

    receiveQueue                         = Worker::getQueueHandleByName(sdesktop::RECEIVE_QUEUE_BUFFER_NAME);
    parserFSM::MessageHandler::sendQueue = Worker::getQueueHandleByName(sdesktop::SEND_QUEUE_BUFFER_NAME);
    parserFSM::MessageHandler::setSendQueueHandle(Worker::getQueueHandleByName(sdesktop::SEND_QUEUE_BUFFER_NAME));

    return (bsp::usbInit(receiveQueue, this) < 0) ? false : true;
}


@@ 58,16 58,17 @@ bool WorkerDesktop::handleMessage(uint32_t queueID)

    LOG_INFO("handleMessage received data from queue: %s", qname.c_str());

    static std::string *sendMsg = nullptr;
    static std::string receivedMsg;
    if (qname == sdesktop::RECEIVE_QUEUE_BUFFER_NAME) {
        std::string *receivedMsg = nullptr;
        if (!queue->Dequeue(&receivedMsg, 0)) {
            LOG_ERROR("handleMessage failed to receive from \"%s\"", sdesktop::RECEIVE_QUEUE_BUFFER_NAME);
            return false;
        }
        parser.processMessage(receivedMsg);
        parser.processMessage(std::move(*receivedMsg));
        delete receivedMsg;
    }
    else if (qname == sdesktop::SEND_QUEUE_BUFFER_NAME) {
        std::string *sendMsg = nullptr;
        if (!queue->Dequeue(&sendMsg, 0)) {
            LOG_ERROR("handleMessage xQueueReceive failed for %s.", sdesktop::SEND_QUEUE_BUFFER_NAME);
            return false;


@@ 75,9 76,7 @@ bool WorkerDesktop::handleMessage(uint32_t queueID)

        LOG_DEBUG("handeMessage sending %d bytes using usbCDCSend", static_cast<unsigned int>(sendMsg->length()));
        bsp::usbCDCSend(sendMsg);

        delete sendMsg;
        sendMsg = nullptr;
    }
    else {
        LOG_INFO("handeMessage got message on an unhandled queue");

M module-services/service-desktop/endpoints/EndpointFactory.hpp => module-services/service-desktop/endpoints/EndpointFactory.hpp +13 -14
@@ 19,36 19,35 @@
#include "restore/RestoreEndpoint.hpp"
#include "update/UpdateEndpoint.hpp"

using namespace parserFSM;

class EndpointFactory
{
  public:
    static auto create(Context &context, sys::Service *ownerServicePtr) -> std::unique_ptr<Endpoint>
    static auto create(parserFSM::Context &context, sys::Service *ownerServicePtr)
        -> std::unique_ptr<parserFSM::Endpoint>
    {
        LOG_DEBUG("Creating endpoint: %d", static_cast<int>(context.getEndpoint()));
        switch (context.getEndpoint()) {
        case EndpointType::update:
        case parserFSM::EndpointType::update:
            return std::make_unique<UpdateEndpoint>(ownerServicePtr);
        case EndpointType::filesystemUpload:
        case parserFSM::EndpointType::filesystemUpload:
            return std::make_unique<FilesystemEndpoint>(ownerServicePtr);
        case EndpointType::backup:
        case parserFSM::EndpointType::backup:
            return std::make_unique<BackupEndpoint>(ownerServicePtr);
        case EndpointType::deviceInfo:
        case parserFSM::EndpointType::deviceInfo:
            return std::make_unique<DeviceInfoEndpoint>(ownerServicePtr);
        case EndpointType::restore:
        case parserFSM::EndpointType::restore:
            return std::make_unique<RestoreEndpoint>(ownerServicePtr);
        case EndpointType::contacts:
        case parserFSM::EndpointType::contacts:
            return std::make_unique<ContactsEndpoint>(ownerServicePtr);
        case EndpointType::messages:
        case parserFSM::EndpointType::messages:
            return std::make_unique<MessagesEndpoint>(ownerServicePtr);
        case EndpointType::factory:
        case parserFSM::EndpointType::factory:
            return std::make_unique<FactoryResetEndpoint>(ownerServicePtr);
        case EndpointType::calllog:
        case parserFSM::EndpointType::calllog:
            return std::make_unique<CalllogEndpoint>(ownerServicePtr);
        case EndpointType::developerMode:
        case parserFSM::EndpointType::developerMode:
            return std::make_unique<DeveloperModeEndpoint>(ownerServicePtr);
        case EndpointType::calendarEvents:
        case parserFSM::EndpointType::calendarEvents:
            return std::make_unique<CalendarEventsEndpoint>(ownerServicePtr);
        default:
            return nullptr;

M module-services/service-desktop/endpoints/backup/BackupEndpoint.cpp => module-services/service-desktop/endpoints/backup/BackupEndpoint.cpp +2 -0
@@ 18,6 18,8 @@

static bool backupReady = false;

using namespace parserFSM;

auto BackupEndpoint::handle(Context &context) -> void
{
    switch (context.getMethod()) {

M module-services/service-desktop/endpoints/backup/BackupEndpoint.hpp => module-services/service-desktop/endpoints/backup/BackupEndpoint.hpp +4 -6
@@ 20,16 20,14 @@ namespace sys
    class Service;
} // namespace sys

using namespace parserFSM;

class BackupEndpoint : public Endpoint
class BackupEndpoint : public parserFSM::Endpoint
{
  public:
    BackupEndpoint(sys::Service *ownerServicePtr) : Endpoint(ownerServicePtr)
    {
        debugName = "BackupEndpoint";
    }
    auto handle(Context &context) -> void override;
    auto request(Context &context) -> sys::ReturnCodes;
    auto upload(Context &context) -> sys::ReturnCodes;
    auto handle(parserFSM::Context &context) -> void override;
    auto request(parserFSM::Context &context) -> sys::ReturnCodes;
    auto upload(parserFSM::Context &context) -> sys::ReturnCodes;
};

M module-services/service-desktop/endpoints/calendarEvents/CalendarEventsEndpoint.hpp => module-services/service-desktop/endpoints/calendarEvents/CalendarEventsEndpoint.hpp +4 -6
@@ 7,18 7,16 @@
#include "Service/Service.hpp"
#include "CalendarEventsHelper.hpp"

using namespace parserFSM;

class CalendarEventsEndpoint : public Endpoint
class CalendarEventsEndpoint : public parserFSM::Endpoint
{
  private:
    std::string debugName = "CalendarEventsEndpoint";
    std::unique_ptr<CalendarEventsHelper> helper;
    std::unique_ptr<parserFSM::CalendarEventsHelper> helper;

  public:
    CalendarEventsEndpoint(sys::Service *_ownerServicePtr) : Endpoint(_ownerServicePtr)
    {
        helper = std::make_unique<CalendarEventsHelper>(ownerServicePtr);
        helper = std::make_unique<parserFSM::CalendarEventsHelper>(ownerServicePtr);
    }
    void handle(Context &context) override;
    void handle(parserFSM::Context &context) override;
};

M module-services/service-desktop/endpoints/calllog/CalllogEndpoint.hpp => module-services/service-desktop/endpoints/calllog/CalllogEndpoint.hpp +4 -6
@@ 20,18 20,16 @@ namespace sys
    class Service;
} // namespace sys

using namespace parserFSM;

class CalllogEndpoint : public Endpoint
class CalllogEndpoint : public parserFSM::Endpoint
{
  private:
    std::unique_ptr<CalllogHelper> helper;
    std::unique_ptr<parserFSM::CalllogHelper> helper;

  public:
    CalllogEndpoint(sys::Service *_ownerServicePtr) : Endpoint(_ownerServicePtr)
    {
        debugName = "CalllogEndpoint";
        helper    = std::make_unique<CalllogHelper>(ownerServicePtr);
        helper    = std::make_unique<parserFSM::CalllogHelper>(ownerServicePtr);
    }
    auto handle(Context &context) -> void override;
    auto handle(parserFSM::Context &context) -> void override;
};

M module-services/service-desktop/endpoints/contacts/ContactsEndpoint.hpp => module-services/service-desktop/endpoints/contacts/ContactsEndpoint.hpp +4 -6
@@ 22,18 22,16 @@ namespace sys
    class Service;
} // namespace sys

using namespace parserFSM;

class ContactsEndpoint : public Endpoint
class ContactsEndpoint : public parserFSM::Endpoint
{
  private:
    std::unique_ptr<ContactHelper> helper;
    std::unique_ptr<parserFSM::ContactHelper> helper;

  public:
    ContactsEndpoint(sys::Service *_ownerServicePtr) : Endpoint(_ownerServicePtr)
    {
        debugName = "ContactsEndpoint";
        helper    = std::make_unique<ContactHelper>(ownerServicePtr);
        helper    = std::make_unique<parserFSM::ContactHelper>(ownerServicePtr);
    }
    auto handle(Context &context) -> void override;
    auto handle(parserFSM::Context &context) -> void override;
};

M module-services/service-desktop/endpoints/developerMode/DeveloperModeEndpoint.hpp => module-services/service-desktop/endpoints/developerMode/DeveloperModeEndpoint.hpp +4 -6
@@ 21,18 21,16 @@ namespace sys
    class Service;
} // namespace sys

using namespace parserFSM;

class DeveloperModeEndpoint : public Endpoint
class DeveloperModeEndpoint : public parserFSM::Endpoint
{
  private:
    std::unique_ptr<DeveloperModeHelper> helper;
    std::unique_ptr<parserFSM::DeveloperModeHelper> helper;

  public:
    DeveloperModeEndpoint(sys::Service *_ownerServicePtr) : Endpoint(_ownerServicePtr)
    {
        debugName = "DeveloperModeEndpoint";
        helper    = std::make_unique<DeveloperModeHelper>(ownerServicePtr);
        helper    = std::make_unique<parserFSM::DeveloperModeHelper>(ownerServicePtr);
    }
    auto handle(Context &context) -> void override;
    auto handle(parserFSM::Context &context) -> void override;
};

M module-services/service-desktop/endpoints/deviceInfo/DeviceInfoEndpoint.cpp => module-services/service-desktop/endpoints/deviceInfo/DeviceInfoEndpoint.cpp +2 -0
@@ 13,6 13,8 @@
#include <cstdint>
#include <string>

using namespace parserFSM;

auto DeviceInfoEndpoint::handle(Context &context) -> void
{
    switch (context.getMethod()) {

M module-services/service-desktop/endpoints/deviceInfo/DeviceInfoEndpoint.hpp => module-services/service-desktop/endpoints/deviceInfo/DeviceInfoEndpoint.hpp +3 -5
@@ 19,9 19,7 @@ namespace sys
    class Service;
} // namespace sys

using namespace parserFSM;

class DeviceInfoEndpoint : public Endpoint
class DeviceInfoEndpoint : public parserFSM::Endpoint
{

  public:


@@ 29,6 27,6 @@ class DeviceInfoEndpoint : public Endpoint
    {
        debugName = "DeviceInfoEndpoint";
    }
    auto handle(Context &context) -> void override;
    auto getDeviceInfo(Context &context) -> bool;
    auto handle(parserFSM::Context &context) -> void override;
    auto getDeviceInfo(parserFSM::Context &context) -> bool;
};

M module-services/service-desktop/endpoints/factoryReset/FactoryResetEndpoint.cpp => module-services/service-desktop/endpoints/factoryReset/FactoryResetEndpoint.cpp +3 -3
@@ 13,7 13,7 @@

#include <memory>

auto FactoryResetEndpoint::handle(Context &context) -> void
auto FactoryResetEndpoint::handle(parserFSM::Context &context) -> void
{
    if (context.getMethod() == parserFSM::http::Method::post) {



@@ 27,14 27,14 @@ auto FactoryResetEndpoint::handle(Context &context) -> void
            context.setResponseBody(json11::Json::object({{parserFSM::json::factoryRequest, false}}));
        }

        MessageHandler::putToSendQueue(context.createSimpleResponse());
        parserFSM::MessageHandler::putToSendQueue(context.createSimpleResponse());

        return;
    }
    else {
        context.setResponseBody(json11::Json::object({{parserFSM::json::factoryRequest, false}}));

        MessageHandler::putToSendQueue(context.createSimpleResponse());
        parserFSM::MessageHandler::putToSendQueue(context.createSimpleResponse());

        return;
    }

M module-services/service-desktop/endpoints/factoryReset/FactoryResetEndpoint.hpp => module-services/service-desktop/endpoints/factoryReset/FactoryResetEndpoint.hpp +3 -5
@@ 19,9 19,7 @@ namespace sys
    class Service;
} // namespace sys

using namespace parserFSM;

class FactoryResetEndpoint : public Endpoint
class FactoryResetEndpoint : public parserFSM::Endpoint
{

  public:


@@ 29,6 27,6 @@ class FactoryResetEndpoint : public Endpoint
    {
        debugName = "FactoryResetEndpoint";
    }
    auto handle(Context &context) -> void override;
    auto makeFactoryReset(Context &context) -> bool;
    auto handle(parserFSM::Context &context) -> void override;
    auto makeFactoryReset(parserFSM::Context &context) -> bool;
};

M module-services/service-desktop/endpoints/filesystem/FilesystemEndpoint.cpp => module-services/service-desktop/endpoints/filesystem/FilesystemEndpoint.cpp +3 -1
@@ 6,6 6,8 @@
#include "service-desktop/ServiceDesktop.hpp"
#include <purefs/filesystem_paths.hpp>

using namespace parserFSM;

auto FilesystemEndpoint::handle(Context &context) -> void
{
    LOG_DEBUG("handle");


@@ 68,4 70,4 @@ auto FilesystemEndpoint::run(Context &context) -> sys::ReturnCodes

    MessageHandler::putToSendQueue(context.createSimpleResponse());
    return returnCode;
}
\ No newline at end of file
}

M module-services/service-desktop/endpoints/filesystem/FilesystemEndpoint.hpp => module-services/service-desktop/endpoints/filesystem/FilesystemEndpoint.hpp +4 -6
@@ 6,14 6,12 @@
#include <module-services/service-desktop/endpoints/Endpoint.hpp>
#include "Service/Service.hpp"

using namespace parserFSM;

class FilesystemEndpoint : public Endpoint
class FilesystemEndpoint : public parserFSM::Endpoint
{
  public:
    FilesystemEndpoint(sys::Service *ownerServicePtr) : Endpoint(ownerServicePtr)
    {}
    auto handle(Context &context) -> void override;
    auto run(Context &context) -> sys::ReturnCodes;
    auto getUpdates(Context &context) -> sys::ReturnCodes;
    auto handle(parserFSM::Context &context) -> void override;
    auto run(parserFSM::Context &context) -> sys::ReturnCodes;
    auto getUpdates(parserFSM::Context &context) -> sys::ReturnCodes;
};

M module-services/service-desktop/endpoints/messages/MessagesEndpoint.hpp => module-services/service-desktop/endpoints/messages/MessagesEndpoint.hpp +4 -6
@@ 21,18 21,16 @@ namespace sys
    class Service;
} // namespace sys

using namespace parserFSM;

class MessagesEndpoint : public Endpoint
class MessagesEndpoint : public parserFSM::Endpoint
{
  private:
    std::shared_ptr<MessageHelper> helper;
    std::shared_ptr<parserFSM::MessageHelper> helper;

  public:
    MessagesEndpoint(sys::Service *_ownerServicePtr) : Endpoint(_ownerServicePtr)
    {
        debugName = "MessagesEndpoint";
        helper    = std::make_shared<MessageHelper>(ownerServicePtr);
        helper    = std::make_shared<parserFSM::MessageHelper>(ownerServicePtr);
    }
    auto handle(Context &context) -> void override;
    auto handle(parserFSM::Context &context) -> void override;
};

M module-services/service-desktop/endpoints/restore/RestoreEndpoint.cpp => module-services/service-desktop/endpoints/restore/RestoreEndpoint.cpp +2 -0
@@ 14,6 14,8 @@

#include <memory>

using namespace parserFSM;

auto RestoreEndpoint::handle(Context &context) -> void
{
    if (context.getMethod() == parserFSM::http::Method::post) {

M module-services/service-desktop/endpoints/restore/RestoreEndpoint.hpp => module-services/service-desktop/endpoints/restore/RestoreEndpoint.hpp +2 -4
@@ 16,14 16,12 @@ namespace sys
    class Service;
} // namespace sys

using namespace parserFSM;

class RestoreEndpoint : public Endpoint
class RestoreEndpoint : public parserFSM::Endpoint
{
  public:
    RestoreEndpoint(sys::Service *ownerServicePtr) : Endpoint(ownerServicePtr)
    {
        debugName = "RestoreEndpoint";
    }
    auto handle(Context &context) -> void override;
    auto handle(parserFSM::Context &context) -> void override;
};

M module-services/service-desktop/endpoints/update/UpdateEndpoint.cpp => module-services/service-desktop/endpoints/update/UpdateEndpoint.cpp +2 -0
@@ 17,6 17,8 @@
#include <filesystem>
#include <memory>

using namespace parserFSM;

auto UpdateEndpoint::handle(Context &context) -> void
{
    switch (context.getMethod()) {

M module-services/service-desktop/endpoints/update/UpdateEndpoint.hpp => module-services/service-desktop/endpoints/update/UpdateEndpoint.hpp +4 -6
@@ 20,9 20,7 @@ namespace sys
    class Service;
} // namespace sys

using namespace parserFSM;

class UpdateEndpoint : public Endpoint
class UpdateEndpoint : public parserFSM::Endpoint
{

  public:


@@ 30,7 28,7 @@ class UpdateEndpoint : public Endpoint
    {
        debugName = "UpdateEndpoint";
    }
    auto handle(Context &context) -> void override;
    auto run(Context &context) -> sys::ReturnCodes;
    auto getUpdates(Context &context) -> sys::ReturnCodes;
    auto handle(parserFSM::Context &context) -> void override;
    auto run(parserFSM::Context &context) -> sys::ReturnCodes;
    auto getUpdates(parserFSM::Context &context) -> sys::ReturnCodes;
};

M module-services/service-desktop/parser/MessageHandler.cpp => module-services/service-desktop/parser/MessageHandler.cpp +3 -3
@@ 23,7 23,7 @@ using namespace parserFSM;

xQueueHandle MessageHandler::sendQueue;

MessageHandler::MessageHandler(std::string &message, sys::Service *OwnerService) : OwnerServicePtr(OwnerService)
MessageHandler::MessageHandler(const std::string &message, sys::Service *OwnerService) : OwnerServicePtr(OwnerService)
{
    try {
        messageJson = json11::Json::parse(message, JsonErrorMsg);


@@ 53,10 53,10 @@ void MessageHandler::processMessage()
    }
}

void MessageHandler::putToSendQueue(const std::string msg)
void MessageHandler::putToSendQueue(const std::string &msg)
{
    if (uxQueueSpacesAvailable(sendQueue) != 0) {
        auto *responseString = new std::string(msg);
        auto responseString = new std::string(msg);
        xQueueSend(sendQueue, &responseString, portMAX_DELAY);
    }
}

M module-services/service-desktop/parser/MessageHandler.hpp => module-services/service-desktop/parser/MessageHandler.hpp +14 -11
@@ 24,29 24,32 @@ namespace parserFSM
{
    class MessageHandler
    {
        static xQueueHandle sendQueue;

        json11::Json messageJson;
        std::string JsonErrorMsg;
        sys::Service *OwnerServicePtr = nullptr;

      public:
        MessageHandler(std::string &message, sys::Service *OwnerService);
        static xQueueHandle sendQueue;
        MessageHandler(const std::string &message, sys::Service *OwnerService);

        bool isJSONNull()
        [[nodiscard]] auto isJSONNull() const -> bool
        {
            return messageJson.is_null();
        };
        bool isValid()
        [[nodiscard]] auto isValid() const noexcept -> bool
        {
            return JsonErrorMsg.empty();
        }
        std::string &getErrorString()
        [[nodiscard]] auto getErrorString() const -> const std::string &
        {
            return JsonErrorMsg;
        };
        void processMessage();
        static void putToSendQueue(const std::string msg);

      private:
        json11::Json messageJson;
        std::string JsonErrorMsg;
        sys::Service *OwnerServicePtr = nullptr;
        static void putToSendQueue(const std::string &msg);
        static void setSendQueueHandle(xQueueHandle handle)
        {
            sendQueue = handle;
        }
    };
} // namespace parserFSM

M module-services/service-desktop/parser/ParserFSM.cpp => module-services/service-desktop/parser/ParserFSM.cpp +23 -23
@@ 28,10 28,10 @@ using namespace parserFSM;
StateMachine::StateMachine(sys::Service *OwnerService) : OwnerServicePtr(OwnerService)
{}

void StateMachine::processMessage(std::string &msg)
void StateMachine::processMessage(std::string &&msg)
{
    receivedMsgPtr = &msg;
    LOG_DEBUG("Msg: %s", receivedMsgPtr->c_str());
    receivedMsg = std::move(msg);
    LOG_DEBUG("Msg: %s", receivedMsg.c_str());

    switch (state) {
    case State::ReceivedPayload:


@@ 58,20 58,20 @@ void StateMachine::parseHeader()
    header.clear();
    payloadLength = 0;

    auto messageStart = receivedMsgPtr->find(message::endpointChar);
    auto messageStart = receivedMsg.find(message::endpointChar);
    if (messageStart == std::string::npos) {
        LOG_ERROR("This is not a valid endpoint message! Type=%c", receivedMsgPtr->at(0));
        LOG_ERROR("This is not a valid endpoint message! Type=%c", receivedMsg.at(0));
        return;
    }

    if (receivedMsgPtr->size() < message::size_header) // header divided in few parts
    if (receivedMsg.size() < message::size_header) // header divided in few parts
    {
        state = State::ReceivedPartialHeader;
        header.append(*receivedMsgPtr); // append to whole header string
        header.append(receivedMsg); // append to whole header string
        return;
    }

    header        = message::getHeader(*receivedMsgPtr);
    header        = message::getHeader(receivedMsg);
    payloadLength = message::calcPayloadLength(header);
    if (payloadLength == 0) // failed to obtain payload length from msg
    {


@@ 82,7 82,7 @@ void StateMachine::parseHeader()

    LOG_DEBUG("Payload length: %lu", payloadLength);

    message::removeHeader(*receivedMsgPtr);
    message::removeHeader(receivedMsg);
    parseNewMessage();
}



@@ 91,39 91,39 @@ void StateMachine::parsePartialHeader()
    auto previousHeaderLength = header.size();
    auto missingHeaderLength  = message::size_header - previousHeaderLength;

    if (receivedMsgPtr->size() >= missingHeaderLength) // rest of the message is here
    if (receivedMsg.size() >= missingHeaderLength) // rest of the message is here
    {
        header.append(receivedMsgPtr->substr(0, missingHeaderLength));
        header.append(receivedMsg.substr(0, missingHeaderLength));
        LOG_DEBUG("Header: %s\n", header.c_str());
        payloadLength = message::calcPayloadLength(header);

        LOG_DEBUG("Payload length: %lu\n", payloadLength);
        message::eraseFront(*receivedMsgPtr, missingHeaderLength);
        message::eraseFront(receivedMsg, missingHeaderLength);

        parseNewMessage();
    }
    else // the message is even longer :(
    {
        header.append(*receivedMsgPtr);
        header.append(receivedMsg);
    }
}

void StateMachine::parseNewMessage()
{
    if (receivedMsgPtr->size() >= payloadLength) {
    if (receivedMsg.size() >= payloadLength) {

        payload = message::extractPayload(*receivedMsgPtr, payloadLength);
        payload = message::extractPayload(receivedMsg, payloadLength);

        parsePayload();

        if (receivedMsgPtr->size() > payloadLength) { // contains part of new header
            message::eraseFront(*receivedMsgPtr, payloadLength);
        if (receivedMsg.size() > payloadLength) { // contains part of new header
            message::eraseFront(receivedMsg, payloadLength);
            parseHeader();
        }
    }
    else // message divided in 2 or more packets
    {
        payload = receivedMsgPtr->substr(0, std::string::npos); // take rest of the message
        payload = receivedMsg.substr(0, std::string::npos); // take rest of the message
        state   = State::ReceivedPartialPayload;
    }
}


@@ 133,20 133,20 @@ void StateMachine::parsePartialMessage()
    auto previousPayloadLength = payload.size();
    auto missingPayloadLength  = payloadLength - previousPayloadLength;

    if (receivedMsgPtr->size() >= missingPayloadLength) // rest of the message is here
    if (receivedMsg.size() >= missingPayloadLength) // rest of the message is here
    {
        payload.append(message::extractPayload(*receivedMsgPtr, missingPayloadLength));
        payload.append(message::extractPayload(receivedMsg, missingPayloadLength));

        parsePayload();

        if (receivedMsgPtr->size() > missingPayloadLength) {
            message::eraseFront(*receivedMsgPtr, missingPayloadLength);
        if (receivedMsg.size() > missingPayloadLength) {
            message::eraseFront(receivedMsg, missingPayloadLength);
            parseHeader();
        }
    }
    else // the message is even longer
    {
        payload.append(*receivedMsgPtr);
        payload.append(receivedMsg);
    }
}


M module-services/service-desktop/parser/ParserFSM.hpp => module-services/service-desktop/parser/ParserFSM.hpp +6 -6
@@ 23,21 23,21 @@ namespace parserFSM
    class StateMachine
    {
      public:
        StateMachine(sys::Service *OwnerService);
        void processMessage(std::string &msg);
        State getCurrentState()
        explicit StateMachine(sys::Service *OwnerService);
        void processMessage(std::string &&msg);
        [[nodiscard]] auto getCurrentState() const noexcept -> State
        {
            return state;
        };

        void setState(const parserFSM::State newState)
        void setState(const parserFSM::State newState) noexcept
        {
            state = newState;
        }

      private:
        std::string *receivedMsgPtr = nullptr;
        parserFSM::State state      = State::NoMsg;
        std::string receivedMsg;
        parserFSM::State state = State::NoMsg;
        std::string payload;
        std::string header;
        unsigned long payloadLength   = 0;

M module-services/service-desktop/service-desktop/DesktopMessages.hpp => module-services/service-desktop/service-desktop/DesktopMessages.hpp +1 -1
@@ 71,7 71,7 @@ namespace sdesktop
        class Event
        {
          protected:
            Context context;
            parserFSM::Context context;

          public:
            void send();

M module-services/service-desktop/tests/unittest.cpp => module-services/service-desktop/tests/unittest.cpp +25 -21
@@ 68,76 68,80 @@ using namespace parserFSM;
TEST_CASE("Parser Test")
{
    StateMachine parser(nullptr);
    std::string testMessage("#00000");

    SECTION("Parse message with divided header and payload")
    {
        parser.processMessage(testMessage);
        std::string testMessage("#00000");
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::ReceivedPartialHeader);

        testMessage = R"(0050{"endpo)";
        parser.processMessage(testMessage);
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::ReceivedPartialPayload);

        testMessage = R"(int":1, "method":1, "body":{"test":"test"}})";
        parser.processMessage(testMessage);
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::ReceivedPayload);
    }

    SECTION("Parse whole message")
    {
        testMessage = R"(#000000050{"endpoint":1, "method":1, "body":{"test":"test"}})";
        parser.processMessage(testMessage);
        std::string testMessage = R"(#000000050{"endpoint":1, "method":1, "body":{"test":"test"}})";
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::ReceivedPayload);
    }

    SECTION("Parse message with start char detached from mesage")
    {
        testMessage = R"(#)";
        parser.processMessage(testMessage);
        std::string testMessage = R"(#)";
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::ReceivedPartialHeader);

        testMessage = R"(000000050{"en)";
        parser.processMessage(testMessage);
        testMessage = R"(000000050{"en)";
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::ReceivedPartialPayload);

        testMessage = R"(dpoint":1, "method":1, "body":{"test":"test"}})";
        parser.processMessage(testMessage);
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::ReceivedPayload);
    }

    SECTION("Parse message with beginning of another one")
    {
        testMessage = R"(#000000050{"endpoint":1, "method":1, "body":{"test":"test"}}#000000050{"end)";
        parser.processMessage(testMessage);
        std::string testMessage = R"(#000000050{"endpoint":1, "method":1, "body":{"test":"test"}}#000000050{"end)";
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::ReceivedPartialPayload);

        testMessage = R"(point":1, "method":1, "body":{"test":"test"}})";
        parser.processMessage(testMessage);
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::ReceivedPayload);
    }
    SECTION("Parse junk message")
    {
        testMessage = R"({"address": "6 Czeczota St.\n02600 Warsaw"})";
        parser.processMessage(testMessage);
        std::string testMessage = R"({"address": "6 Czeczota St.\n02600 Warsaw"})";
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::NoMsg);
    }
    SECTION("Parse message with incorrect header length")
    {
        testMessage = R"(#000000072{"endpoint":7, "method":2, "uuid":3, "body":{"threadID":1,"unread":false}})";
        parser.processMessage(testMessage);
        std::string testMessage =
            R"(#000000072{"endpoint":7, "method":2, "uuid":3, "body":{"threadID":1,"unread":false}})";
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::NoMsg);
    }
    SECTION("Parse message with damaged json ")
    {
        testMessage = R"(#000000074{"endpoint":7, "method":2, "uuid":3, "bo}}dy":{"threadID":1,"unread":false)";
        parser.processMessage(testMessage);
        std::string testMessage =
            R"(#000000074{"endpoint":7, "method":2, "uuid":3, "bo}}dy":{"threadID":1,"unread":false)";
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::NoMsg);
    }
    SECTION("Parse message with damaged json and incorrect header length")
    {
        testMessage = R"(#000000072{"endpoint":7, "method":2, "uuid":3, "bo}}dy":{"threadID":1,"unread":false)";
        parser.processMessage(testMessage);
        std::string testMessage =
            R"(#000000072{"endpoint":7, "method":2, "uuid":3, "bo}}dy":{"threadID":1,"unread":false)";
        parser.processMessage(std::move(testMessage));
        REQUIRE(parser.getCurrentState() == State::NoMsg);
    }
}

M module-services/service-eink/EinkDisplay.cpp => module-services/service-eink/EinkDisplay.cpp +2 -2
@@ 85,8 85,8 @@ namespace service::eink

    EinkBpp_e EinkDisplay::getCurrentBitsPerPixelFormat() const noexcept
    {
        if (waveformSettings.mode == EinkWaveformDU2) {
            return Eink1Bpp;
        if ((waveformSettings.mode == EinkWaveformA2) || (waveformSettings.mode == EinkWaveformDU2)) {
            return Eink4Bpp; /// this should be 1Bpp, but the OS is not ready for this
        }
        return Eink4Bpp;
    }

M module-services/service-eink/board/linux/renderer/CMakeLists.txt => module-services/service-eink/board/linux/renderer/CMakeLists.txt +3 -1
@@ 4,6 4,8 @@ project( service_renderer VERSION 1.0
	DESCRIPTION "GTK application for showing draw buffer."
	LANGUAGES CXX )

include(Utils)

find_package(PkgConfig REQUIRED)
pkg_check_modules(GTKMM REQUIRED gtkmm-3.0)



@@ 14,7 16,7 @@ add_executable( ${PROJECT_NAME}
    ${CMAKE_CURRENT_SOURCE_DIR}/src/RArea.hpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/RWindow.hpp )

install(TARGETS ${PROJECT_NAME} DESTINATION "./")
install(TARGETS ${PROJECT_NAME} DESTINATION "./" COMPONENT Standalone)

target_link_libraries( ${PROJECT_NAME}  ${GTKMM_LIBRARIES}  )
target_include_directories(${PROJECT_NAME} PUBLIC ${GTKMM_LIBRARY_DIRS} )

M module-services/service-evtmgr/CMakeLists.txt => module-services/service-evtmgr/CMakeLists.txt +2 -2
@@ 7,9 7,9 @@ set(SOURCES
        alarm/EventManagerAlarm.cpp
        api/EventManagerServiceAPI.cpp
        messages/Message.cpp
        screen-light-control/ScreenLightControl.cpp
        screen-light-control/ControlFunctions.cpp
        battery-level-check/BatteryLevelCheck.cpp
        screen-light-control/ControlFunctions.cpp
        screen-light-control/ScreenLightControl.cpp
)

add_library(${PROJECT_NAME} STATIC ${SOURCES})

M module-services/service-evtmgr/EventManager.cpp => module-services/service-evtmgr/EventManager.cpp +20 -13
@@ 2,13 2,15 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "service-evtmgr/BatteryMessages.hpp"
#include "service-evtmgr/Constants.hpp"
#include "service-evtmgr/EVMessages.hpp"
#include "service-evtmgr/EventManager.hpp"
#include "service-evtmgr/KbdMessage.hpp"
#include "service-evtmgr/ScreenLightControlMessage.hpp"
#include "service-evtmgr/Constants.hpp"
#include "service-evtmgr/EventManager.hpp"
#include "service-evtmgr/WorkerEvent.hpp"
#include "screen-light-control/ScreenLightControl.hpp"

#include "battery-level-check/BatteryLevelCheck.hpp"
#include "screen-light-control/ScreenLightControl.hpp"

#include <BaseInterface.hpp>
#include <MessageType.hpp>


@@ 39,7 41,8 @@
#include <module-apps/messages/AppMessage.hpp>
#include <SystemManager/messages/CpuFrequencyMessage.hpp>

EventManager::EventManager(const std::string &name) : sys::Service(name)
EventManager::EventManager(const std::string &name)
    : sys::Service(name), screenLightControl(std::make_unique<screen_light_control::ScreenLightControl>(this))
{
    LOG_INFO("[%s] Initializing", name.c_str());
    alarmTimestamp = 0;


@@ 261,12 264,6 @@ sys::ReturnCodes EventManager::InitHandler()
        return response;
    });

    connect(sevm::ScreenLightControlMessage(sevm::screen_light_control::Action::turnOff), [&](sys::Message *msgl) {
        auto request = static_cast<sevm::ScreenLightControlMessage *>(msgl);
        sevm::screen_light_control::processRequest(request->action, request->parameters);
        return std::make_shared<sys::ResponseMessage>();
    });

    connect(sevm::BatterySetCriticalLevel(0), [&](sys::Message *msgl) {
        auto request = static_cast<sevm::BatterySetCriticalLevel *>(msgl);
        battery_level_check::setBatteryCriticalLevel(request->criticalLevel);


@@ 278,6 275,19 @@ sys::ReturnCodes EventManager::InitHandler()
        return std::make_shared<sys::ResponseMessage>();
    });

    connect(sevm::ScreenLightControlMessage(), [&](sys::Message *msgl) {
        auto *m = dynamic_cast<sevm::ScreenLightControlMessage *>(msgl);
        screenLightControl->processRequest(m->action, m->parameters);
        return std::make_shared<sys::ResponseMessage>();
    });

    connect(sevm::ScreenLightControlRequestParameters(), [&](sys::Message *msgl) {
        screen_light_control::Parameters params = {screenLightControl->getBrightnessValue()};
        auto msg                                = std::make_shared<sevm::ScreenLightControlParametersResponse>(
            screenLightControl->getLightState(), screenLightControl->getAutoModeState(), params);
        return msg;
    });

    // initialize keyboard worker
    EventWorker = std::make_unique<WorkerEvent>(this);



@@ 312,14 322,12 @@ sys::ReturnCodes EventManager::InitHandler()

    EventWorker->init(list);
    EventWorker->run();
    sevm::screen_light_control::init(this);

    return sys::ReturnCodes::Success;
}

sys::ReturnCodes EventManager::DeinitHandler()
{
    sevm::screen_light_control::deinit();
    EventWorker->close();
    EventWorker.reset();
    EventWorker = nullptr;


@@ 344,7 352,6 @@ sys::ReturnCodes EventManager::SwitchPowerModeHandler(const sys::ServicePowerMod

bool EventManager::messageSetApplication(sys::Service *sender, const std::string &applicationName)
{

    auto msg = std::make_shared<sevm::EVMFocusApplication>(applicationName);
    return sys::Bus::SendUnicast(msg, service::name::evt_manager, sender);
}

M module-services/service-evtmgr/WorkerEvent.cpp => module-services/service-evtmgr/WorkerEvent.cpp +13 -16
@@ 2,9 2,9 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "service-evtmgr/BatteryMessages.hpp"
#include "service-evtmgr/Constants.hpp"
#include "service-evtmgr/EVMessages.hpp"
#include "service-evtmgr/KbdMessage.hpp"
#include "service-evtmgr/Constants.hpp"
#include "service-evtmgr/WorkerEvent.hpp"
#include "battery-level-check/BatteryLevelCheck.hpp"



@@ 78,7 78,7 @@ bool WorkerEvent::handleMessage(uint32_t queueID)
        }

        if (bsp::headset::Handler(notification) == true) {
            bool state = bsp::headset::IsInserted();
            bool state   = bsp::headset::IsInserted();
            auto message = std::make_shared<AudioEventRequest>(audio::EventType::JackState,
                                                               state ? audio::Event::DeviceState::Connected
                                                                     : audio::Event::DeviceState::Disconnected);


@@ 91,28 91,25 @@ bool WorkerEvent::handleMessage(uint32_t queueID)
        if (!queue->Dequeue(&notification, 0)) {
            return false;
        }
        if (notification == static_cast<uint8_t>(bsp::batteryIRQSource::INTB)) {
        if (notification == static_cast<uint8_t>(bsp::battery_charger::batteryIRQSource::INTB)) {
            LOG_DEBUG("Battery INTB");
            const auto status = bsp::battery_getStatusRegister();
            if (status & static_cast<std::uint16_t>(bsp::batteryINTBSource::minVAlert)) {
            const auto status = bsp::battery_charger::getStatusRegister();
            if (status & static_cast<std::uint16_t>(bsp::battery_charger::batteryINTBSource::minVAlert)) {
                auto messageBrownout = std::make_shared<sevm::BatteryBrownoutMessage>();
                sys::Bus::SendUnicast(messageBrownout, service::name::system_manager, this->service);
            }
            if (status & static_cast<std::uint16_t>(bsp::batteryINTBSource::SOCOnePercentChange)) {
                std::uint8_t battLevel = 0;
                bsp::battery_getBatteryLevel(battLevel);
            if (status & static_cast<std::uint16_t>(bsp::battery_charger::batteryINTBSource::SOCOnePercentChange)) {
                bsp::battery_charger::StateOfCharge battLevel = bsp::battery_charger::getBatteryLevel();
                auto message = std::make_shared<sevm::BatteryLevelMessage>(battLevel, false);
                sys::Bus::SendUnicast(message, service::name::evt_manager, this->service);
                battery_level_check::checkBatteryLevelCritical();
            }
            bsp::battery_ClearAllIRQs();
            bsp::battery_charger::clearAllIRQs();
        }
        if (notification == static_cast<uint8_t>(bsp::batteryIRQSource::INOKB)) {
            bool status;
            bsp::battery_getChargeStatus(status);
            bsp::battery_ClearAllIRQs();
        if (notification == static_cast<uint8_t>(bsp::battery_charger::batteryIRQSource::INOKB)) {
            bsp::battery_charger::clearAllIRQs();
            auto message     = std::make_shared<sevm::BatteryPlugMessage>();
            message->plugged = status;
            message->plugged = bsp::battery_charger::getChargeStatus();
            sys::Bus::SendUnicast(message, service::name::evt_manager, this->service);
        }
    }


@@ 193,7 190,7 @@ bool WorkerEvent::init(std::list<sys::WorkerQueueInfo> queuesList)
    bsp::vibrator::init();
    bsp::keyboard_Init(queues[static_cast<int32_t>(WorkerEventQueues::queueKeyboardIRQ)]->GetQueueHandle());
    bsp::headset::Init(queues[static_cast<int32_t>(WorkerEventQueues::queueHeadsetIRQ)]->GetQueueHandle());
    bsp::battery_Init(queues[static_cast<int32_t>(WorkerEventQueues::queueBattery)]->GetQueueHandle());
    bsp::battery_charger::init(queues[static_cast<int32_t>(WorkerEventQueues::queueBattery)]->GetQueueHandle());
    bsp::rtc_Init(queues[static_cast<int32_t>(WorkerEventQueues::queueRTC)]->GetQueueHandle());
    bsp::cellular::init(queues[static_cast<int32_t>(WorkerEventQueues::queueCellular)]->GetQueueHandle());
    bsp::magnetometer::init(queues[static_cast<int32_t>(WorkerEventQueues::queueMagnetometerIRQ)]->GetQueueHandle());


@@ 216,7 213,7 @@ bool WorkerEvent::deinit(void)
    Worker::deinit();
    bsp::keyboard_Deinit();
    bsp::headset::Deinit();
    bsp::battery_Deinit();
    bsp::battery_charger::deinit();
    bsp::torch::deinit();
    bsp::keypad_backlight::deinit();
    bsp::eink_frontlight::deinit();

M module-services/service-evtmgr/doc/screen_light_control.md => module-services/service-evtmgr/doc/screen_light_control.md +2 -1
@@ 54,6 54,7 @@ Default value of &gamma; is 2.5 . For leds this factor could be in range 2.2-2.8

## Message API

`sevm::ScreenLightControlMessage` is used to control the module. It takes action and data structure as parameters. Set of actions is described in `sevm::screen_light_control::Action`.
`screen_light_control::ScreenLightControlMessage` is used to control the module. It takes action and data structure as parameters. Set of actions is described in `sevm::screen_light_control::Action`.
`screen_light_control::ScreenLightControlRequestParameters` us ised to request currently setup parameters for display light and sensor.

![](light_control_message_flow.svg "Message to light control")
\ No newline at end of file

M module-services/service-evtmgr/screen-light-control/ControlFunctions.cpp => module-services/service-evtmgr/screen-light-control/ControlFunctions.cpp +2 -2
@@ 4,7 4,7 @@
#include "ControlFunctions.hpp"
#include <cmath>

namespace sevm::screen_light_control::functions
namespace screen_light_control::functions
{
    namespace
    {


@@ 95,4 95,4 @@ namespace sevm::screen_light_control::functions
        }
    }

} // namespace sevm::screen_light_control::functions
} // namespace screen_light_control::functions

M module-services/service-evtmgr/screen-light-control/ControlFunctions.hpp => module-services/service-evtmgr/screen-light-control/ControlFunctions.hpp +2 -2
@@ 8,7 8,7 @@
#include <vector>
#include <memory>

namespace sevm::screen_light_control::functions
namespace screen_light_control::functions
{
    using BrightnessFunction =
        std::vector<std::pair<bsp::light_sensor::IlluminanceLux, bsp::eink_frontlight::BrightnessPercentage>>;


@@ 23,4 23,4 @@ namespace sevm::screen_light_control::functions

    void setFunctionFromPoints(const BrightnessFunction &points);

} // namespace sevm::screen_light_control::functions
} // namespace screen_light_control::functions

M module-services/service-evtmgr/screen-light-control/ScreenLightControl.cpp => module-services/service-evtmgr/screen-light-control/ScreenLightControl.cpp +143 -75
@@ 3,119 3,99 @@

#include "ScreenLightControl.hpp"

namespace sevm::screen_light_control
#include <Service/Message.hpp>
#include <Service/Service.hpp>
#include <Service/Timer.hpp>
#include <agents/settings/SystemSettings.hpp>

namespace screen_light_control
{
    namespace
    {
        constexpr inline auto CONTROL_TIMER_MS = 25;
        constexpr inline auto READOUT_TIMER_MS = 500;
        std::unique_ptr<sys::Timer> controlTimer;
        std::unique_ptr<sys::Timer> readoutTimer;

        bool automaticMode = false;
        bool lightOn       = false;

        void enableTimers()
        {
            controlTimer->connect([&](sys::Timer &) { controlTimerCallback(); });
            readoutTimer->connect([&](sys::Timer &) { readoutTimerCallback(); });
            controlTimer->start();
            readoutTimer->start();
        }

        void disableTimers()
        auto from_string(const std::string &str, bool def) -> bool
        {
            controlTimer->stop();
            readoutTimer->stop();
        }

        void setAutomaticModeParameters(const Parameters &params)
        {
            if (lightOn && automaticMode) {
                disableTimers();
            try {
                return std::stoi(str) == 0;
            }

            functions::setRampStep(100.0f *
                                   (static_cast<float>(CONTROL_TIMER_MS) / static_cast<float>(params.rampTimeMS)));
            functions::setHysteresis(params.brightnessHysteresis);
            functions::setFunctionFromPoints(params.functionPoints);

            if (lightOn && automaticMode) {
                enableTimers();
            catch (std::exception &) {
                return def;
            }
        }

        void turnOff()
        auto from_string(const std::string &str, float def) -> float
        {
            bsp::eink_frontlight::turnOff();
            bsp::light_sensor::standby();
            controlTimer->stop();
            readoutTimer->stop();
            lightOn = false;
        }

        void turnOn()
        {
            bsp::eink_frontlight::turnOn();
            bsp::light_sensor::wakeup();
            if (automaticMode) {
                enableTimers();
            try {
                return std::stof(str);
            }
            lightOn = true;
        }

        void enableAutomaticMode()
        {
            if (lightOn) {
                enableTimers();
            catch (std::exception &) {
                return def;
            }
            automaticMode = true;
        }

        void disableAutomaticMode()
        {
            disableTimers();
            automaticMode = false;
        }

    } // namespace

    void init(sys::Service *parent)
    ScreenLightControl::ScreenLightControl(sys::Service *parent)
        : settings(std::make_unique<settings::Settings>(parent))
    {
        controlTimer = std::make_unique<sys::Timer>("LightControlTimer", parent, CONTROL_TIMER_MS);
        readoutTimer = std::make_unique<sys::Timer>("LightSensorReadoutTimer", parent, READOUT_TIMER_MS);

        Parameters defaultParams;
        setAutomaticModeParameters(defaultParams);
        initFromSettings();
    }

    void deinit()
    ScreenLightControl::~ScreenLightControl()
    {
        disableTimers();
        controlTimer.reset();
        readoutTimer.reset();
    }

    void processRequest(Action action, const Parameters &params)
    void ScreenLightControl::initFromSettings()
    {
        settings->registerValueChange(settings::Brightness::brightnessLevel,
                                      [&](const std::string &value) { setBrightnessLevel(from_string(value, 0.0f)); });

        settings->registerValueChange(settings::Brightness::autoMode, [&](const std::string &value) {
            if (from_string(value, false)) {
                enableAutomaticMode();
            }
            else {
                disableAutomaticMode();
            }
        });

        settings->registerValueChange(settings::Brightness::autoMode, [&](const std::string &value) {
            if (from_string(value, false)) {
                turnOn();
            }
            else {
                turnOff();
            }
        });
    }

    void ScreenLightControl::processRequest(Action action, const Parameters &params)
    {
        switch (action) {
        case Action::turnOff:
            turnOff();
            setScreenLightSettings(settings::Brightness::state, lightOn);
            break;
        case Action::turnOn:
            turnOn();
            setScreenLightSettings(settings::Brightness::state, lightOn);
            break;
        case Action::enableAutomaticMode:
            enableAutomaticMode();
            setScreenLightSettings(settings::Brightness::autoMode, automaticMode);
            break;
        case Action::disableAutomaticMode:
            disableAutomaticMode();
            setScreenLightSettings(settings::Brightness::autoMode, automaticMode);
            break;
        case Action::setManualModeBrightness:
            bsp::eink_frontlight::setBrightness(params.manualModeBrightness);
            setBrightnessLevel(params.manualModeBrightness);
            setScreenLightSettings(settings::Brightness::brightnessLevel, params.manualModeBrightness);
            break;
        case Action::setGammaCorrectionFactor:
            bsp::eink_frontlight::setGammaFactor(params.gammaFactor);
            setGammaFactor(params.gammaFactor);
            break;
        case Action::setAutomaticModeParameters:
            setAutomaticModeParameters(params);


@@ 123,14 103,102 @@ namespace sevm::screen_light_control
        }
    }

    void controlTimerCallback()
    void ScreenLightControl::controlTimerCallback()
    {
        bsp::eink_frontlight::setBrightness(functions::brightnessRampOut());
    }

    void readoutTimerCallback()
    void ScreenLightControl::readoutTimerCallback()
    {
        functions::calculateBrightness(bsp::light_sensor::readout());
    }

} // namespace sevm::screen_light_control
    auto ScreenLightControl::getAutoModeState() const noexcept -> ScreenLightMode
    {
        return automaticMode;
    }

    auto ScreenLightControl::getLightState() const noexcept -> bool
    {
        return lightOn;
    }

    auto ScreenLightControl::getBrightnessValue() const noexcept -> bsp::eink_frontlight::BrightnessPercentage
    {
        return brightnessValue;
    }

    void ScreenLightControl::enableTimers()
    {
        controlTimer->connect([&](sys::Timer &) { controlTimerCallback(); });
        readoutTimer->connect([&](sys::Timer &) { readoutTimerCallback(); });
        controlTimer->start();
        readoutTimer->start();
    }

    void ScreenLightControl::disableTimers()
    {
        controlTimer->stop();
        readoutTimer->stop();
    }

    void ScreenLightControl::setAutomaticModeParameters(const Parameters &params)
    {
        if (lightOn && automaticMode == ScreenLightMode::Automatic) {
            disableTimers();
        }

        functions::setRampStep(100.0f * (static_cast<float>(CONTROL_TIMER_MS) / static_cast<float>(params.rampTimeMS)));
        functions::setHysteresis(params.brightnessHysteresis);
        functions::setFunctionFromPoints(params.functionPoints);

        if (lightOn && automaticMode == ScreenLightMode::Automatic) {
            enableTimers();
        }
    }

    void ScreenLightControl::enableAutomaticMode()
    {
        if (lightOn) {
            enableTimers();
        }
        automaticMode = ScreenLightMode::Automatic;
    }

    void ScreenLightControl::disableAutomaticMode()
    {
        disableTimers();
        automaticMode = ScreenLightMode::Manual;
    }

    void ScreenLightControl::turnOn()
    {
        bsp::eink_frontlight::turnOn();
        bsp::light_sensor::wakeup();
        if (automaticMode) {
            enableTimers();
        }
        lightOn = true;
    }

    void ScreenLightControl::setBrightnessLevel(bsp::eink_frontlight::BrightnessPercentage brightnessPercentage)
    {
        bsp::eink_frontlight::setBrightness(brightnessPercentage);
        brightnessValue = brightnessPercentage;
    }

    void ScreenLightControl::setGammaFactor(float gammaFactor)
    {
        bsp::eink_frontlight::setGammaFactor(gammaFactor);
        setScreenLightSettings(settings::Brightness::gammaFactor, gammaFactor);
    }

    void ScreenLightControl::turnOff()
    {
        bsp::eink_frontlight::turnOff();
        bsp::light_sensor::standby();
        controlTimer->stop();
        readoutTimer->stop();
        lightOn = false;
    }
} // namespace screen_light_control

M module-services/service-evtmgr/screen-light-control/ScreenLightControl.hpp => module-services/service-evtmgr/screen-light-control/ScreenLightControl.hpp +62 -10
@@ 3,13 3,26 @@

#pragma once

#include <service-db/service-db/Settings.hpp>
#include "ControlFunctions.hpp"
#include <Service/Timer.hpp>
#include <Utils.hpp>

namespace sys
{
    class Timer;
}

/// Screen light control algorithm. Automatic/Manual mode of operation.
/// Processing of ambient light sensor input to screen brightness output.
namespace sevm::screen_light_control
namespace screen_light_control
{
    /// Modes in which front light can operate
    enum ScreenLightMode
    {
        Automatic, /// Automally sets screen brightness based on sensor data
        Manual     /// Manually set brightness level
    };

    /// Set of actions to control the screen light
    enum class Action
    {


@@ 24,6 37,8 @@ namespace sevm::screen_light_control

    struct Parameters
    {
        static constexpr auto MAX_BRIGHTNESS = 100.0;

        /// Screen brightness 0-100% in manual mode
        bsp::eink_frontlight::BrightnessPercentage manualModeBrightness = 50.0f;
        /// Vector of points for screen brightness [%] in relation to ambient light [Lux] function. Points have to be in


@@ 37,16 52,53 @@ namespace sevm::screen_light_control
        float gammaFactor = 2.5f;
    };

    /// Initialization of screen light control
    /// @param 'parent' - pointer to parent sys::Service class
    void init(sys::Service *parent);
    /// Control screen light and keeps it's current state
    class ScreenLightControl
    {
      public:
        explicit ScreenLightControl(sys::Service *parent);
        ~ScreenLightControl();

        void processRequest(Action action, const Parameters &params);

    void deinit();
        [[nodiscard]] auto getLightState() const noexcept -> bool;
        [[nodiscard]] auto getAutoModeState() const noexcept -> ScreenLightMode;
        [[nodiscard]] auto getBrightnessValue() const noexcept -> bsp::eink_frontlight::BrightnessPercentage;

    void processRequest(Action action, const Parameters &params);
      private:
        void controlTimerCallback();
        void readoutTimerCallback();

    void controlTimerCallback();
        void enableTimers();
        void disableTimers();

    void readoutTimerCallback();
        void setAutomaticModeParameters(const Parameters &params);
        void setBrightnessLevel(bsp::eink_frontlight::BrightnessPercentage brightnessPercentage);
        void setGammaFactor(float gammaFactor);

        void turnOff();
        void turnOn();

        void enableAutomaticMode();
        void disableAutomaticMode();

        template <class T> void setScreenLightSettings(const std::string &varName, T value)
        {
            settings->setValue(varName, utils::to_string(value));
        }
        void initFromSettings();

        static constexpr inline auto CONTROL_TIMER_MS = 25;
        static constexpr inline auto READOUT_TIMER_MS = 500;

        std::unique_ptr<sys::Timer> controlTimer;
        std::unique_ptr<sys::Timer> readoutTimer;

        bool lightOn                                               = false;
        screen_light_control::ScreenLightMode automaticMode        = ScreenLightMode::Manual;
        bsp::eink_frontlight::BrightnessPercentage brightnessValue = 0.0;

        std::unique_ptr<settings::Settings> settings;
    };

} // namespace sevm::screen_light_control
} // namespace screen_light_control

M module-services/service-evtmgr/service-evtmgr/EVMessages.hpp => module-services/service-evtmgr/service-evtmgr/EVMessages.hpp +0 -13
@@ 5,7 5,6 @@

#include "KbdMessage.hpp"
#include "BatteryMessages.hpp"
#include <screen-light-control/ScreenLightControl.hpp>

#include <MessageType.hpp>
#include <Service/Message.hpp>


@@ 143,16 142,4 @@ namespace sevm
        bool success;
    };

    class ScreenLightControlMessage : public Message
    {
      public:
        ScreenLightControlMessage(screen_light_control::Action act,
                                  screen_light_control::Parameters params = screen_light_control::Parameters())
            : Message(MessageType::EVMScreenLightControlMessage), action(act), parameters(params)
        {}

        screen_light_control::Action action;
        screen_light_control::Parameters parameters;
    };

} /* namespace sevm*/

M module-services/service-evtmgr/service-evtmgr/EventManager.hpp => module-services/service-evtmgr/service-evtmgr/EventManager.hpp +3 -0
@@ 11,6 11,7 @@
#include <bsp/common.hpp>
#include <bsp/keyboard/key_codes.hpp>
#include <bsp/keypad_backlight/keypad_backlight.hpp>
#include <screen-light-control/ScreenLightControl.hpp>

#include <cstdint>
#include <memory>


@@ 40,6 41,8 @@ class EventManager : public sys::Service
    // flag set when there is alarm to handle
    bool alarmIsValid = false;

    std::unique_ptr<screen_light_control::ScreenLightControl> screenLightControl;

  public:
    EventManager(const std::string &name);
    ~EventManager();

A module-services/service-evtmgr/service-evtmgr/ScreenLightControlMessage.hpp => module-services/service-evtmgr/service-evtmgr/ScreenLightControlMessage.hpp +55 -0
@@ 0,0 1,55 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "module-services/service-evtmgr/screen-light-control/ScreenLightControl.hpp"

#include <Service/Message.hpp>
#include <Service/Service.hpp>
#include <utility>

namespace sevm
{
    class ScreenLightControlMessage : public sys::DataMessage
    {
      public:
        ScreenLightControlMessage() : sys::DataMessage(MessageType::ScreenLightControlAction)
        {}
        ScreenLightControlMessage(screen_light_control::Action act,
                                  screen_light_control::Parameters params = screen_light_control::Parameters())
            : sys::DataMessage(MessageType::ScreenLightControlAction), action(act), parameters(std::move(params))
        {}

        screen_light_control::Action action;
        screen_light_control::Parameters parameters;
    };

    class ScreenLightControlRequestParameters : public sys::DataMessage
    {
      public:
        ScreenLightControlRequestParameters() : sys::DataMessage(MessageType::ScreenLightControlParameters)
        {}
    };

    class ScreenLightControlParametersResponse : public sys::DataMessage
    {
      public:
        ScreenLightControlParametersResponse() : sys::DataMessage(MessageType::ScreenLightControlParametersResponse)
        {}

        ScreenLightControlParametersResponse(bool lightOn,
                                             screen_light_control::ScreenLightMode mode,
                                             screen_light_control::Parameters params)
            : sys::DataMessage(MessageType::ScreenLightControlParametersResponse), lightOn(lightOn), mode(mode),
              parameters(std::move(params))
        {}

        bool lightOn;
        screen_light_control::ScreenLightMode mode;
        screen_light_control::Parameters parameters;
    };
} // namespace sevm

M module-services/service-evtmgr/tests/test-ScreenLightControlFunctions.cpp => module-services/service-evtmgr/tests/test-ScreenLightControlFunctions.cpp +4 -3
@@ 6,7 6,7 @@

TEST_CASE("ScreenLightControlFunctions")
{
    using namespace sevm::screen_light_control::functions;
    using namespace screen_light_control::functions;
    constexpr auto controlTimerMS = 25;

    SECTION("Ramp an hysteresis test")


@@ 14,8 14,9 @@ TEST_CASE("ScreenLightControlFunctions")
        INFO("Setup");
        const unsigned int testRampTime                          = 500;
        const bsp::eink_frontlight::BrightnessPercentage testVal = 100.0f;
        BrightnessFunction functionPoints = BrightnessFunction({{0.0f, testVal}, {100.0f, 0.0f}});
        const float hysteresis            = 10.0f;
        screen_light_control::functions::BrightnessFunction functionPoints =
            BrightnessFunction({{0.0f, testVal}, {100.0f, 0.0f}});
        const float hysteresis = 10.0f;

        setRampStep(100.0f * (static_cast<float>(controlTimerMS) / static_cast<float>(testRampTime)));
        setHysteresis(hysteresis);

M module-services/service-fota/FotaUrcHandler.cpp => module-services/service-fota/FotaUrcHandler.cpp +2 -0
@@ 3,6 3,8 @@

#include "FotaUrcHandler.hpp"

using namespace at::urc;

void FotaUrcHandler::Handle(Qind &urc)
{
    if (urc.isFotaValid()) {

M module-services/service-fota/FotaUrcHandler.hpp => module-services/service-fota/FotaUrcHandler.hpp +11 -13
@@ 8,27 8,25 @@
#include <module-cellular/at/UrcHandler.hpp>
#include <module-cellular/at/UrcQind.hpp>

using namespace at::urc;

/**
 * ServiceFota helper for handling Urc messages
 */
class FotaUrcHandler : public UrcHandler
class FotaUrcHandler : public at::urc::UrcHandler
{
  public:
    FotaUrcHandler(FotaService::Service &fotaService) : fotaService(fotaService)
    {}

    void Handle(Qind &urc) final;
    virtual void Handle(Clip &urc){};
    virtual void Handle(Creg &urc){};
    virtual void Handle(Cmti &urc){};
    virtual void Handle(Cusd &urc){};
    virtual void Handle(Ctze &urc){};
    virtual void Handle(Cpin &urc){};
    virtual void Handle(Qiurc &urc){};
    virtual void Handle(PoweredDown &urc){};
    virtual void Handle(UrcResponse &urc){};
    void Handle(at::urc::Qind &urc) final;
    virtual void Handle(at::urc::Clip &urc){};
    virtual void Handle(at::urc::Creg &urc){};
    virtual void Handle(at::urc::Cmti &urc){};
    virtual void Handle(at::urc::Cusd &urc){};
    virtual void Handle(at::urc::Ctze &urc){};
    virtual void Handle(at::urc::Cpin &urc){};
    virtual void Handle(at::urc::Qiurc &urc){};
    virtual void Handle(at::urc::PoweredDown &urc){};
    virtual void Handle(at::urc::UrcResponse &urc){};

  private:
    FotaService::Service &fotaService;

M module-services/service-time/service-time/CalendarTimeEvents.hpp => module-services/service-time/service-time/CalendarTimeEvents.hpp +1 -1
@@ 27,7 27,7 @@ namespace stm
    {
      private:
        EventsRecord eventRecord;
        TimePoint startTP = TIME_POINT_INVALID;
        calendar::TimePoint startTP = TIME_POINT_INVALID;

      protected:
        const std::string timerName() override

M module-services/service-time/timeEvents/CalendarTimeEvents.cpp => module-services/service-time/timeEvents/CalendarTimeEvents.cpp +4 -3
@@ 29,6 29,7 @@ namespace sys

namespace stm
{
    using namespace std::chrono_literals;
    constexpr static auto eventTimerMinSkipInterval = 100ms;

    CalendarTimeEvents::CalendarTimeEvents(sys::Service *service) : TimeEvents(service)


@@ 36,8 37,8 @@ namespace stm

    bool CalendarTimeEvents::sendNextEventQuery()
    {
        TimePoint filterFrom = TimePointNow();
        TimePoint filterTill = filterFrom;
        calendar::TimePoint filterFrom = TimePointNow();
        calendar::TimePoint filterTill = filterFrom;
        if (startTP != TIME_POINT_INVALID) {
            filterFrom = std::min(startTP, filterFrom);
            filterTill = filterFrom;


@@ 64,7 65,7 @@ namespace stm
        }

        eventRecord   = records.at(0);
        startTP       = eventRecord.date_from - minutes{eventRecord.reminder};
        startTP       = eventRecord.date_from - std::chrono::minutes{eventRecord.reminder};
        auto duration = eventRecord.date_from - std::chrono::minutes{eventRecord.reminder} - TimePointNow();
        if (duration.count() <= 0) {
            duration = std::chrono::milliseconds(eventTimerMinSkipInterval);

M module-sys/SystemManager/SystemManager.cpp => module-sys/SystemManager/SystemManager.cpp +2 -2
@@ 116,7 116,7 @@ namespace sys
        // pingPongTimerID = CreateTimer(Ticks::MsToTicks(pingInterval), true);
        // ReloadTimer(pingPongTimerID);

        cpuStatisticsTimer = std::make_unique<sys::Timer>("cpuStatistics", this, timerInitInterval.count());
        cpuStatisticsTimer = std::make_unique<sys::Timer>("cpuStatistics", this, constants::timerInitInterval.count());
        cpuStatisticsTimer->connect([&](sys::Timer &) { CpuStatisticsTimerHandler(); });
        cpuStatisticsTimer->start();
    }


@@ 354,7 354,7 @@ namespace sys
    {
        if (!cpuStatisticsTimerInit) {
            cpuStatisticsTimerInit = true;
            cpuStatisticsTimer->setInterval(timerPeriodInterval.count());
            cpuStatisticsTimer->setInterval(constants::timerPeriodInterval.count());
        }

        cpuStatistics->Update();

M module-sys/SystemManager/SystemManager.hpp => module-sys/SystemManager/SystemManager.hpp +6 -3
@@ 26,9 26,12 @@

namespace sys
{
    using namespace std::chrono_literals;
    inline constexpr std::chrono::milliseconds timerInitInterval{30s};
    inline constexpr std::chrono::milliseconds timerPeriodInterval{100ms};
    namespace constants
    {
        using namespace std::chrono_literals;
        inline constexpr std::chrono::milliseconds timerInitInterval{30s};
        inline constexpr std::chrono::milliseconds timerPeriodInterval{100ms};
    } // namespace constants

    enum class Code
    {

M module-utils/Utils.hpp => module-utils/Utils.hpp +7 -0
@@ 122,7 122,14 @@ namespace utils
                baseAsStr = "-0";
            }
        }

        auto fractionalPart = static_cast<unsigned long int>(roundl(frac));
        auto fractionalPartLength = std::to_string(fractionalPart).length();
        if (fractionalPartLength > precision) {
            base += 1;
            baseAsStr      = std::to_string(base);
            fractionalPart = 0;
        }
        if (fractionalPart == 0) {
            if (baseAsStr == "-0") {
                return "0";

M module-utils/ical/ParserICS.cpp => module-utils/ical/ParserICS.cpp +8 -5
@@ 446,7 446,7 @@ auto Event::timeStringFrom(const std::string &icalTime) const -> std::string
           getSecondsFromIcalTime(icalTime);
}

auto Event::TimePointFromIcalDate(const std::string &icalDateTime) const -> TimePoint
auto Event::TimePointFromIcalDate(const std::string &icalDateTime) const -> calendar::TimePoint
{
    std::string icalDate(getDateFromIcalFormat(icalDateTime));
    std::string icalTime(getTimeFromIcalFormat(icalDateTime));


@@ 459,7 459,7 @@ auto Event::TimePointFromIcalDate(const std::string &icalDateTime) const -> Time
    return TimePointFromString(dateTime.c_str());
}

auto Event::TimePointToIcalDate(const TimePoint &tp) const -> std::string
auto Event::TimePointToIcalDate(const calendar::TimePoint &tp) const -> std::string
{
    constexpr uint32_t bufferLimit = 16;
    auto time                      = TimePointToTimeT(tp);


@@ 541,7 541,10 @@ auto Event::validateUID(const std::string &UID) -> bool
    return validateDT(DTimestamp);
}

Event::Event(const std::string &summary, const TimePoint from, TimePoint till, const std::string &uid)
Event::Event(const std::string &summary,
             const calendar::TimePoint from,
             calendar::TimePoint till,
             const std::string &uid)
{
    if (summary.empty()) {
        isValid = false;


@@ 595,12 598,12 @@ auto Event::getSummary() const -> std::string
    return summary;
}

auto Event::getDTStartTimePoint() const -> TimePoint
auto Event::getDTStartTimePoint() const -> calendar::TimePoint
{
    return dtstart;
}

auto Event::getDTEndTimePoint() const -> TimePoint
auto Event::getDTEndTimePoint() const -> calendar::TimePoint
{
    return dtend;
}

M module-utils/ical/ParserICS.hpp => module-utils/ical/ParserICS.hpp +7 -7
@@ 91,8 91,8 @@ class Event
{
    std::string uid;
    std::string summary;
    TimePoint dtstart;
    TimePoint dtend;
    calendar::TimePoint dtstart;
    calendar::TimePoint dtend;

    auto isDate(const std::string &dt) -> bool;
    auto isTime(const std::string &dt) -> bool;


@@ 112,13 112,13 @@ class Event
    [[nodiscard]] auto dateStringFrom(const std::string &icalDate) const -> std::string;
    [[nodiscard]] auto timeStringFrom(const std::string &icalTime) const -> std::string;

    [[nodiscard]] auto TimePointFromIcalDate(const std::string &icalDateTime) const -> TimePoint;
    [[nodiscard]] auto TimePointToIcalDate(const TimePoint &tp) const -> std::string;
    [[nodiscard]] auto TimePointFromIcalDate(const std::string &icalDateTime) const -> calendar::TimePoint;
    [[nodiscard]] auto TimePointToIcalDate(const calendar::TimePoint &tp) const -> std::string;

  public:
    bool isValid = true;
    Event()      = default;
    Event(const std::string &summary, TimePoint from, TimePoint till, const std::string &uid);
    Event(const std::string &summary, calendar::TimePoint from, calendar::TimePoint till, const std::string &uid);

    void setUID(const std::string &property);
    void setSummary(const std::string &property);


@@ 127,8 127,8 @@ class Event

    [[nodiscard]] auto getUID() const -> std::string;
    [[nodiscard]] auto getSummary() const -> std::string;
    [[nodiscard]] auto getDTStartTimePoint() const -> TimePoint;
    [[nodiscard]] auto getDTEndTimePoint() const -> TimePoint;
    [[nodiscard]] auto getDTStartTimePoint() const -> calendar::TimePoint;
    [[nodiscard]] auto getDTEndTimePoint() const -> calendar::TimePoint;

    [[nodiscard]] auto getDTStartString() const -> std::string;
    [[nodiscard]] auto getDTEndString() const -> std::string;

M module-utils/time/TimeRangeParser.cpp => module-utils/time/TimeRangeParser.cpp +2 -2
@@ 19,8 19,8 @@ namespace utils::time
        return utils::localize.get(utils::time::Locale::getPM());
    }

    std::string TimeRangeParser::getCalendarTimeString(TimePoint startDate,
                                                       TimePoint endDate,
    std::string TimeRangeParser::getCalendarTimeString(calendar::TimePoint startDate,
                                                       calendar::TimePoint endDate,
                                                       Version version,
                                                       bool isMode24H)
    {

M module-utils/time/TimeRangeParser.hpp => module-utils/time/TimeRangeParser.hpp +2 -2
@@ 20,8 20,8 @@ namespace utils::time
        std::string AMPMtoString(bool isAm);

      public:
        std::string getCalendarTimeString(TimePoint startDate,
                                          TimePoint endDate,
        std::string getCalendarTimeString(calendar::TimePoint startDate,
                                          calendar::TimePoint endDate,
                                          Version version = Version::normal,
                                          bool isMode24H  = false);
    };

M module-utils/time/time_conversion.cpp => module-utils/time/time_conversion.cpp +1 -1
@@ 277,7 277,7 @@ namespace utils::time
        }
        else {
            return Timestamp::str(
                Locale::format(Locale::FormatTime12H)); // @TODO: M.G. FormatLocaleTime which actually works
                Locale::format(Locale::FormatTime12HShort)); // @TODO: M.G. FormatLocaleTime which actually works
        }
    }


M module-utils/time/time_locale.hpp => module-utils/time/time_locale.hpp +3 -1
@@ 21,7 21,7 @@ namespace utils
        {
            static const int num_days       = 7;
            static const int num_monts      = 12;
            static const int num_formatters = 4;
            static const int num_formatters = 5;
            // imo it would be nicer to have datetime locales in different json with thiny bit nicer and more effective
            // getters
            const std::array<std::string, num_days> daysShort = {


@@ 50,6 50,7 @@ namespace utils

            const std::array<std::string, num_formatters> time_formats{
                "locale_12hour_min",
                "locale_12hour_min_short",
                "locale_24hour_min",
                "locale_date_full",
                "locale_date_short",


@@ 90,6 91,7 @@ namespace utils
            enum TimeFormat
            {
                FormatTime12H = 0,     // H:M in 12h format
                FormatTime12HShort,    // H:M in 12h format, am/pm excluded
                FormatTime24H,         // H:M in 24h format
                FormatLocaleDateFull,  // format locale specified format
                FormatLocaleDateShort, // format locale specified format

M source/MessageType.hpp => source/MessageType.hpp +6 -3
@@ 177,8 177,6 @@ enum class MessageType
    EVMTorchStateMessage,
    // Keypad backlight control messages
    EVMKeypadBacklightMessage,
    // Screen frontlight control messages
    EVMScreenLightControlMessage,

    // cellular messages
    EVMGetBoard,


@@ 238,7 236,12 @@ enum class MessageType
    AntennaLockNotification,
    Settings,
    FileContentModified,
    FileIndexer
    FileIndexer,

    // Screen frontlight control messages
    ScreenLightControlAction,
    ScreenLightControlParameters,
    ScreenLightControlParametersResponse,
};

#endif /* SOURCE_MESSAGETYPE_HPP_ */

M tools/check_commit_messages.py => tools/check_commit_messages.py +1 -1
@@ 33,7 33,7 @@ def validate_commit(commit):
  empty_line = lines[1]
  body = ''.join(lines[2:]).strip()

  subject_format = r'^\[\w+-\d+\] .+[^.]$'
  subject_format = r'^\[EGD-\d+\] [A-Z].+[^.]$'
  if not re.match(subject_format, subject):
    errors.append(f'[{commit.hexsha}] invalid subject "{subject}", should match format "{subject_format}"')


A tools/clang-tidy.cmake => tools/clang-tidy.cmake +19 -0
@@ 0,0 1,19 @@
find_program(RUN_CLANG_TIDY_COMMAND NAMES run-clang-tidy)
if (NOT RUN_CLANG_TIDY_COMMAND)
	message(WARNING "run-clang-tidy can not be found.")
	return()
endif()

if (NOT CMAKE_EXPORT_COMPILE_COMMANDS)
	message(WARNING "Unable to run clang-tidy without the compile commands database.")
	return()
endif()

set(STATIC_ANALYSIS_OUTPUT_DIR "StaticAnalysis")

string(TIMESTAMP CURRENT_TIME)
set(CLANG_TIDY_OUTPUL_FILE "clang-tidy_${CURRENT_TIME}")

add_custom_target(clang-tidy
	COMMAND ${CMAKE_COMMAND} -E make_directory ${STATIC_ANALYSIS_OUTPUT_DIR}
	COMMAND ${RUN_CLANG_TIDY_COMMAND} -header-filter='.*' -p ${CMAKE_BINARY_DIR} > "${STATIC_ANALYSIS_OUTPUT_DIR}/${CLANG_TIDY_OUTPUL_FILE}")

M tools/download_asset.py => tools/download_asset.py +3 -2
@@ 52,7 52,7 @@ class Getter(object):
        try:
            gitConfigReader = self.gitRepo.config_reader()
            self.apitoken = gitConfigReader.get_value("user", "apitoken")
        except git.exc.NoOptionError as error:
        except: 
            pass

    def getGHLogin(self, args=None):


@@ 63,7 63,7 @@ class Getter(object):
        try:
            gitConfigReader = self.gitRepo.config_reader()
            self.ghLogin = gitConfigReader.get_value("user", "githublogin")
        except git.exc.NoOptionError as error:
        except:
            pass

    def findWorkDir(self):


@@ 117,6 117,7 @@ class Getter(object):
                    break
        if release is None:
            print("No release with tag:", args.tag)
        print("release:", release['tag_name'])
        assets = release['assets']
        self.downloadAsset(assets[0])