~aleteoryx/muditaos

75c12a82e56a2c30fafd9b178e414ba9a1fce66c — Lefucjusz 1 year, 10 months ago ddcc09c
[BH-1895][BH-1909][BH-1910] New database structure for custom sounds

* Added creation of /user/media/app/alarm
directory that will be used to store
custom alarm sounds.
* Implemented new database structure.
* Adapted Alarm, Bedtime, Pre-wake up and
Snooze to new database structure.
* Added removing custom alarm files during
factory reset.
* Added fallback alarm sound mechanism.
* Cleanups, unifications.
47 files changed, 677 insertions(+), 348 deletions(-)

M module-apps/apps-common/ApplicationCommon.hpp
M module-apps/apps-common/widgets/spinners/Model.hpp
M module-apps/apps-common/widgets/spinners/StringOutputSpinner.hpp
M module-services/service-db/include/service-db/SettingsScope.hpp
M module-services/service-fileindexer/InotifyHandler.cpp
M module-vfs/paths/include/purefs/filesystem_paths.hpp
M products/BellHybrid/CMakeLists.txt
M products/BellHybrid/alarms/src/actions/PlayAudioActions.cpp
M products/BellHybrid/alarms/src/actions/PlayAudioActions.hpp
M products/BellHybrid/apps/Application.cpp
M products/BellHybrid/apps/application-bell-bedtime/ApplicationBellBedtime.cpp
M products/BellHybrid/apps/application-bell-bedtime/CMakeLists.txt
M products/BellHybrid/apps/application-bell-bedtime/include/application-bell-bedtime/ApplicationBellBedtime.hpp
M products/BellHybrid/apps/application-bell-bedtime/models/BedtimeListItemProvider.cpp
M products/BellHybrid/apps/application-bell-bedtime/models/BedtimeListItemProvider.hpp
M products/BellHybrid/apps/application-bell-powernap/ApplicationBellPowerNap.cpp
M products/BellHybrid/apps/application-bell-powernap/presenter/PowerNapProgressPresenter.cpp
M products/BellHybrid/apps/application-bell-powernap/presenter/PowerNapProgressPresenter.hpp
M products/BellHybrid/apps/application-bell-relaxation/ApplicationBellRelaxation.cpp
M products/BellHybrid/apps/application-bell-settings/ApplicationBellSettings.cpp
M products/BellHybrid/apps/application-bell-settings/include/application-bell-settings/ApplicationBellSettings.hpp
M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/AlarmSettingsModel.cpp
M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/PrewakeUpSettingsModel.cpp
M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/PrewakeUpSettingsModel.hpp
M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/SnoozeSettingsModel.cpp
M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/SnoozeSettingsModel.hpp
M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/AlarmSettingsPresenter.hpp
M products/BellHybrid/apps/application-bell-settings/windows/alarm_settings/BellSettingsAlarmSettingsWindow.cpp
M products/BellHybrid/apps/common/include/common/models/AbstractSettingsModel.hpp
M products/BellHybrid/apps/common/include/common/models/AlarmSettingsModel.hpp
M products/BellHybrid/apps/common/include/common/models/BedtimeModel.hpp
M products/BellHybrid/apps/common/src/AlarmModel.cpp
M products/BellHybrid/apps/common/src/SoundsRepository.cpp
M products/BellHybrid/apps/common/src/models/BedtimeModel.cpp
M products/BellHybrid/apps/common/src/models/SettingsModel.cpp
M products/BellHybrid/apps/include/Application.hpp
M products/BellHybrid/paths/Paths.cpp
M products/BellHybrid/paths/Paths.hpp
A products/BellHybrid/services/db/databases/migration/settings_bell/current/1b034c28_Change_tone_names_to_tone_paths/.meta
A products/BellHybrid/services/db/databases/migration/settings_bell/current/1b034c28_Change_tone_names_to_tone_paths/devel.sql
A products/BellHybrid/services/db/databases/migration/settings_bell/current/1b034c28_Change_tone_names_to_tone_paths/down.sql
A products/BellHybrid/services/db/databases/migration/settings_bell/current/1b034c28_Change_tone_names_to_tone_paths/up.sql
M products/BellHybrid/services/db/include/db/SystemSettings.hpp
M products/BellHybrid/services/time/AlarmOperations.cpp
M products/BellHybrid/services/time/include/time/AlarmOperations.hpp
M scripts/lua/products/BellHybrid/scripts/factory.lua
M scripts/lua/share/paths.lua
M module-apps/apps-common/ApplicationCommon.hpp => module-apps/apps-common/ApplicationCommon.hpp +1 -1
@@ 40,7 40,7 @@
namespace app
{
    class WindowsStack;
    using UiNotificationFilter = std::function<bool(sys::Message *, const std::string &name)>;
    using UiNotificationFilter = std::function<bool(sys::Message *msg, const std::string &name)>;
} // namespace app

namespace db

M module-apps/apps-common/widgets/spinners/Model.hpp => module-apps/apps-common/widgets/spinners/Model.hpp +17 -17
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 32,12 32,12 @@ class Model
    Model(const range &r, Boundaries boundaries) : elements{r}, it{elements.begin()}, boundaries{boundaries}
    {}

    ElementType get() const
    auto get() const -> ElementType
    {
        return it == elements.end() ? ElementType{} : *it;
    }

    void set(ElementType val)
    auto set(ElementType val) -> void
    {
        const auto e = std::find_if(elements.begin(), elements.end(), [&val](const auto &i) { return i == val; });
        if (e != elements.end()) {


@@ 45,7 45,7 @@ class Model
        }
    }

    bool next()
    auto next() -> bool
    {
        bool ret{true};
        if (std::next(it) == elements.end()) {


@@ 62,7 62,7 @@ class Model
        return ret;
    }

    bool previous()
    auto previous() -> bool
    {
        bool ret{true};
        if (it == elements.begin()) {


@@ 79,7 79,7 @@ class Model
        return ret;
    }

    void set_range(range newRange)
    auto set_range(range newRange) -> void
    {
        if (elements != newRange) {
            elements = newRange;


@@ 87,17 87,17 @@ class Model
        }
    }

    [[nodiscard]] size_t size() const
    [[nodiscard]] auto size() const -> std::size_t
    {
        return elements.size();
    }

    [[nodiscard]] bool is_min() const
    [[nodiscard]] auto is_min() const -> bool
    {
        return it == elements.begin();
    }

    [[nodiscard]] bool is_max() const
    [[nodiscard]] auto is_max() const -> bool
    {
        return std::next(it) == elements.end();
    }


@@ 129,7 129,7 @@ class Model<ElementType, force, std::enable_if_t<std::is_fundamental_v<ElementTy
            ElementType max{};
            ElementType step{};

            bool operator!=(const range &oth) const
            constexpr auto operator!=(const range &oth) const -> bool
            {
                return min != oth.min || max != oth.max || step != oth.step;
            }


@@ 152,17 152,17 @@ class Model<ElementType, force, std::enable_if_t<std::is_fundamental_v<ElementTy
    Model(range &elements, Boundaries boundaries) : elements{elements}, value{elements.min}, boundaries{boundaries}
    {}

    ElementType get() const
    auto get() const -> ElementType
    {
        return value;
    }

    void set(ElementType val)
    auto set(ElementType val) -> void
    {
        value = val;
    }

    bool next()
    auto next() -> bool
    {
        bool ret{true};
        if (value >= elements.max) {


@@ 180,7 180,7 @@ class Model<ElementType, force, std::enable_if_t<std::is_fundamental_v<ElementTy
        return ret;
    }

    bool previous()
    auto previous() -> bool
    {
        bool ret{true};
        if (value <= elements.min) {


@@ 198,7 198,7 @@ class Model<ElementType, force, std::enable_if_t<std::is_fundamental_v<ElementTy
        return ret;
    }

    void set_range(range newRange)
    auto set_range(range newRange) -> void
    {
        if (elements != newRange) {
            elements = newRange;


@@ 206,12 206,12 @@ class Model<ElementType, force, std::enable_if_t<std::is_fundamental_v<ElementTy
        }
    }

    [[nodiscard]] bool is_min() const
    [[nodiscard]] auto is_min() const -> bool
    {
        return value == elements.min;
    }

    [[nodiscard]] bool is_max() const
    [[nodiscard]] auto is_max() const -> bool
    {
        return value == elements.max;
    }

M module-apps/apps-common/widgets/spinners/StringOutputSpinner.hpp => module-apps/apps-common/widgets/spinners/StringOutputSpinner.hpp +1 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 6,7 6,6 @@
#include <widgets/text/TextFixedSize.hpp>

#include <string>
#include <type_traits>

namespace gui
{

M module-services/service-db/include/service-db/SettingsScope.hpp => module-services/service-db/include/service-db/SettingsScope.hpp +2 -1
@@ 1,7 1,8 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, 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

M module-services/service-fileindexer/InotifyHandler.cpp => module-services/service-fileindexer/InotifyHandler.cpp +1 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <service-fileindexer/InotifyHandler.hpp>


@@ 188,5 188,4 @@ namespace service::detail
        }
        return true;
    }

} // namespace service::detail

M module-vfs/paths/include/purefs/filesystem_paths.hpp => module-vfs/paths/include/purefs/filesystem_paths.hpp +5 -5
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 26,13 26,13 @@ namespace purefs

    namespace file
    {
        constexpr inline auto boot_json    = "boot.json";
        constexpr inline auto os_bin       = "os.bin";
        constexpr inline auto version_json = "version.json";
        inline constexpr auto boot_json    = "boot.json";
        inline constexpr auto os_bin       = "os.bin";
        inline constexpr auto version_json = "version.json";
    } // namespace file

    namespace buffer
    {
        constexpr inline auto tar_buf = 1024;
        inline constexpr auto tar_buf = 1024;
    }
} // namespace purefs

M products/BellHybrid/CMakeLists.txt => products/BellHybrid/CMakeLists.txt +1 -1
@@ 92,7 92,7 @@ add_directories(
        TARGET create_user_directories
        PREFIX ${SYSROOT_PATH}/user/media/app
        DEPENDS system_directories_common
        DIRECTORIES relaxation
        DIRECTORIES relaxation alarm
)

if (${PROJECT_TARGET} STREQUAL "TARGET_RT1051")

M products/BellHybrid/alarms/src/actions/PlayAudioActions.cpp => products/BellHybrid/alarms/src/actions/PlayAudioActions.cpp +71 -36
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "PlayAudioActions.hpp"


@@ 11,96 11,131 @@
namespace alarms
{
    PlayAudioAction::PlayAudioAction(sys::Service &service,
                                     const std::filesystem::path &tonesDirPath,
                                     std::string_view toneSetting,
                                     audio::PlaybackType playbackType,
                                     std::optional<std::string_view> durationSetting)
        : service{service}, soundsRepository{tonesDirPath}, toneSetting{toneSetting}, durationSetting{durationSetting},
        : service{service}, toneSetting{toneSetting}, durationSetting{durationSetting},
          playbackType{playbackType}, settings{service::ServiceProxy{service.weak_from_this()}}
    {}

    bool PlayAudioAction::play(const std::filesystem::path &path, std::optional<std::chrono::minutes> duration)
    auto PlayAudioAction::play(const std::filesystem::path &path, std::optional<std::chrono::minutes> duration) -> bool
    {
        if (duration) {
            spawnTimer(*duration);
        if (duration.has_value()) {
            spawnTimer(duration.value());
        }
        const auto fadeInSettings = utils::getNumericValue<bool>(
            settings.getValue(bell::settings::Alarm::fadeActive, settings::SettingsScope::Global));
        const auto fadeInEnabled = (fadeInSettings && (playbackType == audio::PlaybackType::Alarm))
                                       ? audio::FadeIn::Enable
                                       : audio::FadeIn::Disable;
        return service.bus.sendUnicast(
            std::make_shared<service::AudioStartPlaybackRequest>(path, playbackType, fadeInEnabled),
            service::audioServiceName);

        auto msg = std::make_shared<service::AudioStartPlaybackRequest>(path, playbackType, fadeInEnabled);
        return service.bus.sendUnicast(std::move(msg), service::audioServiceName);
    }

    bool PlayAudioAction::turnOff()
    auto PlayAudioAction::turnOff() -> bool
    {
        detachTimer();
        auto stopPlaybackVec = std::vector<audio::PlaybackType>({playbackType});
        const auto msg       = std::make_shared<service::AudioStopRequest>(stopPlaybackVec);
        return service.bus.sendUnicast(msg, service::audioServiceName);

        auto msg = std::make_shared<service::AudioStopRequest>(std::move(stopPlaybackVec));
        return service.bus.sendUnicast(std::move(msg), service::audioServiceName);
    }
    bool PlayAudioAction::execute()

    auto PlayAudioAction::execute() -> bool
    {
        const auto tone = settings.getValue(toneSetting, settings::SettingsScope::Global);
        auto path = settings.getValue(toneSetting, settings::SettingsScope::Global);
        if (!std::filesystem::exists(path)) {
            const auto &fallbackPath = handleMissingFile();
            LOG_ERROR("File '%s' not found, falling back to default: '%s'", path.c_str(), fallbackPath.c_str());
            path = fallbackPath;
        }

        std::optional<std::chrono::minutes> duration{};
        if (durationSetting) {
            const auto durationStr = settings.getValue(*durationSetting, settings::SettingsScope::Global);
        if (durationSetting.has_value()) {
            const auto &durationStr = settings.getValue(durationSetting.value(), settings::SettingsScope::Global);
            duration.emplace(utils::getNumericValue<int>(durationStr));
        }

        return play(soundsRepository.titleToPath(tone).value_or(""), duration);
        return play(path, duration);
    }

    void PlayAudioAction::detachTimer()
    auto PlayAudioAction::detachTimer() -> void
    {
        if (timer.isValid()) {
            timer.stop();
            timer.reset();
        }
    }
    void PlayAudioAction::spawnTimer(std::chrono::minutes timeout)

    auto PlayAudioAction::spawnTimer(std::chrono::minutes timeout) -> void
    {
        constexpr auto timerName = "playDurationTimer";
        if (not timer.isValid()) {
        if (!timer.isValid()) {
            auto callback = [this](sys::Timer &) { turnOff(); };
            timer         = sys::TimerFactory::createSingleShotTimer(&service, timerName, timeout, callback);
        }
        timer.stop();
        timer.start();
    }

    auto PlayAudioAction::getFallbackTonePath() -> std::string
    {
        using namespace settings;
        using namespace bell::settings;

        if (toneSetting == Snooze::tonePath) {
            return settings.getValue(Snooze::toneFallbackPath, SettingsScope::Global);
        }
        if (toneSetting == PrewakeUp::tonePath) {
            return settings.getValue(PrewakeUp::toneFallbackPath, SettingsScope::Global);
        }
        if (toneSetting == Alarm::tonePath) {
            return settings.getValue(Alarm::toneFallbackPath, SettingsScope::Global);
        }
        if (toneSetting == Bedtime::tonePath) {
            return settings.getValue(Bedtime::toneFallbackPath, SettingsScope::Global);
        }
        return {};
    }

    auto PlayAudioAction::handleMissingFile() -> std::string
    {
        auto fallbackPath = getFallbackTonePath();
        if (fallbackPath.empty()) {
            LOG_ERROR("Fallback path not found! This should never really happen!");
        }
        else {
            settings.setValue(toneSetting, fallbackPath, settings::SettingsScope::Global);
        }
        return fallbackPath;
    }

    namespace factory
    {
        std::unique_ptr<PlayAudioAction> createPreWakeUpChimeAction(sys::Service &service)
        {
            return std::make_unique<PlayAudioAction>(service,
                                                     paths::audio::proprietary() / paths::audio::preWakeup(),
                                                     bell::settings::PrewakeUp::tone,
                                                     audio::PlaybackType::PreWakeUp);
            return std::make_unique<PlayAudioAction>(
                service, bell::settings::PrewakeUp::tonePath, audio::PlaybackType::PreWakeUp);
        }

        std::unique_ptr<PlayAudioAction> createSnoozeChimeAction(sys::Service &service)
        {
            return std::make_unique<PlayAudioAction>(service,
                                                     paths::audio::proprietary() / paths::audio::snooze(),
                                                     bell::settings::Snooze::tone,
                                                     audio::PlaybackType::Snooze);
            return std::make_unique<PlayAudioAction>(
                service, bell::settings::Snooze::tonePath, audio::PlaybackType::Snooze);
        }

        std::unique_ptr<PlayAudioAction> createAlarmToneAction(sys::Service &service)
        {
            /// Alarm duration is controlled from the main application's state machine
            return std::make_unique<PlayAudioAction>(service,
                                                     paths::audio::proprietary() / paths::audio::alarm(),
                                                     bell::settings::Alarm::tone,
                                                     audio::PlaybackType::Alarm);
            return std::make_unique<PlayAudioAction>(
                service, bell::settings::Alarm::tonePath, audio::PlaybackType::Alarm);
        }

        std::unique_ptr<PlayAudioAction> createBedtimeChimeAction(sys::Service &service)
        {
            return std::make_unique<PlayAudioAction>(service,
                                                     paths::audio::proprietary() / paths::audio::bedtimeReminder(),
                                                     bell::settings::Bedtime::tone,
                                                     audio::PlaybackType::Bedtime);
            return std::make_unique<PlayAudioAction>(
                service, bell::settings::Bedtime::tonePath, audio::PlaybackType::Bedtime);
        }
    } // namespace factory
} // namespace alarms

M products/BellHybrid/alarms/src/actions/PlayAudioActions.hpp => products/BellHybrid/alarms/src/actions/PlayAudioActions.hpp +12 -12
@@ 5,7 5,6 @@

#include "AbstractAlarmAction.hpp"
#include <audio/AudioMessage.hpp>
#include <common/SoundsRepository.hpp>
#include <service-db/Settings.hpp>
#include <Timers/TimerHandle.hpp>
#include <Service/Service.hpp>


@@ 18,22 17,23 @@ namespace alarms
    class PlayAudioAction : public AbstractAlarmAction
    {
      public:
        bool turnOff() override;
        bool execute() override;
        explicit PlayAudioAction(sys::Service &service,
                                 const std::filesystem::path &tonesDirPath,
                                 std::string_view toneSetting,
                                 audio::PlaybackType                             = audio::PlaybackType::Alarm,
                                 std::optional<std::string_view> durationSetting = {});
        PlayAudioAction(sys::Service &service,
                        std::string_view toneSetting,
                        audio::PlaybackType                             = audio::PlaybackType::Alarm,
                        std::optional<std::string_view> durationSetting = {});

        auto turnOff() -> bool override;
        auto execute() -> bool override;

      private:
        bool play(const std::filesystem::path &path, std::optional<std::chrono::minutes> duration = {});
        void spawnTimer(std::chrono::minutes timeout);
        void detachTimer();
        auto play(const std::filesystem::path &path, std::optional<std::chrono::minutes> duration = {}) -> bool;
        auto spawnTimer(std::chrono::minutes timeout) -> void;
        auto detachTimer() -> void;
        auto getFallbackTonePath() -> std::string;
        auto handleMissingFile() -> std::string;

        sys::Service &service;
        sys::TimerHandle timer;
        SimpleSoundsRepository soundsRepository;
        const std::string toneSetting;
        const std::optional<std::string> durationSetting;
        const audio::PlaybackType playbackType;

M products/BellHybrid/apps/Application.cpp => products/BellHybrid/apps/Application.cpp +7 -8
@@ 17,9 17,7 @@
#include <common/popups/BedtimeNotificationWindow.hpp>
#include <common/popups/ChargingNotificationWindow.hpp>
#include <apps-common/WindowsPopupFilter.hpp>
#include <service-time/AlarmMessage.hpp>
#include <service-evtmgr/KbdMessage.hpp>
#include <products/BellHybrid/keymap/include/keymap/KeyMap.hpp>

namespace app
{


@@ 27,15 25,16 @@ namespace app
                             std::string parent,
                             StatusIndicators statusIndicators,
                             StartInBackground startInBackground,
                             uint32_t stackDepth,
                             std::uint32_t stackDepth,
                             sys::ServicePriority priority)
        : ApplicationCommon(name, parent, statusIndicators, startInBackground, stackDepth, priority)
        : ApplicationCommon(
              std::move(name), std::move(parent), statusIndicators, startInBackground, stackDepth, priority)
    {
        getPopupFilter().addAppDependentFilter([&](const gui::PopupRequestParams &popupParams) {
            bool val = ((isCurrentWindow(gui::popup::resolveWindowName(gui::popup::ID::Reboot))) ||
                        (isCurrentWindow(gui::popup::resolveWindowName(gui::popup::ID::PowerOff))) ||
                        (isCurrentWindow(gui::BellTurnOffWindow::name)));
            if (val == true) {
            const bool val = ((isCurrentWindow(gui::popup::resolveWindowName(gui::popup::ID::Reboot))) ||
                              (isCurrentWindow(gui::popup::resolveWindowName(gui::popup::ID::PowerOff))) ||
                              (isCurrentWindow(gui::BellTurnOffWindow::name)));
            if (val) {
                LOG_ERROR("Block popup - as current window is in higher order popup");
            }
            return val ? gui::popup::FilterType::Ignore : gui::popup::FilterType::Show;

M products/BellHybrid/apps/application-bell-bedtime/ApplicationBellBedtime.cpp => products/BellHybrid/apps/application-bell-bedtime/ApplicationBellBedtime.cpp +17 -12
@@ 1,12 1,14 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "ApplicationBellBedtime.hpp"
#include "presenter/BellBedtimeWindowPresenter.hpp"
#include "windows/BellBedtimeWindow.hpp"
#include "common/models/BedtimeModel.hpp"
#include <common/windows/BellFinishedWindow.hpp>
#include "models/BedtimeListItemProvider.hpp"
#include <common/models/BedtimeModel.hpp>
#include <common/windows/BellFinishedWindow.hpp>
#include <common/SoundsRepository.hpp>
#include <Paths.hpp>

namespace app
{


@@ 14,8 16,8 @@ namespace app
                                                   std::string parent,
                                                   StatusIndicators statusIndicators,
                                                   StartInBackground startInBackground,
                                                   uint32_t stackDepth)
        : Application(name, parent, statusIndicators, startInBackground, stackDepth)
                                                   std::uint32_t stackDepth)
        : Application(std::move(name), std::move(parent), statusIndicators, startInBackground, stackDepth)
    {}

    sys::ReturnCodes ApplicationBellBedtime::InitHandler()


@@ 32,13 34,16 @@ namespace app

    void ApplicationBellBedtime::createUserInterface()
    {
        windowsFactory.attach(gui::name::window::main_window, [](ApplicationCommon *app, const std::string &) {
            auto audioModel   = std::make_unique<AudioModel>(app);
            auto bedtimeModel = std::make_unique<bell_bedtime::BedtimeModel>(app, *audioModel);
            auto provider     = std::make_shared<bell_bedtime::BedtimeListItemProvider>(std::move(bedtimeModel));
            auto presenter    = std::make_unique<bell_bedtime::BellBedtimeWindowPresenter>(provider);
            return std::make_unique<gui::BellBedtimeWindow>(app, std::move(presenter));
        });
        windowsFactory.attach(
            gui::name::window::main_window, [](ApplicationCommon *app, [[maybe_unused]] const std::string &name) {
                auto soundsRepository = std::make_unique<SimpleSoundsRepository>(paths::audio::proprietary() /
                                                                                 paths::audio::bedtimeReminder());
                auto audioModel       = std::make_unique<AudioModel>(app);
                auto bedtimeModel = std::make_unique<bell_bedtime::BedtimeModel>(app, *audioModel, *soundsRepository);
                auto provider     = std::make_shared<bell_bedtime::BedtimeListItemProvider>(std::move(bedtimeModel));
                auto presenter    = std::make_unique<bell_bedtime::BellBedtimeWindowPresenter>(provider);
                return std::make_unique<gui::BellBedtimeWindow>(app, std::move(presenter));
            });

        windowsFactory.attach(gui::window::bell_finished::defaultName,
                              [](ApplicationCommon *app, const std::string &name) {

M products/BellHybrid/apps/application-bell-bedtime/CMakeLists.txt => products/BellHybrid/apps/application-bell-bedtime/CMakeLists.txt +1 -1
@@ 27,7 27,7 @@ target_include_directories(application-bell-bedtime
target_link_libraries(application-bell-bedtime
    PRIVATE
        app
        bell::app-common
        bell::paths
        bell::db
        date::date
        service-appmgr

M products/BellHybrid/apps/application-bell-bedtime/include/application-bell-bedtime/ApplicationBellBedtime.hpp => products/BellHybrid/apps/application-bell-bedtime/include/application-bell-bedtime/ApplicationBellBedtime.hpp +2 -4
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 8,8 8,6 @@
namespace gui::window::name
{
    inline constexpr auto bellBedtime      = "BellBedtime";
    inline constexpr auto bellBedtimeOnOff = "bellBedtimeOnff";

} // namespace gui::window::name

namespace app


@@ 23,7 21,7 @@ namespace app
                                        std::string parent                  = "",
                                        StatusIndicators statusIndicators   = StatusIndicators{},
                                        StartInBackground startInBackground = {false},
                                        uint32_t stackDepth                 = 4096 * 2);
                                        std::uint32_t stackDepth            = 1024 * 8);

        auto InitHandler() -> sys::ReturnCodes override;


M products/BellHybrid/apps/application-bell-bedtime/models/BedtimeListItemProvider.cpp => products/BellHybrid/apps/application-bell-bedtime/models/BedtimeListItemProvider.cpp +2 -3
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "BedtimeListItemProvider.hpp"


@@ 44,7 44,7 @@ namespace app::bell_bedtime
        }
    }

    auto BedtimeListItemProvider::requestRecords(uint32_t offset, uint32_t limit) -> void
    auto BedtimeListItemProvider::requestRecords(std::uint32_t offset, std::uint32_t limit) -> void
    {
        setupModel(offset, limit);
        list->onProviderDataUpdate();


@@ 69,5 69,4 @@ namespace app::bell_bedtime
    {
        return internalData;
    }

} // namespace app::bell_bedtime

M products/BellHybrid/apps/application-bell-bedtime/models/BedtimeListItemProvider.hpp => products/BellHybrid/apps/application-bell-bedtime/models/BedtimeListItemProvider.hpp +3 -4
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 15,7 15,7 @@ namespace app::bell_bedtime
      public:
        explicit BedtimeListItemProvider(std::unique_ptr<AbstractBedtimeModel> &&model);
        auto getListItems() -> std::vector<gui::BellSideListItemWithCallbacks *>;
        auto requestRecords(uint32_t offset, uint32_t limit) -> void override;
        auto requestRecords(std::uint32_t offset, std::uint32_t limit) -> void override;
        [[nodiscard]] auto getItem(gui::Order order) -> gui::ListItem * override;
        [[nodiscard]] auto requestRecordsCount() -> unsigned int override;
        [[nodiscard]] auto getMinimalItemSpaceRequired() const -> unsigned int override;


@@ 23,9 23,8 @@ namespace app::bell_bedtime
        std::function<void()> onExit;

      private:
        void buildListItems();
        auto buildListItems() -> void;

        std::unique_ptr<AbstractBedtimeModel> model;
    };

} // namespace app::bell_bedtime

M products/BellHybrid/apps/application-bell-powernap/ApplicationBellPowerNap.cpp => products/BellHybrid/apps/application-bell-powernap/ApplicationBellPowerNap.cpp +0 -3
@@ 61,11 61,8 @@ namespace app
            [this](ApplicationCommon *app, [[maybe_unused]] const std::string &name) {
                auto timeModel       = std::make_unique<app::TimeModel>();
                auto frontlightModel = std::make_unique<powernap::PowerNapFrontlightModel>(this, powerNapAlarmDuration);
                auto soundsRepository =
                    std::make_unique<SimpleSoundsRepository>(paths::audio::proprietary() / paths::audio::alarm());
                auto presenter = std::make_unique<powernap::PowerNapProgressPresenter>(app,
                                                                                       settings.get(),
                                                                                       std::move(soundsRepository),
                                                                                       *audioModel,
                                                                                       std::move(timeModel),
                                                                                       std::move(frontlightModel),

M products/BellHybrid/apps/application-bell-powernap/presenter/PowerNapProgressPresenter.cpp => products/BellHybrid/apps/application-bell-powernap/presenter/PowerNapProgressPresenter.cpp +23 -26
@@ 18,22 18,20 @@ namespace

namespace app::powernap
{
    PowerNapProgressPresenter::PowerNapProgressPresenter(
        app::ApplicationCommon *app,
        settings::Settings *settings,
        std::unique_ptr<AbstractSimpleSoundsRepository> soundsRepository,
        AbstractAudioModel &audioModel,
        std::unique_ptr<AbstractTimeModel> timeModel,
        std::unique_ptr<PowerNapFrontlightModel> frontlightModel,
        const std::chrono::seconds &powerNapAlarmDuration)
        : app{app}, settings{settings}, soundsRepository{std::move(soundsRepository)},
          audioModel{audioModel}, timeModel{std::move(timeModel)}, frontlightModel{std::move(frontlightModel)},
    PowerNapProgressPresenter::PowerNapProgressPresenter(app::ApplicationCommon *app,
                                                         settings::Settings *settings,
                                                         AbstractAudioModel &audioModel,
                                                         std::unique_ptr<AbstractTimeModel> timeModel,
                                                         std::unique_ptr<PowerNapFrontlightModel> frontlightModel,
                                                         const std::chrono::seconds &powerNapAlarmDuration)
        : app{app}, settings{settings}, audioModel{audioModel}, timeModel{std::move(timeModel)},
          frontlightModel{std::move(frontlightModel)},
          napAlarmTimer{sys::TimerFactory::createSingleShotTimer(
              app, powerNapAlarmTimerName, powerNapAlarmDuration, [this](sys::Timer &) { onNapAlarmFinished(); })}

    {}

    void PowerNapProgressPresenter::setTimer(std::unique_ptr<app::TimerWithCallbacks> &&_timer)
    auto PowerNapProgressPresenter::setTimer(std::unique_ptr<app::TimerWithCallbacks> &&_timer) -> void
    {
        timer = std::move(_timer);
        timer->registerOnFinishedCallback([this]() {


@@ 42,42 40,42 @@ namespace app::powernap
        });
    }

    void PowerNapProgressPresenter::activate()
    auto PowerNapProgressPresenter::activate() -> void
    {
        Expects(timer != nullptr);
        const auto value = settings->getValue(powernapDBRecordName);
        const auto &value = settings->getValue(powernapDBRecordName);
        static_cast<app::Application *>(app)->suspendIdleTimer();
        timer->reset(std::chrono::minutes{utils::getNumericValue<int>(value)});
        timer->start();
        napFinished = false;
    }

    void PowerNapProgressPresenter::abortNap()
    auto PowerNapProgressPresenter::abortNap() -> void
    {
        napFinished = false;
        timer->stop();
        napAlarmTimer.stop();
    }

    void PowerNapProgressPresenter::endNap()
    auto PowerNapProgressPresenter::endNap() -> void
    {
        abortNap();
        onNapAlarmFinished();
    }

    void PowerNapProgressPresenter::pause()
    auto PowerNapProgressPresenter::pause() -> void
    {
        timer->stop();
        getView()->pause();
    }

    void PowerNapProgressPresenter::resume()
    auto PowerNapProgressPresenter::resume() -> void
    {
        timer->start();
        getView()->resume();
    }

    void PowerNapProgressPresenter::onNapFinished()
    auto PowerNapProgressPresenter::onNapFinished() -> void
    {
        if (napFinished) {
            return;


@@ 88,18 86,17 @@ namespace app::powernap
            frontlightModel->startBrightnessFadeIn();
        }

        const auto &filePath = soundsRepository->titleToPath(
            settings->getValue(bell::settings::Alarm::tone, settings::SettingsScope::Global));
        const auto &filePath    = settings->getValue(bell::settings::Alarm::tonePath, settings::SettingsScope::Global);
        const auto fadeInActive = utils::getNumericValue<bool>(settings->getValue(bell::settings::Alarm::fadeActive,
                                                                                  settings::SettingsScope::Global))
                                      ? audio::FadeIn::Enable
                                      : audio::FadeIn::Disable;
        audioModel.play(filePath.value_or(""), AbstractAudioModel::PlaybackType::Alarm, {}, fadeInActive);
        audioModel.play(filePath, AbstractAudioModel::PlaybackType::Alarm, {}, fadeInActive);
        napAlarmTimer.start();
        napFinished = true;
    }

    void PowerNapProgressPresenter::onNapAlarmFinished()
    auto PowerNapProgressPresenter::onNapAlarmFinished() -> void
    {
        frontlightModel->unlockKeypressTrigger();
        frontlightModel->turnOff();


@@ 107,22 104,22 @@ namespace app::powernap
        getView()->napEnded();
    }

    void PowerNapProgressPresenter::handleUpdateTimeEvent()
    auto PowerNapProgressPresenter::handleUpdateTimeEvent() -> void
    {
        getView()->setTime(timeModel->getCurrentTime());
    }

    bool PowerNapProgressPresenter::isNapFinished()
    auto PowerNapProgressPresenter::isNapFinished() -> bool
    {
        return napFinished;
    }

    void PowerNapProgressPresenter::onBeforeShow()
    auto PowerNapProgressPresenter::onBeforeShow() -> void
    {
        getView()->setTimeFormat(timeModel->getTimeFormat());
    }

    bool PowerNapProgressPresenter::isTimerStopped()
    auto PowerNapProgressPresenter::isTimerStopped() -> bool
    {
        return timer->isStopped();
    }

M products/BellHybrid/apps/application-bell-powernap/presenter/PowerNapProgressPresenter.hpp => products/BellHybrid/apps/application-bell-powernap/presenter/PowerNapProgressPresenter.hpp +40 -41
@@ 38,65 38,64 @@ namespace app::powernap
        {
          public:
            ~View()                                                         = default;
            virtual void napEnded()                                         = 0;
            virtual void setTime(std::time_t newTime)                       = 0;
            virtual void setTimeFormat(utils::time::Locale::TimeFormat fmt) = 0;
            virtual void progressFinished()                                 = 0;
            virtual void pause()                                            = 0;
            virtual void resume()                                           = 0;
            virtual auto napEnded() -> void                                         = 0;
            virtual auto setTime(std::time_t newTime) -> void                       = 0;
            virtual auto setTimeFormat(utils::time::Locale::TimeFormat fmt) -> void = 0;
            virtual auto progressFinished() -> void                                 = 0;
            virtual auto pause() -> void                                            = 0;
            virtual auto resume() -> void                                           = 0;
        };

        class Presenter : public BasePresenter<PowerNapProgressContract::View>
        {
          public:
            virtual void activate()                                                 = 0;
            virtual void endNap()                                                   = 0;
            virtual void abortNap()                                                 = 0;
            virtual bool isTimerStopped()                                           = 0;
            virtual void pause()                                                    = 0;
            virtual void resume()                                                   = 0;
            virtual void setTimer(std::unique_ptr<app::TimerWithCallbacks> &&timer) = 0;
            virtual void handleUpdateTimeEvent()                                    = 0;
            virtual bool isNapFinished()                                            = 0;
            virtual void onBeforeShow()                                             = 0;
            virtual auto activate() -> void                                                 = 0;
            virtual auto endNap() -> void                                                   = 0;
            virtual auto abortNap() -> void                                                 = 0;
            virtual auto isTimerStopped() -> bool                                           = 0;
            virtual auto pause() -> void                                                    = 0;
            virtual auto resume() -> void                                                   = 0;
            virtual auto setTimer(std::unique_ptr<app::TimerWithCallbacks> &&timer) -> void = 0;
            virtual auto handleUpdateTimeEvent() -> void                                    = 0;
            virtual auto isNapFinished() -> bool                                            = 0;
            virtual auto onBeforeShow() -> void                                             = 0;
        };
    };

    class PowerNapProgressPresenter : public PowerNapProgressContract::Presenter
    {
        app::ApplicationCommon *app{};
        settings::Settings *settings{};
        std::unique_ptr<AbstractSimpleSoundsRepository> soundsRepository;
        AbstractAudioModel &audioModel;
        std::unique_ptr<app::TimerWithCallbacks> timer;
        std::unique_ptr<AbstractTimeModel> timeModel;
        std::unique_ptr<PowerNapFrontlightModel> frontlightModel;
        sys::TimerHandle napAlarmTimer;
        bool napFinished{false};

        static constexpr auto endWindowTimeout = std::chrono::seconds{5};

      public:
        PowerNapProgressPresenter(app::ApplicationCommon *app,
                                  settings::Settings *settings,
                                  std::unique_ptr<AbstractSimpleSoundsRepository> soundsRepository,
                                  AbstractAudioModel &audioModel,
                                  std::unique_ptr<AbstractTimeModel> timeModel,
                                  std::unique_ptr<PowerNapFrontlightModel> frontlightModel,
                                  const std::chrono::seconds &powerNapAlarmDuration);

        void activate() override;
        void endNap() override;
        void abortNap() override;
        void pause() override;
        void resume() override;
        void setTimer(std::unique_ptr<app::TimerWithCallbacks> &&_timer) override;
        void handleUpdateTimeEvent() override;
        bool isNapFinished() override;
        bool isTimerStopped() override;
        auto activate() -> void override;
        auto endNap() -> void override;
        auto abortNap() -> void override;
        auto pause() -> void override;
        auto resume() -> void override;
        auto setTimer(std::unique_ptr<app::TimerWithCallbacks> &&_timer) -> void override;
        auto handleUpdateTimeEvent() -> void override;
        auto isNapFinished() -> bool override;
        auto isTimerStopped() -> bool override;

        void onNapFinished();
        void onNapAlarmFinished();
        void onBeforeShow() override;
        auto onNapFinished() -> void;
        auto onNapAlarmFinished() -> void;
        auto onBeforeShow() -> void override;

      private:
        static constexpr auto endWindowTimeout = std::chrono::seconds{5};

        app::ApplicationCommon *app{};
        settings::Settings *settings{};
        AbstractAudioModel &audioModel;
        std::unique_ptr<app::TimerWithCallbacks> timer;
        std::unique_ptr<AbstractTimeModel> timeModel;
        std::unique_ptr<PowerNapFrontlightModel> frontlightModel;
        sys::TimerHandle napAlarmTimer;
        bool napFinished{false};
    };
} // namespace app::powernap

M products/BellHybrid/apps/application-bell-relaxation/ApplicationBellRelaxation.cpp => products/BellHybrid/apps/application-bell-relaxation/ApplicationBellRelaxation.cpp +2 -1
@@ 181,7 181,8 @@ namespace app
                return sys::msgHandled();
            }
            userInterfaceDBNotification(
                msgl, [&]([[maybe_unused]] sys::Message *, [[maybe_unused]] const std::string &) { return true; });
                msgl,
                []([[maybe_unused]] sys::Message *msg, [[maybe_unused]] const std::string &name) { return true; });
            return sys::msgHandled();
        }
        return handleAsyncResponse(resp);

M products/BellHybrid/apps/application-bell-settings/ApplicationBellSettings.cpp => products/BellHybrid/apps/application-bell-settings/ApplicationBellSettings.cpp +22 -17
@@ 39,7 39,6 @@
#include <common/windows/BellFinishedWindow.hpp>
#include <common/windows/BellTurnOffWindow.hpp>
#include <common/windows/ShortcutsWindow.hpp>
#include <common/windows/BellFactoryReset.hpp>
#include <common/popups/BellTurnOffOptionWindow.hpp>
#include <common/models/AudioModel.hpp>
#include <common/models/TimeModel.hpp>


@@ 53,7 52,7 @@ namespace app
                                                     std::string parent,
                                                     StatusIndicators statusIndicators,
                                                     StartInBackground startInBackground,
                                                     uint32_t stackDepth)
                                                     std::uint32_t stackDepth)
        : Application(std::move(name), std::move(parent), statusIndicators, startInBackground, stackDepth),
          audioModel{std::make_unique<AudioModel>(this)}
    {


@@ 68,13 67,11 @@ namespace app
        }
        createUserInterface();

        connect(typeid(manager::GetCurrentDisplayLanguageResponse), [&](sys::Message *msg) {
        connect(typeid(manager::GetCurrentDisplayLanguageResponse), [&]([[maybe_unused]] sys::Message *msg) {
            if (gui::window::name::bellSettingsLanguage == getCurrentWindow()->getName()) {

                switchWindow(gui::window::bell_finished::defaultName,
                             gui::BellFinishedWindowData::Factory::create("circle_success_big",
                                                                          gui::window::name::bellSettings));

                return sys::msgHandled();
            }
            return sys::msgNotHandled();


@@ 126,9 123,10 @@ namespace app

        windowsFactory.attach(
            gui::window::name::bellSettingsBedtimeTone, [this](ApplicationCommon *app, const std::string &name) {
                auto bedtimeModel = std::make_shared<bell_bedtime::BedtimeModel>(app, *audioModel);
                auto soundsRepository = std::make_unique<SimpleSoundsRepository>(paths::audio::proprietary() /
                                                                                 paths::audio::bedtimeReminder());
                auto bedtimeModel = std::make_shared<bell_bedtime::BedtimeModel>(app, *audioModel, *soundsRepository);

                auto provider = std::make_shared<bell_settings::BedtimeSettingsListItemProvider>(
                    bedtimeModel, soundsRepository->getSongTitles());
                auto presenter = std::make_unique<bell_settings::SettingsPresenter>(


@@ 162,8 160,11 @@ namespace app

        windowsFactory.attach(
            gui::BellSettingsPrewakeUpWindow::name, [this](ApplicationCommon *app, const std::string &name) {
                auto soundsRepository =
                    std::make_unique<SimpleSoundsRepository>(paths::audio::proprietary() / paths::audio::preWakeup());
                auto prewakeUpChimeDurationModel = std::make_unique<bell_settings::PrewakeUpChimeDurationModel>(this);
                auto prewakeUpChimeToneModel     = std::make_unique<bell_settings::PrewakeUpChimeToneModel>(this);
                auto prewakeUpChimeToneModel =
                    std::make_unique<bell_settings::PrewakeUpChimeToneModel>(this, *soundsRepository);
                auto prewakeUpChimeVolumeModel =
                    std::make_unique<bell_settings::PrewakeUpChimeVolumeModel>(*audioModel);
                auto prewakeUpLightDurationModel = std::make_unique<bell_settings::PrewakeUpLightDurationModel>(this);


@@ 174,8 175,7 @@ namespace app
                                                                            std::move(prewakeUpChimeVolumeModel),
                                                                            std::move(prewakeUpLightDurationModel),
                                                                            std::move(prewakeUpFrontlightModel));
                auto soundsRepository =
                    std::make_unique<SimpleSoundsRepository>(paths::audio::proprietary() / paths::audio::preWakeup());

                auto provider         = std::make_unique<bell_settings::PrewakeUpListItemProvider>(
                    *prewakeUpSettingsModel, soundsRepository->getSongTitles());
                auto frontlightModel = std::make_unique<bell_settings::FrontlightModel>(app);


@@ 194,11 194,15 @@ namespace app
                                  return std::make_unique<gui::BellSettingsAlarmSettingsMenuWindow>(app);
                              });
        windowsFactory.attach(
            gui::BellSettingsAlarmSettingsSnoozeWindow::name, [this](ApplicationCommon *app, const std::string &) {
            gui::BellSettingsAlarmSettingsSnoozeWindow::name,
            [this](ApplicationCommon *app, [[maybe_unused]] const std::string &name) {
                auto soundsRepository =
                    std::make_unique<SimpleSoundsRepository>(paths::audio::proprietary() / paths::audio::snooze());
                auto snoozeOnOffModel         = std::make_unique<bell_settings::SnoozeOnOffModel>(this);
                auto snoozeLengthModel        = std::make_unique<bell_settings::SnoozeLengthModel>(this);
                auto snoozeChimeIntervalModel = std::make_unique<bell_settings::SnoozeChimeIntervalModel>(this);
                auto snoozeChimeToneModel     = std::make_unique<bell_settings::SnoozeChimeToneModel>(this);
                auto snoozeChimeToneModel =
                    std::make_unique<bell_settings::SnoozeChimeToneModel>(this, *soundsRepository);
                auto snoozeChimeVolumeModel   = std::make_unique<bell_settings::SnoozeChimeVolumeModel>(*audioModel);
                auto snoozeSettingsModel =
                    std::make_unique<bell_settings::SnoozeSettingsModel>(std::move(snoozeOnOffModel),


@@ 206,8 210,7 @@ namespace app
                                                                         std::move(snoozeChimeIntervalModel),
                                                                         std::move(snoozeChimeToneModel),
                                                                         std::move(snoozeChimeVolumeModel));
                auto soundsRepository =
                    std::make_unique<SimpleSoundsRepository>(paths::audio::proprietary() / paths::audio::snooze());

                auto provider = std::make_shared<bell_settings::SnoozeListItemProvider>(
                    *snoozeSettingsModel, soundsRepository->getSongTitles());
                auto presenter = std::make_unique<bell_settings::SnoozePresenter>(


@@ 215,8 218,11 @@ namespace app
                return std::make_unique<gui::BellSettingsAlarmSettingsSnoozeWindow>(app, std::move(presenter));
            });
        windowsFactory.attach(
            gui::BellSettingsAlarmSettingsWindow::name, [this](ApplicationCommon *app, const std::string &) {
                auto alarmToneModel       = std::make_unique<bell_settings::AlarmToneModel>(this);
            gui::BellSettingsAlarmSettingsWindow::name,
            [this](ApplicationCommon *app, [[maybe_unused]] const std::string &name) {
                auto soundsRepository =
                    std::make_unique<SimpleSoundsRepository>(paths::audio::proprietary() / paths::audio::alarm());
                auto alarmToneModel       = std::make_unique<bell_settings::AlarmToneModel>(this, *soundsRepository);
                auto alarmVolumeModel     = std::make_unique<bell_settings::AlarmVolumeModel>(*audioModel);
                auto alarmFadeOnOffModel  = std::make_unique<bell_settings::AlarmFadeOnOffModel>(this);
                auto alarmLightOnOffModel = std::make_unique<bell_settings::AlarmLightOnOffModel>(this);


@@ 227,8 233,7 @@ namespace app
                                                                        std::move(alarmFadeOnOffModel),
                                                                        std::move(alarmLightOnOffModel),
                                                                        std::move(alarmFrontlightModel));
                auto soundsRepository =
                    std::make_unique<SimpleSoundsRepository>(paths::audio::proprietary() / paths::audio::alarm());

                auto frontlightModel  = std::make_unique<bell_settings::FrontlightModel>(app);
                auto provider         = std::make_unique<bell_settings::AlarmSettingsListItemProvider>(
                    *alarmSettingsModel, soundsRepository->getSongTitles());

M products/BellHybrid/apps/application-bell-settings/include/application-bell-settings/ApplicationBellSettings.hpp => products/BellHybrid/apps/application-bell-settings/include/application-bell-settings/ApplicationBellSettings.hpp +2 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 37,7 37,7 @@ namespace app
                                std::string parent                  = "",
                                StatusIndicators statusIndicators   = StatusIndicators{},
                                StartInBackground startInBackground = {false},
                                uint32_t stackDepth                 = 4096 * 2);
                                std::uint32_t stackDepth            = 1024 * 8);

        sys::ReturnCodes InitHandler() override;


M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/AlarmSettingsModel.cpp => products/BellHybrid/apps/application-bell-settings/models/alarm_settings/AlarmSettingsModel.cpp +8 -2
@@ 18,14 18,20 @@ namespace app::bell_settings
        }
    }

    AlarmToneModel::AlarmToneModel(sys::Service *app, SimpleSoundsRepository &soundsRepository)
        : gui::SettingsModel<UTF8>{app}, soundsRepository{soundsRepository}
    {}

    void AlarmToneModel::setValue(UTF8 value)
    {
        settings.setValue(bell::settings::Alarm::tone, value, settings::SettingsScope::Global);
        const auto &path = soundsRepository.titleToPath(value).value_or("");
        settings.setValue(bell::settings::Alarm::tonePath, path, settings::SettingsScope::Global);
    }

    UTF8 AlarmToneModel::getValue() const
    {
        return settings.getValue(bell::settings::Alarm::tone, settings::SettingsScope::Global);
        const auto &path = settings.getValue(bell::settings::Alarm::tonePath, settings::SettingsScope::Global);
        return soundsRepository.pathToTitle(path).value_or("");
    }

    void AlarmVolumeModel::setValue(std::uint8_t value)

M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/PrewakeUpSettingsModel.cpp => products/BellHybrid/apps/application-bell-settings/models/alarm_settings/PrewakeUpSettingsModel.cpp +8 -2
@@ 23,14 23,20 @@ namespace app::bell_settings
        return utils::toNumeric(str);
    }

    PrewakeUpChimeToneModel::PrewakeUpChimeToneModel(sys::Service *app, SimpleSoundsRepository &soundsRepository)
        : gui::SettingsModel<UTF8>{app}, soundsRepository{soundsRepository}
    {}

    void PrewakeUpChimeToneModel::setValue(UTF8 value)
    {
        settings.setValue(bell::settings::PrewakeUp::tone, value, settings::SettingsScope::Global);
        const auto &path = soundsRepository.titleToPath(value).value_or("");
        settings.setValue(bell::settings::PrewakeUp::tonePath, path, settings::SettingsScope::Global);
    }

    UTF8 PrewakeUpChimeToneModel::getValue() const
    {
        return settings.getValue(bell::settings::PrewakeUp::tone, settings::SettingsScope::Global);
        const auto &path = settings.getValue(bell::settings::PrewakeUp::tonePath, settings::SettingsScope::Global);
        return soundsRepository.pathToTitle(path).value_or("");
    }

    void PrewakeUpChimeVolumeModel::setValue(std::uint8_t value)

M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/PrewakeUpSettingsModel.hpp => products/BellHybrid/apps/application-bell-settings/models/alarm_settings/PrewakeUpSettingsModel.hpp +6 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 7,6 7,7 @@
#include <common/models/SettingsModel.hpp>
#include <common/models/AudioModel.hpp>
#include <common/data/FrontlightUtils.hpp>
#include <common/SoundsRepository.hpp>

namespace app::bell_settings
{


@@ 22,10 23,13 @@ namespace app::bell_settings
    class PrewakeUpChimeToneModel : public gui::SettingsModel<UTF8>
    {
      public:
        using SettingsModel::SettingsModel;
        PrewakeUpChimeToneModel(sys::Service *app, SimpleSoundsRepository &soundsRepository);

        void setValue(UTF8 value) override;
        UTF8 getValue() const override;

      private:
        SimpleSoundsRepository &soundsRepository;
    };

    class PrewakeUpChimeVolumeModel : public gui::AbstractSettingsModel<std::uint8_t>

M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/SnoozeSettingsModel.cpp => products/BellHybrid/apps/application-bell-settings/models/alarm_settings/SnoozeSettingsModel.cpp +25 -37
@@ 4,78 4,66 @@
#include <models/alarm_settings/SnoozeSettingsModel.hpp>
#include <db/SystemSettings.hpp>

namespace
{
    template <typename T>
    std::optional<T> get_helper(settings::Settings &settings, const std::string &str)
    {
        const auto retStr = settings.getValue(str, settings::SettingsScope::Global);
        if (retStr.empty()) {
            LOG_ERROR("%s does not exist", str.c_str());
            return {};
        }
        else {
            if constexpr (std::is_integral_v<T>) {
                return utils::toNumeric(retStr);
            }
            else {
                return retStr;
            }
        }
    }
} // namespace

namespace app::bell_settings
{
    void SnoozeOnOffModel::setValue(bool value)
    auto SnoozeOnOffModel::setValue(bool value) -> void
    {
        const auto valStr = std::to_string(value);
        settings.setValue(bell::settings::Snooze::active, valStr, settings::SettingsScope::Global);
    }

    bool SnoozeOnOffModel::getValue() const
    auto SnoozeOnOffModel::getValue() const -> bool
    {
        return get_helper<bool>(settings, bell::settings::Snooze::active).value_or(false);
        return utils::getNumericValue<bool>(
            settings.getValue(bell::settings::Snooze::active, settings::SettingsScope::Global));
    }

    void SnoozeLengthModel::setValue(std::uint8_t value)
    auto SnoozeLengthModel::setValue(std::uint8_t value) -> void
    {
        const auto valStr = std::to_string(value);
        settings.setValue(bell::settings::Snooze::length, valStr, settings::SettingsScope::Global);
    }

    std::uint8_t SnoozeLengthModel::getValue() const
    auto SnoozeLengthModel::getValue() const -> std::uint8_t
    {
        return get_helper<std::uint32_t>(settings, bell::settings::Snooze::length).value_or(0);
        return utils::getNumericValue<std::uint8_t>(
            settings.getValue(bell::settings::Snooze::length, settings::SettingsScope::Global));
    }

    void SnoozeChimeIntervalModel::setValue(std::uint8_t value)
    auto SnoozeChimeIntervalModel::setValue(std::uint8_t value) -> void
    {
        const auto valStr = std::to_string(value);
        settings.setValue(bell::settings::Snooze::interval, valStr, settings::SettingsScope::Global);
    }

    std::uint8_t SnoozeChimeIntervalModel::getValue() const
    auto SnoozeChimeIntervalModel::getValue() const -> std::uint8_t
    {
        return get_helper<std::uint32_t>(settings, bell::settings::Snooze::interval).value_or(0);
        return utils::getNumericValue<std::uint8_t>(
            settings.getValue(bell::settings::Snooze::interval, settings::SettingsScope::Global));
    }

    void SnoozeChimeToneModel::setValue(UTF8 value)
    SnoozeChimeToneModel::SnoozeChimeToneModel(sys::Service *app, SimpleSoundsRepository &soundsRepository)
        : gui::SettingsModel<UTF8>{app}, soundsRepository{soundsRepository}
    {}

    auto SnoozeChimeToneModel::setValue(UTF8 value) -> void
    {
        settings.setValue(bell::settings::Snooze::tone, value, settings::SettingsScope::Global);
        const auto &path = soundsRepository.titleToPath(value).value_or("");
        settings.setValue(bell::settings::Snooze::tonePath, path, settings::SettingsScope::Global);
    }

    UTF8 SnoozeChimeToneModel::getValue() const
    auto SnoozeChimeToneModel::getValue() const -> UTF8
    {
        return get_helper<UTF8>(settings, bell::settings::Snooze::tone).value_or("");
        const auto &path = settings.getValue(bell::settings::Snooze::tonePath, settings::SettingsScope::Global);
        return soundsRepository.pathToTitle(path).value_or("");
    }

    void SnoozeChimeVolumeModel::setValue(std::uint8_t value)
    auto SnoozeChimeVolumeModel::setValue(std::uint8_t value) -> void
    {
        audioModel.setVolume(value, AbstractAudioModel::PlaybackType::Snooze);
    }

    std::uint8_t SnoozeChimeVolumeModel::getValue() const
    auto SnoozeChimeVolumeModel::getValue() const -> std::uint8_t
    {
        return defaultValue;
    }


@@ 85,7 73,7 @@ namespace app::bell_settings
        defaultValue = audioModel.getVolume(AbstractAudioModel::PlaybackType::Snooze).value_or(0);
    }

    void SnoozeChimeVolumeModel::restoreDefault()
    auto SnoozeChimeVolumeModel::restoreDefault() -> void
    {
        setValue(defaultValue);
    }

M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/SnoozeSettingsModel.hpp => products/BellHybrid/apps/application-bell-settings/models/alarm_settings/SnoozeSettingsModel.hpp +17 -13
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 6,6 6,7 @@
#include "AbstractSnoozeSettingsModel.hpp"
#include <common/models/SettingsModel.hpp>
#include <common/models/AudioModel.hpp>
#include <common/SoundsRepository.hpp>

namespace app::bell_settings
{


@@ 14,8 15,8 @@ namespace app::bell_settings
      public:
        using SettingsModel::SettingsModel;

        void setValue(bool value) override;
        bool getValue() const override;
        auto setValue(bool value) -> void override;
        auto getValue() const -> bool override;
    };

    class SnoozeLengthModel : public gui::SettingsModel<std::uint8_t>


@@ 23,8 24,8 @@ namespace app::bell_settings
      public:
        using SettingsModel::SettingsModel;

        void setValue(std::uint8_t value) override;
        std::uint8_t getValue() const override;
        auto setValue(std::uint8_t value) -> void override;
        auto getValue() const -> std::uint8_t override;
    };

    class SnoozeChimeIntervalModel : public gui::SettingsModel<std::uint8_t>


@@ 32,17 33,20 @@ namespace app::bell_settings
      public:
        using SettingsModel::SettingsModel;

        void setValue(std::uint8_t value) override;
        std::uint8_t getValue() const override;
        auto setValue(std::uint8_t value) -> void override;
        auto getValue() const -> std::uint8_t override;
    };

    class SnoozeChimeToneModel : public gui::SettingsModel<UTF8>
    {
      public:
        using SettingsModel::SettingsModel;
        SnoozeChimeToneModel(sys::Service *app, SimpleSoundsRepository &soundsRepository);

        auto setValue(UTF8 value) -> void override;
        auto getValue() const -> UTF8 override;

        void setValue(UTF8 value) override;
        UTF8 getValue() const override;
      private:
        SimpleSoundsRepository &soundsRepository;
    };

    class SnoozeChimeVolumeModel : public gui::AbstractSettingsModel<std::uint8_t>


@@ 50,9 54,9 @@ namespace app::bell_settings
      public:
        explicit SnoozeChimeVolumeModel(AbstractAudioModel &audioModel);

        void setValue(std::uint8_t value) override;
        std::uint8_t getValue() const override;
        void restoreDefault() override;
        auto setValue(std::uint8_t value) -> void override;
        auto getValue() const -> std::uint8_t override;
        auto restoreDefault() -> void override;

      private:
        AbstractAudioModel &audioModel;

M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/AlarmSettingsPresenter.hpp => products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/AlarmSettingsPresenter.hpp +1 -1
@@ 54,7 54,7 @@ namespace app::bell_settings

        auto getPagesProvider() const -> std::shared_ptr<gui::ListItemProvider> override;
        auto loadData() -> void override;
        auto saveData() -> void;
        auto saveData() -> void override;
        auto eraseProviderData() -> void override;
        auto exitWithSave() -> void override;
        auto exitWithRollback() -> void override;

M products/BellHybrid/apps/application-bell-settings/windows/alarm_settings/BellSettingsAlarmSettingsWindow.cpp => products/BellHybrid/apps/application-bell-settings/windows/alarm_settings/BellSettingsAlarmSettingsWindow.cpp +1 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "application-bell-settings/ApplicationBellSettings.hpp"


@@ 79,5 79,4 @@ namespace gui
    {
        setFocusItem(sidelistview);
    }

} /* namespace gui */

M products/BellHybrid/apps/common/include/common/models/AbstractSettingsModel.hpp => products/BellHybrid/apps/common/include/common/models/AbstractSettingsModel.hpp +3 -3
@@ 18,9 18,9 @@ namespace gui
      public:
        virtual ~AbstractSettingsModel() = default;

        virtual void setValue(ValueType value) = 0;
        virtual ValueType getValue() const     = 0;
        virtual void restoreDefault()
        virtual auto setValue(ValueType value) -> void = 0;
        virtual auto getValue() const -> ValueType     = 0;
        virtual auto restoreDefault() -> void
        {}
    };
} // namespace gui

M products/BellHybrid/apps/common/include/common/models/AlarmSettingsModel.hpp => products/BellHybrid/apps/common/include/common/models/AlarmSettingsModel.hpp +6 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 7,16 7,20 @@
#include <common/models/SettingsModel.hpp>
#include <common/models/AudioModel.hpp>
#include <common/data/FrontlightUtils.hpp>
#include <common/SoundsRepository.hpp>

namespace app::bell_settings
{
    class AlarmToneModel : public gui::SettingsModel<UTF8>
    {
      public:
        using SettingsModel::SettingsModel;
        AlarmToneModel(sys::Service *app, SimpleSoundsRepository &soundsRepository);

        void setValue(UTF8 value) override;
        UTF8 getValue() const override;

      private:
        SimpleSoundsRepository &soundsRepository;
    };

    class AlarmVolumeModel : public gui::AbstractSettingsModel<std::uint8_t>

M products/BellHybrid/apps/common/include/common/models/BedtimeModel.hpp => products/BellHybrid/apps/common/include/common/models/BedtimeModel.hpp +27 -25
@@ 1,40 1,37 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "AbstractBedtimeModel.hpp"
#include "SettingsModel.hpp"
#include <Service/Service.hpp>
#include <common/models/AudioModel.hpp>
#include <common/SoundsRepository.hpp>
#include <ApplicationCommon.hpp>
#include <ctime>

namespace app::bell_bedtime
{
    inline constexpr auto DEFAULT_BEDTIME_TIME = "21:00";
    inline constexpr auto DEFAULT_BEDTIME_TONE = "Evening Horizon";

    class BedtimeOnOffModel : public gui::SettingsModel<bool>
    {
      public:
        using SettingsModel::SettingsModel;

        void setValue(bool value) override;
        auto setValue(bool value) -> void override;
        auto getValue() const -> bool override;
    };

    class BedtimeTimeModel : public gui::SettingsModel<time_t>
    class BedtimeTimeModel : public gui::SettingsModel<std::time_t>
    {
        auto writeString(std::string str) -> void;
        auto readString() const -> std::string;
        auto getTmFromString(const std::string &str, std::tm &tm) const -> bool;

      public:
        using SettingsModel::SettingsModel;

        void setValue(time_t value) override;
        auto getValue() const -> time_t override;
        auto setValue(std::time_t value) -> void override;
        auto getValue() const -> std::time_t override;

      private:
        auto writeString(const std::string &str) -> void;
        auto readString() const -> std::string;
        auto getTmFromString(const std::string &str, std::tm &tm) const -> bool;
    };

    class BedtimeVolumeModel : public gui::AbstractSettingsModel<std::uint8_t>


@@ 42,22 39,25 @@ namespace app::bell_bedtime
      public:
        explicit BedtimeVolumeModel(AbstractAudioModel &audioModel);

        void setValue(std::uint8_t value) override;
        std::uint8_t getValue() const override;
        void restoreDefault() override;
        auto setValue(std::uint8_t value) -> void override;
        auto getValue() const -> std::uint8_t override;
        auto restoreDefault() -> void override;

      private:
        AbstractAudioModel &audioModel;
        std::uint8_t defaultValue;
    };

    class AlarmToneModel : public gui::SettingsModel<UTF8>
    class BedtimeToneModel : public gui::SettingsModel<UTF8>
    {
      public:
        using SettingsModel::SettingsModel;
        BedtimeToneModel(sys::Service *app, SimpleSoundsRepository &soundsRepository);

        auto setValue(UTF8 value) -> void override;
        auto getValue() const -> UTF8 override;

        void setValue(UTF8) override;
        UTF8 getValue() const override;
      private:
        SimpleSoundsRepository &soundsRepository;
    };

    class BedtimeModel : public AbstractBedtimeModel


@@ 65,18 65,20 @@ namespace app::bell_bedtime
      public:
        BedtimeModel() = delete;

        explicit BedtimeModel(ApplicationCommon *app, AbstractAudioModel &audioModel)
        BedtimeModel(ApplicationCommon *app, AbstractAudioModel &audioModel, SimpleSoundsRepository &soundsRepository)
        {
            bedtimeOnOff  = std::make_unique<bell_bedtime::BedtimeOnOffModel>(app);
            bedtimeTime   = std::make_unique<bell_bedtime::BedtimeTimeModel>(app);
            bedtimeTone   = std::make_unique<bell_bedtime::AlarmToneModel>(app);
            bedtimeTone   = std::make_unique<bell_bedtime::BedtimeToneModel>(app, soundsRepository);
            bedtimeVolume = std::make_unique<bell_bedtime::BedtimeVolumeModel>(audioModel);
        }

        gui::AbstractSettingsModel<bool> &getBedtimeOnOff() override
        {
            return *bedtimeOnOff;
        }
        gui::AbstractSettingsModel<time_t> &getBedtimeTime() override

        gui::AbstractSettingsModel<std::time_t> &getBedtimeTime() override
        {
            return *bedtimeTime;
        }


@@ 93,7 95,7 @@ namespace app::bell_bedtime

      private:
        std::unique_ptr<gui::AbstractSettingsModel<bool>> bedtimeOnOff;
        std::unique_ptr<gui::AbstractSettingsModel<time_t>> bedtimeTime;
        std::unique_ptr<gui::AbstractSettingsModel<std::time_t>> bedtimeTime;
        std::unique_ptr<gui::AbstractSettingsModel<UTF8>> bedtimeTone;
        std::unique_ptr<gui::AbstractSettingsModel<std::uint8_t>> bedtimeVolume;
    };

M products/BellHybrid/apps/common/src/AlarmModel.cpp => products/BellHybrid/apps/common/src/AlarmModel.cpp +5 -0
@@ 50,6 50,7 @@ namespace app
                                                       service::name::service_time);
        request->execute(app, this, responseCallback);
    }

    void AlarmModel::setAlarmTime(std::time_t time)
    {
        auto alarmEventPtr = getAlarmPtr();


@@ 73,6 74,7 @@ namespace app
    {
        return Clock::to_time_t(cachedRecord.startDate);
    }

    void AlarmModel::activate(bool value)
    {
        auto alarmEventPtr = getAlarmPtr();


@@ 89,6 91,7 @@ namespace app
            disableSnooze(*alarmEventPtr);
        }
    }

    void AlarmModel::updateAlarm(AlarmEventRecord &alarm)
    {
        auto request = AsyncRequest::createFromMessage(std::make_unique<alarms::AlarmUpdateRequestMessage>(alarm),


@@ 100,6 103,7 @@ namespace app

        cachedRecord = alarm.getNextSingleEvent(TimePointNow());
    }

    void AlarmModel::disableSnooze(AlarmEventRecord &alarm)
    {
        auto request = AsyncRequest::createFromMessage(std::make_unique<alarms::TurnOffSnoozeRequestMessage>(alarm.ID),


@@ 110,6 114,7 @@ namespace app
        });
        nextSnoozeTime = TIME_POINT_INVALID;
    }

    bool AlarmModel::isActive() const
    {
        if (!cachedRecord.parent) {

M products/BellHybrid/apps/common/src/SoundsRepository.cpp => products/BellHybrid/apps/common/src/SoundsRepository.cpp +6 -2
@@ 21,6 21,7 @@ namespace
        }
        return offset;
    }

    constexpr std::pair<std::uint32_t, std::uint32_t> calculateNewOffsetAndLimit(std::uint32_t offset,
                                                                                 std::uint32_t limit,
                                                                                 std::uint32_t loadedFiles)


@@ 29,7 30,8 @@ namespace
        const auto newOffset = offset + loadedFiles;
        return {newOffset, newLimit};
    }
    db::multimedia_files::SortingBy transformSorting(SoundsRepository::SortingBy sorting)

    constexpr db::multimedia_files::SortingBy transformSorting(SoundsRepository::SortingBy sorting)
    {
        switch (sorting) {
        case SoundsRepository::SortingBy::IdAscending:


@@ 43,13 45,14 @@ namespace

SimpleSoundsRepository::SimpleSoundsRepository(std::filesystem::path dirToScan)
{
    for (auto const &entry : std::filesystem::directory_iterator(dirToScan)) {
    for (const auto &entry : std::filesystem::directory_iterator(dirToScan)) {
        processEntry(entry);
    }

    /// Sort entries by track ID
    std::sort(samples.begin(), samples.end(), [](const auto &a, const auto &b) { return a.track < b.track; });
}

std::optional<std::filesystem::path> SimpleSoundsRepository::titleToPath(const UTF8 &title) const
{
    const auto res =


@@ 59,6 62,7 @@ std::optional<std::filesystem::path> SimpleSoundsRepository::titleToPath(const U
    }
    return {};
}

std::optional<UTF8> SimpleSoundsRepository::pathToTitle(std::filesystem::path path) const
{
    const auto res =

M products/BellHybrid/apps/common/src/models/BedtimeModel.cpp => products/BellHybrid/apps/common/src/models/BedtimeModel.cpp +24 -17
@@ 6,9 6,14 @@
#include <db/SystemSettings.hpp>
#include <ctime>

namespace
{
    constexpr auto defaultBedtimeTime = "21:00";
}

namespace app::bell_bedtime
{
    void BedtimeOnOffModel::setValue(bool value)
    auto BedtimeOnOffModel::setValue(bool value) -> void
    {
        const auto valStr = std::to_string(value);
        settings.setValue(bell::settings::Bedtime::active, valStr, settings::SettingsScope::Global);


@@ 20,7 25,7 @@ namespace app::bell_bedtime
        return utils::toNumeric(str);
    }

    auto BedtimeTimeModel::writeString(std::string str) -> void
    auto BedtimeTimeModel::writeString(const std::string &str) -> void
    {
        settings.setValue(bell::settings::Bedtime::time, str, settings::SettingsScope::Global);
    }


@@ 37,7 42,7 @@ namespace app::bell_bedtime
        return bool(stringStream);
    }

    void BedtimeTimeModel::setValue(time_t value)
    auto BedtimeTimeModel::setValue(std::time_t value) -> void
    {
        auto tm = std::localtime(&value);
        std::stringstream stringStream;


@@ 45,32 50,34 @@ namespace app::bell_bedtime
        writeString(stringStream.str());
    }

    auto BedtimeTimeModel::getValue() const -> time_t
    auto BedtimeTimeModel::getValue() const -> std::time_t
    {
        const auto str = readString();
        std::tm tm     = {};
        const auto &str = readString();
        std::tm tm{};
        if (!getTmFromString(str, tm)) {
            // incorrect time string
            getTmFromString(DEFAULT_BEDTIME_TIME, tm);
            getTmFromString(defaultBedtimeTime, tm);
        }
        return std::mktime(&tm);
    }

    void AlarmToneModel::setValue(UTF8 value)
    BedtimeToneModel::BedtimeToneModel(sys::Service *app, SimpleSoundsRepository &soundsRepository)
        : gui::SettingsModel<UTF8>{app}, soundsRepository{soundsRepository}
    {}

    auto BedtimeToneModel::setValue(UTF8 value) -> void
    {
        settings.setValue(bell::settings::Bedtime::tone, value, settings::SettingsScope::Global);
        const auto &path = soundsRepository.titleToPath(value).value_or("");
        settings.setValue(bell::settings::Bedtime::tonePath, path, settings::SettingsScope::Global);
    }

    auto AlarmToneModel::getValue() const -> UTF8
    auto BedtimeToneModel::getValue() const -> UTF8
    {
        const auto str = settings.getValue(bell::settings::Bedtime::tone, settings::SettingsScope::Global);
        if (str.empty()) {
            return DEFAULT_BEDTIME_TONE;
        }
        return str;
        const auto &path = settings.getValue(bell::settings::Bedtime::tonePath, settings::SettingsScope::Global);
        return soundsRepository.pathToTitle(path).value_or("");
    }

    void BedtimeVolumeModel::setValue(std::uint8_t value)
    auto BedtimeVolumeModel::setValue(std::uint8_t value) -> void
    {
        audioModel.setVolume(value, AbstractAudioModel::PlaybackType::Bedtime);
    }


@@ 85,7 92,7 @@ namespace app::bell_bedtime
        defaultValue = audioModel.getVolume(AbstractAudioModel::PlaybackType::Bedtime).value_or(0);
    }

    void BedtimeVolumeModel::restoreDefault()
    auto BedtimeVolumeModel::restoreDefault() -> void
    {
        setValue(defaultValue);
    }

M products/BellHybrid/apps/common/src/models/SettingsModel.cpp => products/BellHybrid/apps/common/src/models/SettingsModel.cpp +3 -2
@@ 1,9 1,10 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <models/SettingsModel.hpp>
#include <utf8/UTF8.hpp>
#include <widgets/list_items/Fraction.hpp>

namespace gui
{
    template <class ValueType>


@@ 17,6 18,6 @@ namespace gui
    template class SettingsModel<std::uint32_t>;
    template class SettingsModel<std::string>;
    template class SettingsModel<UTF8>;
    template class SettingsModel<time_t>;
    template class SettingsModel<std::time_t>;
    template class SettingsModel<app::list_items::FractionData>;
} // namespace gui

M products/BellHybrid/apps/include/Application.hpp => products/BellHybrid/apps/include/Application.hpp +1 -1
@@ 20,7 20,7 @@ namespace app
                             std::string parent                  = "",
                             StatusIndicators statusIndicators   = StatusIndicators{},
                             StartInBackground startInBackground = {false},
                             uint32_t stackDepth                 = 4096,
                             std::uint32_t stackDepth            = 1024 * 4,
                             sys::ServicePriority priority       = sys::ServicePriority::Idle);

        sys::ReturnCodes InitHandler() override;

M products/BellHybrid/paths/Paths.cpp => products/BellHybrid/paths/Paths.cpp +9 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "Paths.hpp"


@@ 8,34 8,42 @@ std::filesystem::path paths::audio::userApp() noexcept
{
    return purefs::dir::getUserMediaPath() / "app";
}

std::filesystem::path paths::audio::proprietary() noexcept
{
    return purefs::dir::getAssetsDirPath() / "audio";
}

std::filesystem::path paths::audio::alarm() noexcept
{
    return "alarm";
}

std::filesystem::path paths::audio::preWakeup() noexcept
{
    return "prewakeup";
}

std::filesystem::path paths::audio::snooze() noexcept
{
    return "chimes";
}

std::filesystem::path paths::audio::bedtimeReminder() noexcept
{
    return "evening_reminder";
}

std::filesystem::path paths::audio::relaxation() noexcept
{
    return "relaxation";
}

std::filesystem::path paths::audio::meditation() noexcept
{
    return "meditation";
}

std::filesystem::path paths::audio::colorOfNoises() noexcept
{
    return "noises";

M products/BellHybrid/paths/Paths.hpp => products/BellHybrid/paths/Paths.hpp +1 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 19,5 19,4 @@ namespace paths
        std::filesystem::path meditation() noexcept;
        std::filesystem::path colorOfNoises() noexcept;
    } // namespace audio

} // namespace paths

A products/BellHybrid/services/db/databases/migration/settings_bell/current/1b034c28_Change_tone_names_to_tone_paths/.meta => products/BellHybrid/services/db/databases/migration/settings_bell/current/1b034c28_Change_tone_names_to_tone_paths/.meta +6 -0
@@ 0,0 1,6 @@
{
 "id": "1b034c28-f8f4-4792-8f35-9ab376fec0de",
 "date": "2024-03-06 15:07:49",
 "message": "Change tone names to tone paths",
 "parent": 0
}
\ No newline at end of file

A products/BellHybrid/services/db/databases/migration/settings_bell/current/1b034c28_Change_tone_names_to_tone_paths/devel.sql => products/BellHybrid/services/db/databases/migration/settings_bell/current/1b034c28_Change_tone_names_to_tone_paths/devel.sql +6 -0
@@ 0,0 1,6 @@
-- Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
-- For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

-- Message: Change tone names to tone paths
-- Revision: 1b034c28-f8f4-4792-8f35-9ab376fec0de
-- Create Date: 2024-03-06 15:07:49

A products/BellHybrid/services/db/databases/migration/settings_bell/current/1b034c28_Change_tone_names_to_tone_paths/down.sql => products/BellHybrid/services/db/databases/migration/settings_bell/current/1b034c28_Change_tone_names_to_tone_paths/down.sql +118 -0
@@ 0,0 1,118 @@
-- Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
-- For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

-- Message: Change tone names to tone paths
-- Revision: 1b034c28-f8f4-4792-8f35-9ab376fec0de
-- Create Date: 2024-03-06 15:07:49

-- Revert snooze tone data update
UPDATE OR IGNORE settings_tab
SET value = (
    CASE
    WHEN (SELECT value FROM settings_tab WHERE path = 'snooze_tone_path') = '/system/assets/audio/chimes/Blissful_Dream.mp3'
    THEN 'Blissful Dream'
    WHEN (SELECT value FROM settings_tab WHERE path = 'snooze_tone_path') = '/system/assets/audio/chimes/Gentle_Chime.mp3'
    THEN 'Gentle Chime'
    WHEN (SELECT value FROM settings_tab WHERE path = 'snooze_tone_path') = '/system/assets/audio/chimes/Rise_&_Shine.mp3'
    THEN 'Rise & Shine'
    WHEN (SELECT value FROM settings_tab WHERE path = 'snooze_tone_path') =  '/system/assets/audio/chimes/Twinkle_Chime.mp3'
    THEN 'Twinkle Chime'
    END
    )
WHERE path = 'snooze_tone_path';

UPDATE OR IGNORE settings_tab
SET path = 'snooze_tone'
WHERE path = 'snooze_tone_path';

-- Revert prewake up tone data update
UPDATE OR IGNORE settings_tab
SET value = (
    CASE
    WHEN (SELECT value FROM settings_tab WHERE path = 'prewake_up_tone_path') =  '/system/assets/audio/prewakeup/Joyful_Awakening.mp3'
    THEN 'Joyful Awakening'
    WHEN (SELECT value FROM settings_tab WHERE path = 'prewake_up_tone_path') = '/system/assets/audio/prewakeup/Morning_Spirit.mp3'
    THEN 'Morning Spirit'
    WHEN (SELECT value FROM settings_tab WHERE path = 'prewake_up_tone_path') = '/system/assets/audio/prewakeup/Radiant_Morning.mp3'
    THEN 'Radiant Morning'
    WHEN (SELECT value FROM settings_tab WHERE path = 'prewake_up_tone_path') = '/system/assets/audio/prewakeup/Spring_Sunrise.mp3'
    THEN 'Spring Sunrise'
    END
    )
WHERE path = 'prewake_up_tone_path';

UPDATE OR IGNORE settings_tab
SET path = 'prewake_up_tone'
WHERE path = 'prewake_up_tone_path';

-- Revert alarm tone data update
UPDATE OR IGNORE settings_tab
SET value = (
    CASE
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = '/system/assets/audio/alarm/Morning_Dew.mp3'
    THEN 'Morning Dew'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = '/system/assets/audio/alarm/Tongue_Drum.mp3'
    THEN 'Tongue Drum'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = '/system/assets/audio/alarm/Koshi_Dream.mp3'
    THEN 'Koshi Dream'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = '/system/assets/audio/alarm/Tibetan_Bowls.mp3'
    THEN 'Tibetan Bowls'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = '/system/assets/audio/alarm/Reverie_Harp.mp3'
    THEN 'Reverie Harp'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = '/system/assets/audio/alarm/Tranquil_Rainstick.mp3'
    THEN 'Tranquil Rainstick'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = '/system/assets/audio/alarm/Hawaiian_Blues.mp3'
    THEN 'Hawaiian Blues'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = '/system/assets/audio/alarm/Sunrise_Guitar.mp3'
    THEN 'Sunrise Guitar'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = '/system/assets/audio/alarm/Acoustic_Vibes.mp3'
    THEN 'Acoustic Vibes'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = '/system/assets/audio/alarm/Back_Porch.mp3'
    THEN 'Back Porch'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = '/system/assets/audio/alarm/Cowboy_Chords.mp3'
    THEN 'Cowboy Chords'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = '/system/assets/audio/alarm/Bubbling_Brook.mp3'
    THEN 'Bubbling Brook'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = '/system/assets/audio/alarm/Autumnal_Sea.mp3'
    THEN 'Autumnal Sea'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = '/system/assets/audio/alarm/Natures_Harmony.mp3'
    THEN 'Nature''s Harmony'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = '/system/assets/audio/alarm/Delightful_Morning.mp3'
    THEN 'Delightful Morning'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = '/system/assets/audio/alarm/Always_With_You.mp3'
    THEN 'Always With You'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = '/system/assets/audio/alarm/Love_Peace_and_Harmony.mp3'
    THEN 'Love, Peace and Harmony'
    END
    )
WHERE path = 'alarm_tone_path';

UPDATE OR IGNORE settings_tab
SET path = 'alarm_tone'
WHERE path = 'alarm_tone_path';

-- Revert bedtime tone data update
UPDATE OR IGNORE settings_tab
SET value = (
    CASE
    WHEN (SELECT value FROM settings_tab WHERE path = 'bedtime_tone_path') = '/system/assets/audio/evening_reminder/Evening_Horizon.mp3'
    THEN 'Evening Horizon'
    WHEN (SELECT value FROM settings_tab WHERE path = 'bedtime_tone_path') = '/system/assets/audio/evening_reminder/Evolving_Dusk.mp3'
    THEN 'Evolving Dusk'
    WHEN (SELECT value FROM settings_tab WHERE path = 'bedtime_tone_path') = '/system/assets/audio/evening_reminder/Melodic_Mirth.mp3'
    THEN 'Melodic Mirth'
    WHEN (SELECT value FROM settings_tab WHERE path = 'bedtime_tone_path') = '/system/assets/audio/evening_reminder/Twilight_Gleam.mp3'
    THEN 'Twilight Gleam'
    END
    )
WHERE path = 'bedtime_tone_path';

UPDATE OR IGNORE settings_tab
SET path = 'bedtime_tone'
WHERE path = 'bedtime_tone_path';

-- Remove fallback defaults
DELETE FROM settings_tab WHERE path = 'snooze_tone_path_default';
DELETE FROM settings_tab WHERE path = 'prewake_up_tone_path_default';
DELETE FROM settings_tab WHERE path = 'alarm_tone_path_default';
DELETE FROM settings_tab WHERE path = 'bedtime_tone_path_default';

A products/BellHybrid/services/db/databases/migration/settings_bell/current/1b034c28_Change_tone_names_to_tone_paths/up.sql => products/BellHybrid/services/db/databases/migration/settings_bell/current/1b034c28_Change_tone_names_to_tone_paths/up.sql +119 -0
@@ 0,0 1,119 @@
-- Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
-- For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

-- Message: Change tone names to tone paths
-- Revision: 1b034c28-f8f4-4792-8f35-9ab376fec0de
-- Create Date: 2024-03-06 15:07:49

-- Update snooze tone data
UPDATE OR IGNORE settings_tab
SET path = 'snooze_tone_path'
WHERE path = 'snooze_tone';

UPDATE OR IGNORE settings_tab
SET value = (
    CASE
    WHEN (SELECT value FROM settings_tab WHERE path = 'snooze_tone_path') = 'Blissful Dream'
    THEN '/system/assets/audio/chimes/Blissful_Dream.mp3'
    WHEN (SELECT value FROM settings_tab WHERE path = 'snooze_tone_path') = 'Gentle Chime'
    THEN '/system/assets/audio/chimes/Gentle_Chime.mp3'
    WHEN (SELECT value FROM settings_tab WHERE path = 'snooze_tone_path') = 'Rise & Shine'
    THEN '/system/assets/audio/chimes/Rise_&_Shine.mp3'
    WHEN (SELECT value FROM settings_tab WHERE path = 'snooze_tone_path') = 'Twinkle Chime'
    THEN '/system/assets/audio/chimes/Twinkle_Chime.mp3'
    END
    )
WHERE path = 'snooze_tone_path';

-- Update prewake up tone data
UPDATE OR IGNORE settings_tab
SET path = 'prewake_up_tone_path'
WHERE path = 'prewake_up_tone';

UPDATE OR IGNORE settings_tab
SET value = (
    CASE
    WHEN (SELECT value FROM settings_tab WHERE path = 'prewake_up_tone_path') = 'Joyful Awakening'
    THEN '/system/assets/audio/prewakeup/Joyful_Awakening.mp3'
    WHEN (SELECT value FROM settings_tab WHERE path = 'prewake_up_tone_path') = 'Morning Spirit'
    THEN '/system/assets/audio/prewakeup/Morning_Spirit.mp3'
    WHEN (SELECT value FROM settings_tab WHERE path = 'prewake_up_tone_path') = 'Radiant Morning'
    THEN '/system/assets/audio/prewakeup/Radiant_Morning.mp3'
    WHEN (SELECT value FROM settings_tab WHERE path = 'prewake_up_tone_path') = 'Spring Sunrise'
    THEN '/system/assets/audio/prewakeup/Spring_Sunrise.mp3'
    END
    )
WHERE path = 'prewake_up_tone_path';

-- Update alarm tone data
UPDATE OR IGNORE settings_tab
SET path = 'alarm_tone_path'
WHERE path = 'alarm_tone';

UPDATE OR IGNORE settings_tab
SET value = (
    CASE
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = 'Morning Dew'
    THEN '/system/assets/audio/alarm/Morning_Dew.mp3'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = 'Tongue Drum'
    THEN '/system/assets/audio/alarm/Tongue_Drum.mp3'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = 'Koshi Dream'
    THEN '/system/assets/audio/alarm/Koshi_Dream.mp3'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = 'Tibetan Bowls'
    THEN '/system/assets/audio/alarm/Tibetan_Bowls.mp3'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = 'Reverie Harp'
    THEN '/system/assets/audio/alarm/Reverie_Harp.mp3'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = 'Tranquil Rainstick'
    THEN '/system/assets/audio/alarm/Tranquil_Rainstick.mp3'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = 'Hawaiian Blues'
    THEN '/system/assets/audio/alarm/Hawaiian_Blues.mp3'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = 'Sunrise Guitar'
    THEN '/system/assets/audio/alarm/Sunrise_Guitar.mp3'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = 'Acoustic Vibes'
    THEN '/system/assets/audio/alarm/Acoustic_Vibes.mp3'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = 'Back Porch'
    THEN '/system/assets/audio/alarm/Back_Porch.mp3'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = 'Cowboy Chords'
    THEN '/system/assets/audio/alarm/Cowboy_Chords.mp3'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = 'Bubbling Brook'
    THEN '/system/assets/audio/alarm/Bubbling_Brook.mp3'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = 'Autumnal Sea'
    THEN '/system/assets/audio/alarm/Autumnal_Sea.mp3'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = 'Nature''s Harmony'
    THEN '/system/assets/audio/alarm/Natures_Harmony.mp3'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = 'Delightful Morning'
    THEN '/system/assets/audio/alarm/Delightful_Morning.mp3'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = 'Always With You'
    THEN '/system/assets/audio/alarm/Always_With_You.mp3'
    WHEN (SELECT value FROM settings_tab WHERE path = 'alarm_tone_path') = 'Love, Peace and Harmony'
    THEN '/system/assets/audio/alarm/Love_Peace_and_Harmony.mp3'
    END
    )
WHERE path = 'alarm_tone_path';

-- Update bedtime tone data
UPDATE OR IGNORE settings_tab
SET path = 'bedtime_tone_path'
WHERE path = 'bedtime_tone';

UPDATE OR IGNORE settings_tab
SET value = (
    CASE
    WHEN (SELECT value FROM settings_tab WHERE path = 'bedtime_tone_path') = 'Evening Horizon'
    THEN '/system/assets/audio/evening_reminder/Evening_Horizon.mp3'
    WHEN (SELECT value FROM settings_tab WHERE path = 'bedtime_tone_path') = 'Evolving Dusk'
    THEN '/system/assets/audio/evening_reminder/Evolving_Dusk.mp3'
    WHEN (SELECT value FROM settings_tab WHERE path = 'bedtime_tone_path') = 'Melodic Mirth'
    THEN '/system/assets/audio/evening_reminder/Melodic_Mirth.mp3'
    WHEN (SELECT value FROM settings_tab WHERE path = 'bedtime_tone_path') = 'Twilight Gleam'
    THEN '/system/assets/audio/evening_reminder/Twilight_Gleam.mp3'
    END
    )
WHERE path = 'bedtime_tone_path';

-- Add fallback defaults for each tone
INSERT OR IGNORE INTO settings_tab (path, value) VALUES
   ('snooze_tone_path_default', '/system/assets/audio/chimes/Gentle_Chime.mp3'),
   ('prewake_up_tone_path_default', '/system/assets/audio/prewakeup/Joyful_Awakening.mp3'),
   ('alarm_tone_path_default', '/system/assets/audio/alarm/Morning_Dew.mp3'),
   ('bedtime_tone_path_default', '/system/assets/audio/evening_reminder/Evening_Horizon.mp3');

M products/BellHybrid/services/db/include/db/SystemSettings.hpp => products/BellHybrid/services/db/include/db/SystemSettings.hpp +30 -21
@@ 1,4 1,4 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 7,39 7,48 @@ namespace bell::settings
{
    namespace Temperature
    {
        constexpr inline auto unit = "temperature_unit";
        inline constexpr auto unit = "temperature_unit";
    } // namespace Temperature

    namespace Snooze
    {
        constexpr inline auto active   = "snooze_active";
        constexpr inline auto length   = "snooze_length";
        constexpr inline auto interval = "snooze_interval";
        constexpr inline auto tone     = "snooze_tone";
        inline constexpr auto tonePath         = "snooze_tone_path";
        inline constexpr auto toneFallbackPath = "snooze_tone_path_default";
        inline constexpr auto active   = "snooze_active";
        inline constexpr auto length   = "snooze_length";
        inline constexpr auto interval = "snooze_interval";
    } // namespace Snooze

    namespace PrewakeUp
    {
        constexpr inline auto duration      = "prewake_up_duration";
        constexpr inline auto tone          = "prewake_up_tone";
        constexpr inline auto lightDuration = "prewake_up_light_duration";
        constexpr inline auto brightness    = "prewake_up_brightness";
        inline constexpr auto tonePath         = "prewake_up_tone_path";
        inline constexpr auto toneFallbackPath = "prewake_up_tone_path_default";
        inline constexpr auto duration      = "prewake_up_duration";
        inline constexpr auto lightDuration = "prewake_up_light_duration";
        inline constexpr auto brightness    = "prewake_up_brightness";
    } // namespace PrewakeUp

    namespace Alarm
    {
        constexpr inline auto tone        = "alarm_tone";
        constexpr inline auto fadeActive  = "alarm_fade_active";
        constexpr inline auto lightActive = "alarm_light_active";
        constexpr inline auto duration    = "alarm_duration";
        constexpr inline auto brightness  = "alarm_brightness";
        inline constexpr auto tonePath    = "alarm_tone_path";
        inline constexpr auto toneFallbackPath = "alarm_tone_path_default";
        inline constexpr auto fadeActive  = "alarm_fade_active";
        inline constexpr auto lightActive = "alarm_light_active";
        inline constexpr auto duration    = "alarm_duration";
        inline constexpr auto brightness  = "alarm_brightness";
    } // namespace Alarm

    namespace Bedtime
    {
        constexpr inline auto active   = "bedtime_active";
        constexpr inline auto time     = "bedtime_time";
        constexpr inline auto tone     = "bedtime_tone";
        constexpr inline auto duration = "bedtime_duration";
        inline constexpr auto tonePath         = "bedtime_tone_path";
        inline constexpr auto toneFallbackPath = "bedtime_tone_path_default";
        inline constexpr auto active   = "bedtime_active";
        inline constexpr auto time     = "bedtime_time";
        inline constexpr auto duration = "bedtime_duration";
    } // namespace Bedtime

    namespace Layout
    {
        constexpr inline auto layout = "layout";
        inline constexpr auto layout = "layout";
    } // namespace Layout
};    // namespace bell::settings
} // namespace bell::settings

M products/BellHybrid/services/time/AlarmOperations.cpp => products/BellHybrid/services/time/AlarmOperations.cpp +5 -7
@@ 6,7 6,9 @@
#include <service-time/AlarmMessage.hpp>
#include <time/AlarmOperations.hpp>
#include <time/dateCommon.hpp>
#include <db/SystemSettings.hpp>
#include <service-db/agents/settings/SystemSettings.hpp>
#include <common/models/BedtimeModel.hpp>

#include <string>



@@ 104,12 106,8 @@ namespace alarms
            const auto intervalStr =
                settings.getValue(bell::settings::Snooze::interval, settings::SettingsScope::Global);
            const auto interval = utils::getNumericValue<std::uint32_t>(intervalStr);
            if (interval == 0) {
                return {false, std::chrono::minutes{0}};
            }
            else {
                return {true, std::chrono::minutes{interval}};
            }
            const auto enabled  = (interval != 0);
            return {enabled, std::chrono::minutes{interval}};
        }

        class OnboardingSettingsProviderImpl : public OnboardingSettingsProvider


@@ 184,7 182,7 @@ namespace alarms

    void AlarmOperations::minuteUpdated(TimePoint now)
    {
        // Prevent activating alarms when the onboard is not done yet
        // Prevent activating alarms when the onboarding is not done yet
        if (!isOnboardingDone()) {
            return;
        }

M products/BellHybrid/services/time/include/time/AlarmOperations.hpp => products/BellHybrid/services/time/include/time/AlarmOperations.hpp +0 -2
@@ 4,8 4,6 @@
#pragma once

#include <AlarmOperations.hpp>
#include <db/SystemSettings.hpp>
#include <common/models/BedtimeModel.hpp>
#include <service-db/Settings.hpp>

namespace alarms

M scripts/lua/products/BellHybrid/scripts/factory.lua => scripts/lua/products/BellHybrid/scripts/factory.lua +6 -4
@@ 26,15 26,17 @@ local function remove_cache()
    end
end

local function remove_user_relaxation_files()
    print(string.format("Removing user relaxation files from '%s'", paths.user_relaxation_file))
    helpers.rm_files_from_dir(paths.user_relaxation_file)
local function remove_user_files()
    print(string.format("Removing user relaxation files from '%s'", paths.user_relaxation_dir))
    helpers.rm_files_from_dir(paths.user_relaxation_dir)
    print(string.format("Removing user alarm files from '%s'", paths.user_alarm_dir))
    helpers.rm_files_from_dir(paths.user_alarm_dir)
end

function factory.execute()
    remove_old_databases()
    copy_clean_databases()
    remove_user_relaxation_files()
    remove_user_files()
    remove_cache()
end


M scripts/lua/share/paths.lua => scripts/lua/share/paths.lua +4 -1
@@ 14,7 14,10 @@ paths.db_factory_dir = paths.db_dir .. "/factory"
paths.temp_dir = user_dir .. "/temp"
paths.update_dir = user_dir .. "/temp/update"
paths.migration_scripts_dir = paths.db_dir .. "/migration"
paths.user_relaxation_file = user_dir .. "/media/app/relaxation" -- Only for Harmony

-- Only for Harmony
paths.user_relaxation_dir = user_dir .. "/media/app/relaxation"
paths.user_alarm_dir = user_dir .. "/media/app/alarm"

local target = {}
target.var_dir = target_dir .. "/var"