~aleteoryx/muditaos

2b985de0d0c97a45b5d76f53d089df96f608aeff — Mateusz Piesta 4 years ago 1dcb9d7
[BH-935] Volume and tone selection

Added playback of volume and tone selection
45 files changed, 730 insertions(+), 441 deletions(-)

M image/user/db/settings_bell_002.sql
M module-apps/apps-common/AudioOperations.cpp
M module-apps/apps-common/AudioOperations.hpp
M module-apps/apps-common/widgets/spinners/GenericSpinner.hpp
M module-apps/apps-common/widgets/spinners/SpinnerPolicies.hpp
M products/BellHybrid/alarms/include/AlarmSoundPaths.hpp
M products/BellHybrid/alarms/src/AlarmSoundPaths.cpp
M products/BellHybrid/alarms/src/actions/PlayAudioActions.cpp
M products/BellHybrid/apps/CMakeLists.txt
M products/BellHybrid/apps/application-bell-main/windows/BellBatteryShutdownWindow.hpp
M products/BellHybrid/apps/application-bell-settings/ApplicationBellSettings.cpp
M products/BellHybrid/apps/application-bell-settings/CMakeLists.txt
D products/BellHybrid/apps/application-bell-settings/models/SoundFilesModel.cpp
D products/BellHybrid/apps/application-bell-settings/models/SoundFilesModel.hpp
M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/AbstractPrewakeUpSettingsModel.hpp
M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/AlarmSettingsListItemProvider.cpp
M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/AlarmSettingsListItemProvider.hpp
M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/PrewakeUpListItemProvider.cpp
M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/PrewakeUpListItemProvider.hpp
M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/PrewakeUpSettingsModel.cpp
M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/PrewakeUpSettingsModel.hpp
A products/BellHybrid/apps/application-bell-settings/models/alarm_settings/SettingsListItemProvider.cpp
A products/BellHybrid/apps/application-bell-settings/models/alarm_settings/SettingsListItemProvider.hpp
M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/SnoozeListItemProvider.cpp
M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/SnoozeListItemProvider.hpp
M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/AlarmSettingsPresenter.cpp
M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/AlarmSettingsPresenter.hpp
M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/PrewakeUpPresenter.cpp
M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/PrewakeUpPresenter.hpp
M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/SnoozePresenter.cpp
M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/SnoozePresenter.hpp
D products/BellHybrid/apps/application-bell-settings/widgets/SoundFileListItem.cpp
D products/BellHybrid/apps/application-bell-settings/widgets/SoundFileListItem.hpp
M products/BellHybrid/apps/common/CMakeLists.txt
A products/BellHybrid/apps/common/include/common/SoundsRepository.hpp
A products/BellHybrid/apps/common/include/common/models/AbstractAudioModel.hpp
A products/BellHybrid/apps/common/include/common/models/AudioModel.hpp
M products/BellHybrid/apps/common/include/common/widgets/BellSideListItemWithCallbacks.hpp
M products/BellHybrid/apps/common/include/common/widgets/ListItems.hpp
A products/BellHybrid/apps/common/src/AudioModel.cpp
M products/BellHybrid/apps/common/src/BellSideListItemWithCallbacks.cpp
A products/BellHybrid/apps/common/src/SoundsRepository.cpp
M products/BellHybrid/apps/common/src/widgets/ListItems.cpp
M products/BellHybrid/services/db/include/db/SystemSettings.hpp
M test/harness
M image/user/db/settings_bell_002.sql => image/user/db/settings_bell_002.sql +5 -6
@@ 31,17 31,16 @@ INSERT OR IGNORE INTO settings_tab (path, value) VALUES
    ('gs_current_timezone_rules', ''),
    ('\ServiceTime\\gs_automatic_date_and_time_is_on', '1'),
    ('temperature_unit', 'C'),
    ('ringing_duration', '10000'),
    ('ringing_tone', 'Nick_Lewis_-_Kristies_Elephant.mp3'),
    ('snooze_active', '1'),
    ('snooze_length','10'),
    ('snooze_interval','1'),
    ('snooze_tone','chime_bnm.mp3'),
    ('snooze_tone','Blissful Dream'),
    ('snooze_volume','10'),
    ('prewake_up_duration', '10'),
    ('prewake_up_tone','Meditative surprises'),
    ('prewake_up_tone','Joyful Awakening'),
    ('prewake_up_volume','5'),
    ('prewake_up_light_duration','10'),
    ('alarm_tone','Meditative surprises'),
    ('alarm_tone','Atumnal Sea'),
    ('alarm_volume','5'),
    ('alarm_light_active','1');
    ('alarm_light_active','1'),
    ('alarm_duration','10000');

M module-apps/apps-common/AudioOperations.cpp => module-apps/apps-common/AudioOperations.cpp +4 -2
@@ 18,9 18,11 @@ namespace app
        : app::AsyncCallbackReceiver{application}, application(application)
    {}

    bool AsyncAudioOperations::play(const std::string &filePath, const OnPlayCallback &callback)
    bool AsyncAudioOperations::play(const std::string &filePath,
                                    const OnPlayCallback &callback,
                                    const audio::PlaybackType playbackType)
    {
        auto msg  = std::make_unique<AudioStartPlaybackRequest>(filePath, audio::PlaybackType::Multimedia);
        auto msg  = std::make_unique<AudioStartPlaybackRequest>(filePath, playbackType);
        auto task = app::AsyncRequest::createFromMessage(std::move(msg), service::name::audio);
        auto cb   = [callback](auto response) {
            auto result = dynamic_cast<AudioStartPlaybackResponse *>(response);

M module-apps/apps-common/AudioOperations.hpp => module-apps/apps-common/AudioOperations.hpp +4 -2
@@ 21,7 21,9 @@ namespace app

        virtual ~AbstractAudioOperations() noexcept = default;

        virtual bool play(const std::string &filePath, const OnPlayCallback &callback)   = 0;
        virtual bool play(const std::string &filePath,
                          const OnPlayCallback &callback,
                          audio::PlaybackType type = audio::PlaybackType::Multimedia)    = 0;
        virtual bool pause(const audio::Token &token, const OnPauseCallback &callback)   = 0;
        virtual bool resume(const audio::Token &token, const OnResumeCallback &callback) = 0;
        virtual bool stop(const audio::Token &token, const OnStopCallback &callback)     = 0;


@@ 32,7 34,7 @@ namespace app
      public:
        explicit AsyncAudioOperations(ApplicationCommon *application);

        bool play(const std::string &filePath, const OnPlayCallback &callback) override;
        bool play(const std::string &filePath, const OnPlayCallback &callback, audio::PlaybackType type) override;
        bool pause(const audio::Token &token, const OnPauseCallback &callback) override;
        bool resume(const audio::Token &token, const OnResumeCallback &callback) override;
        bool stop(const audio::Token &token, const OnStopCallback &callback) override;

M module-apps/apps-common/widgets/spinners/GenericSpinner.hpp => module-apps/apps-common/widgets/spinners/GenericSpinner.hpp +19 -4
@@ 14,6 14,8 @@ namespace gui
        using Range = typename Policy::Range;
        using Type  = typename Policy::Type;

        using OnValueChanged = std::function<void(const Type &&)>;

        explicit GenericSpinner(Range range,
                                Boundaries boundaries   = Boundaries::Continuous,
                                Orientation orientation = Orientation::Vertical);


@@ 26,12 28,15 @@ namespace gui
        bool onInput(const InputEvent &inputEvent) override;
        bool onFocus(bool state) override;

        OnValueChanged onValueChanged;

      private:
        void stepNext();
        void stepPrevious();
        bool isPreviousEvent(const InputEvent &inputEvent);
        bool isNextEvent(const InputEvent &inputEvent);
        void update();
        void invoke();

        Policy policy;
        RectangleEdge focusEdges = RectangleEdge::Bottom;


@@ 113,18 118,28 @@ namespace gui

    template <typename Policy> void GenericSpinner<Policy>::stepNext()
    {
        policy.next();
        update();
        if (policy.next()) {
            update();
            invoke();
        }
    }

    template <typename Policy> void GenericSpinner<Policy>::stepPrevious()
    {
        policy.previous();
        update();
        if (policy.previous()) {
            update();
            invoke();
        }
    }

    template <typename Policy> void GenericSpinner<Policy>::update()
    {
        setText(policy.str());
    }
    template <typename Policy> void GenericSpinner<Policy>::invoke()
    {
        if (onValueChanged) {
            onValueChanged(getCurrentValue());
        }
    }
} // namespace gui

M module-apps/apps-common/widgets/spinners/SpinnerPolicies.hpp => module-apps/apps-common/widgets/spinners/SpinnerPolicies.hpp +24 -6
@@ 40,34 40,40 @@ namespace gui
            }
        }

        void next()
        bool next()
        {
            bool ret{true};
            if (pos >= upRange()) {
                if (boundaries == Boundaries::Continuous) {
                    pos = 0;
                }
                else {
                    pos = upRange();
                    ret = false;
                }
            }
            else {
                pos++;
            }
            return ret;
        }

        void previous()
        bool previous()
        {
            bool ret{true};
            if (pos <= 0) {
                if (boundaries == Boundaries::Continuous) {
                    pos = upRange();
                }
                else {
                    pos = 0;
                    ret = false;
                }
            }
            else {
                pos--;
            }
            return ret;
        }

        void updateRange(Range newRange)


@@ 118,34 124,40 @@ namespace gui
            currentValue = val;
        }

        void next()
        bool next()
        {
            bool ret{true};
            if (currentValue >= range.max) {
                if (boundaries == Boundaries::Continuous) {
                    currentValue = range.min;
                }
                else {
                    currentValue = range.max;
                    ret          = false;
                }
            }
            else {
                currentValue += range.step;
            }
            return ret;
        }

        void previous()
        bool previous()
        {
            bool ret{true};
            if (currentValue <= range.min) {
                if (boundaries == Boundaries::Continuous) {
                    currentValue = range.max;
                }
                else {
                    currentValue = range.min;
                    ret          = false;
                }
            }
            else {
                currentValue -= range.step;
            }
            return ret;
        }

        void updateRange(Range newRange)


@@ 191,34 203,40 @@ namespace gui
            }
        }

        void next()
        bool next()
        {
            bool ret{true};
            if (pos >= upRange()) {
                if (boundaries == Boundaries::Continuous) {
                    pos = 0;
                }
                else {
                    pos = upRange();
                    ret = false;
                }
            }
            else {
                pos++;
            }
            return ret;
        }

        void previous()
        bool previous()
        {
            bool ret{true};
            if (pos <= 0) {
                if (boundaries == Boundaries::Continuous) {
                    pos = upRange();
                }
                else {
                    pos = 0;
                    ret = false;
                }
            }
            else {
                pos--;
            }
            return ret;
        }

        void updateRange(Range newRange)

M products/BellHybrid/alarms/include/AlarmSoundPaths.hpp => products/BellHybrid/alarms/include/AlarmSoundPaths.hpp +1 -0
@@ 7,6 7,7 @@

namespace alarms::paths
{
    std::filesystem::path getAlarmDir() noexcept;
    std::filesystem::path getMusicDir() noexcept;
    std::filesystem::path getPreWakeUpChimesDir() noexcept;
    std::filesystem::path getSnoozeChimesDir() noexcept;

M products/BellHybrid/alarms/src/AlarmSoundPaths.cpp => products/BellHybrid/alarms/src/AlarmSoundPaths.cpp +7 -2
@@ 7,6 7,11 @@

namespace alarms::paths
{
    std::filesystem::path getAlarmDir() noexcept
    {
        return purefs::dir::getCurrentOSPath() / "assets/audio/bell/alarm";
    }

    std::filesystem::path getMusicDir() noexcept
    {
        return purefs::dir::getUserDiskPath() / "music";


@@ 14,10 19,10 @@ namespace alarms::paths

    std::filesystem::path getPreWakeUpChimesDir() noexcept
    {
        return purefs::dir::getCurrentOSPath() / "assets/audio/alarm/prewakeup";
        return purefs::dir::getCurrentOSPath() / "assets/audio/bell/prewakeup";
    }
    std::filesystem::path getSnoozeChimesDir() noexcept
    {
        return purefs::dir::getCurrentOSPath() / "assets/audio/alarm/snooze";
        return purefs::dir::getCurrentOSPath() / "assets/audio/bell/chimes";
    }
} // namespace alarms::paths

M products/BellHybrid/alarms/src/actions/PlayAudioActions.cpp => products/BellHybrid/alarms/src/actions/PlayAudioActions.cpp +2 -2
@@ 58,9 58,9 @@ namespace alarms

    bool PlayToneAction::execute()
    {
        const auto tone     = settings.getValue(bell::settings::Ringing::tone, settings::SettingsScope::Global);
        const auto tone     = settings.getValue(bell::settings::Alarm::tone, settings::SettingsScope::Global);
        const auto tonePath = paths::getMusicDir() / tone;
        const auto valueStr = settings.getValue(bell::settings::Ringing::duration, settings::SettingsScope::Global);
        const auto valueStr = settings.getValue(bell::settings::Alarm::duration, settings::SettingsScope::Global);
        const auto ringingDuration = std::chrono::seconds{utils::getNumericValue<uint32_t>(valueStr)};
        return play(tonePath, ringingDuration);
    }

M products/BellHybrid/apps/CMakeLists.txt => products/BellHybrid/apps/CMakeLists.txt +1 -0
@@ 17,6 17,7 @@ target_link_libraries(app
        apps-common
        bell::app-common
        bell::appmgr
        bell::alarms
)

add_subdirectory(application-bell-main)

M products/BellHybrid/apps/application-bell-main/windows/BellBatteryShutdownWindow.hpp => products/BellHybrid/apps/application-bell-main/windows/BellBatteryShutdownWindow.hpp +2 -2
@@ 12,9 12,9 @@ namespace gui
    class BellBatteryShutdownWindow : public gui::AppWindow
    {
      public:
        static constexpr auto name = "BellBatteryShutdown";
        static constexpr auto defaultName = "BellBatteryShutdown";

        BellBatteryShutdownWindow(app::ApplicationCommon *app, const std::string &name = name);
        BellBatteryShutdownWindow(app::ApplicationCommon *app, const std::string &name = defaultName);

      private:
        void buildInterface() override;

M products/BellHybrid/apps/application-bell-settings/ApplicationBellSettings.cpp => products/BellHybrid/apps/application-bell-settings/ApplicationBellSettings.cpp +19 -8
@@ 28,10 28,12 @@
#include "windows/BellSettingsHomeViewWindow.hpp"
#include "windows/BellSettingsWindow.hpp"

#include <AlarmSoundPaths.hpp>
#include <apps-common/windows/Dialog.hpp>
#include <common/windows/BellFinishedWindow.hpp>
#include <common/windows/BellTurnOffWindow.hpp>
#include <common/popups/BellTurnOffOptionWindow.hpp>
#include <common/models/AudioModel.hpp>
#include <service-evtmgr/Constants.hpp>
#include <service-evtmgr/EventManagerServiceAPI.hpp>
#include <service-evtmgr/ScreenLightControlMessage.hpp>


@@ 141,9 143,12 @@ namespace app
                                                                            std::move(chimeToneModel),
                                                                            std::move(chimeVolumeModel),
                                                                            std::move(lightDurationModel));
                auto provider  = std::make_shared<bell_settings::PrewakeUpListItemProvider>(*prewakeUpSettingsModel);
                auto audioModel       = std::make_unique<AudioModel>(this);
                auto soundsRepository = std::make_unique<SoundsRepository>(alarms::paths::getPreWakeUpChimesDir());
                auto provider         = std::make_shared<bell_settings::PrewakeUpListItemProvider>(
                    *prewakeUpSettingsModel, soundsRepository->getSongTitles());
                auto presenter = std::make_unique<bell_settings::PrewakeUpWindowPresenter>(
                    provider, std::move(prewakeUpSettingsModel));
                    provider, std::move(prewakeUpSettingsModel), std::move(audioModel), std::move(soundsRepository));
                return std::make_unique<gui::BellSettingsPrewakeUpWindow>(app, std::move(presenter));
            });



@@ 165,9 170,12 @@ namespace app
                                                                         std::move(snoozeChimeIntervalModel),
                                                                         std::move(snoozeChimeToneModel),
                                                                         std::move(snoozeChimeVolumeModel));
                auto provider = std::make_shared<bell_settings::SnoozeListItemProvider>(*snoozeSettingsModel);
                auto presenter =
                    std::make_unique<bell_settings::SnoozePresenter>(provider, std::move(snoozeSettingsModel));
                auto audioModel       = std::make_unique<AudioModel>(this);
                auto soundsRepository = std::make_unique<SoundsRepository>(alarms::paths::getSnoozeChimesDir());
                auto provider         = std::make_shared<bell_settings::SnoozeListItemProvider>(
                    *snoozeSettingsModel, soundsRepository->getSongTitles());
                auto presenter = std::make_unique<bell_settings::SnoozePresenter>(
                    provider, std::move(snoozeSettingsModel), std::move(audioModel), std::move(soundsRepository));
                return std::make_unique<gui::BellSettingsAlarmSettingsSnoozeWindow>(app, std::move(presenter));
            });
        windowsFactory.attach(


@@ 177,9 185,12 @@ namespace app
                auto alarmLightOnOffModel = std::make_unique<bell_settings::AlarmLightOnOffModel>(this);
                auto alarmSettingsModel   = std::make_unique<bell_settings::AlarmSettingsModel>(
                    std::move(alarmToneModel), std::move(alarmVolumeModel), std::move(alarmLightOnOffModel));
                auto provider = std::make_shared<bell_settings::AlarmSettingsListItemProvider>(*alarmSettingsModel);
                auto presenter =
                    std::make_unique<bell_settings::AlarmSettingsPresenter>(provider, std::move(alarmSettingsModel));
                auto audioModel       = std::make_unique<AudioModel>(this);
                auto soundsRepository = std::make_unique<SoundsRepository>(alarms::paths::getAlarmDir());
                auto provider         = std::make_shared<bell_settings::AlarmSettingsListItemProvider>(
                    *alarmSettingsModel, soundsRepository->getSongTitles());
                auto presenter = std::make_unique<bell_settings::AlarmSettingsPresenter>(
                    provider, std::move(alarmSettingsModel), std::move(audioModel), std::move(soundsRepository));
                return std::make_unique<gui::BellSettingsAlarmSettingsWindow>(app, std::move(presenter));
            });


M products/BellHybrid/apps/application-bell-settings/CMakeLists.txt => products/BellHybrid/apps/application-bell-settings/CMakeLists.txt +2 -4
@@ 24,7 24,6 @@ target_sources(application-bell-settings
        ApplicationBellSettings.cpp
        models/FrontlightModel.cpp
        models/SettingsModel.cpp
        models/SoundFilesModel.cpp
        models/TemperatureUnitModel.cpp
        models/TimeUnitsModel.cpp
        models/advanced/AboutYourBellModel.cpp


@@ 34,6 33,7 @@ target_sources(application-bell-settings
        models/alarm_settings/PrewakeUpSettingsModel.cpp
        models/alarm_settings/SnoozeListItemProvider.cpp
        models/alarm_settings/SnoozeSettingsModel.cpp
        models/alarm_settings/SettingsListItemProvider.cpp

        presenter/FrontlightPresenter.cpp
        presenter/TimeUnitsPresenter.cpp


@@ 43,7 43,6 @@ target_sources(application-bell-settings
        presenter/alarm_settings/PrewakeUpPresenter.cpp
        presenter/alarm_settings/SnoozePresenter.cpp

        widgets/SoundFileListItem.cpp
        widgets/TemperatureUnitListItem.cpp
        widgets/TimeFormatSetListItem.cpp
        widgets/TimeSetListItem.cpp


@@ 63,7 62,6 @@ target_sources(application-bell-settings
        windows/alarm_settings/BellSettingsPrewakeUpWindow.cpp

        models/SettingsModel.hpp
        models/SoundFilesModel.hpp
        models/advanced/AboutYourBellModel.hpp
        models/alarm_settings/AbstractAlarmSettingsModel.hpp
        models/alarm_settings/AbstractPrewakeUpSettingsModel.hpp


@@ 74,6 72,7 @@ target_sources(application-bell-settings
        models/alarm_settings/PrewakeUpSettingsModel.hpp
        models/alarm_settings/SnoozeListItemProvider.hpp
        models/alarm_settings/SnoozeSettingsModel.hpp
        models/alarm_settings/SettingsListItemProvider.hpp

        presenter/FrontlightPresenter.hpp
        presenter/advanced/AboutYourBellWindowPresenter.hpp


@@ 82,7 81,6 @@ target_sources(application-bell-settings
        presenter/alarm_settings/PrewakeUpPresenter.hpp
        presenter/alarm_settings/SnoozePresenter.hpp

        widgets/SoundFileListItem.hpp
        widgets/TemperatureUnitListItem.hpp
        widgets/TimeFormatSetListItem.hpp
        widgets/TimeSetListItem.hpp

D products/BellHybrid/apps/application-bell-settings/models/SoundFilesModel.cpp => products/BellHybrid/apps/application-bell-settings/models/SoundFilesModel.cpp +0 -78
@@ 1,78 0,0 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "SoundFilesModel.hpp"

#include "AlarmSoundPaths.hpp"

#include <log/log.hpp>
#include <tags_fetcher/TagsFetcher.hpp>

#include <algorithm>

using namespace app::bell_settings;

AlarmSoundsModel::AlarmSoundsModel(AlarmSoundType type) : type{type}
{}

auto AlarmSoundsModel::getSoundFiles() const -> std::vector<std::filesystem::path>
{
    const auto dir = getSoundFilesDir(type);
    if (!std::filesystem::is_directory(dir)) {
        LOG_ERROR("Unable to find directory: %s", dir.c_str());
        return {};
    }
    return scanDirForFiles(dir, {".mp3"});
}

auto AlarmSoundsModel::getSoundFilesDir(AlarmSoundType type) -> std::filesystem::path
{
    switch (type) {
    case AlarmSoundType::PreWakeUp:
        return alarms::paths::getPreWakeUpChimesDir();
    }
    return {};
}

auto AlarmSoundsModel::scanDirForFiles(const std::filesystem::path &dir, std::vector<std::string> extensions)
    -> std::vector<std::filesystem::path>
{
    std::vector<std::filesystem::path> files;
    for (const auto &entry : std::filesystem::directory_iterator(dir)) {
        if (!std::filesystem::is_regular_file(entry)) {
            continue;
        }

        const auto &filePath = entry.path();
        if (const auto it = std::find(extensions.begin(), extensions.end(), filePath.extension());
            it != extensions.end()) {
            files.push_back(filePath);
        }
    }
    return files;
}

auto AlarmSoundDelegate::fromModel(const AlarmSoundsModel &model) -> std::vector<AlarmSoundDelegate>
{
    const auto files = model.getSoundFiles();

    std::vector<AlarmSoundDelegate> delegates;
    delegates.reserve(files.size());
    std::transform(files.begin(), files.end(), std::back_inserter(delegates), [](const auto &filepath) {
        return AlarmSoundDelegate{filepath};
    });
    return delegates;
}

AlarmSoundDelegate::AlarmSoundDelegate(const std::filesystem::path &filePath) : path{filePath}
{}

AlarmSoundDelegate::AlarmSoundDelegate(AlarmSoundType type, const std::string &filename)
    : path{AlarmSoundsModel::getSoundFilesDir(type) / filename}
{}

AlarmSoundDelegate::operator UTF8() const
{
    auto tags = tags::fetcher::fetchTags(path);
    return tags.title;
}

D products/BellHybrid/apps/application-bell-settings/models/SoundFilesModel.hpp => products/BellHybrid/apps/application-bell-settings/models/SoundFilesModel.hpp +0 -56
@@ 1,56 0,0 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <utf8/UTF8.hpp>

#include <filesystem>
#include <string>
#include <vector>

namespace app::bell_settings
{
    enum class AlarmSoundType
    {
        PreWakeUp
    };

    class AlarmSoundsModel
    {
      public:
        explicit AlarmSoundsModel(AlarmSoundType type);
        auto getSoundFiles() const -> std::vector<std::filesystem::path>;
        static auto getSoundFilesDir(AlarmSoundType type) -> std::filesystem::path;

      private:
        static auto scanDirForFiles(const std::filesystem::path &dir, std::vector<std::string> extensions)
            -> std::vector<std::filesystem::path>;

        AlarmSoundType type;
    };

    struct AlarmSoundDelegate
    {
      public:
        static auto fromModel(const AlarmSoundsModel &model) -> std::vector<AlarmSoundDelegate>;

        AlarmSoundDelegate() = default;
        explicit AlarmSoundDelegate(const std::filesystem::path &filePath);
        AlarmSoundDelegate(AlarmSoundType type, const std::string &fileName);

        operator UTF8() const;

        friend bool operator==(const AlarmSoundDelegate &lhs, const AlarmSoundDelegate &rhs) noexcept
        {
            return lhs.path == rhs.path;
        }

        friend bool operator!=(const AlarmSoundDelegate &lhs, const AlarmSoundDelegate &rhs) noexcept
        {
            return !operator==(lhs, rhs);
        }

        const std::filesystem::path path;
    };
} // namespace app::bell_settings

M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/AbstractPrewakeUpSettingsModel.hpp => products/BellHybrid/apps/application-bell-settings/models/alarm_settings/AbstractPrewakeUpSettingsModel.hpp +4 -3
@@ 4,6 4,7 @@
#pragma once

#include <common/models/AbstractSettingsModel.hpp>
#include <utf8/UTF8.hpp>

#include <cstdint>
#include <memory>


@@ 15,7 16,7 @@ namespace app::bell_settings
    {
      public:
        AbstractPrewakeUpSettingsModel(std::unique_ptr<gui::AbstractSettingsModel<std::uint8_t>> chimeDuration,
                                       std::unique_ptr<gui::AbstractSettingsModel<std::string>> chimeTone,
                                       std::unique_ptr<gui::AbstractSettingsModel<UTF8>> chimeTone,
                                       std::unique_ptr<gui::AbstractSettingsModel<std::uint8_t>> chimeVolume,
                                       std::unique_ptr<gui::AbstractSettingsModel<std::uint8_t>> lightDuration)
            : chimeDuration(std::move(chimeDuration)), chimeTone(std::move(chimeTone)),


@@ 29,7 30,7 @@ namespace app::bell_settings
            return *chimeDuration;
        }

        gui::AbstractSettingsModel<std::string> &getChimeTone()
        gui::AbstractSettingsModel<UTF8> &getChimeTone()
        {
            return *chimeTone;
        }


@@ 46,7 47,7 @@ namespace app::bell_settings

      private:
        std::unique_ptr<gui::AbstractSettingsModel<std::uint8_t>> chimeDuration;
        std::unique_ptr<gui::AbstractSettingsModel<std::string>> chimeTone;
        std::unique_ptr<gui::AbstractSettingsModel<UTF8>> chimeTone;
        std::unique_ptr<gui::AbstractSettingsModel<std::uint8_t>> chimeVolume;
        std::unique_ptr<gui::AbstractSettingsModel<std::uint8_t>> lightDuration;
    };

M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/AlarmSettingsListItemProvider.cpp => products/BellHybrid/apps/application-bell-settings/models/alarm_settings/AlarmSettingsListItemProvider.cpp +45 -44
@@ 2,36 2,69 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "BellSettingsStyle.hpp"
#include <common/widgets/ListItems.hpp>
#include "AlarmSettingsListItemProvider.hpp"

#include <common/widgets/ListItems.hpp>
#include <apps-common/ApplicationCommon.hpp>
#include <gui/widgets/ListViewEngine.hpp>

namespace app::bell_settings
{
    using namespace gui;

    AlarmSettingsListItemProvider::AlarmSettingsListItemProvider(AbstractAlarmSettingsModel &model) : model{model}
    AlarmSettingsListItemProvider::AlarmSettingsListItemProvider(AbstractAlarmSettingsModel &model,
                                                                 std::vector<UTF8> alarmToneRange)
        : model{model}
    {
        buildListItems();
        buildListItems(std::move(alarmToneRange));
    }

    void AlarmSettingsListItemProvider::buildListItems()
    void AlarmSettingsListItemProvider::buildListItems(std::vector<UTF8> alarmTonesRange)
    {
        constexpr auto itemCount = 4U;
        internalData.reserve(itemCount);

        const auto textRange = UTF8Spinner::Range{{"Meditative\nsurprises"}};
        internalData.emplace_back(new UTF8ListItem(
            model.getAlarmTone(), textRange, utils::translate("app_bell_settings_alarm_settings_tone")));
        auto alarmTone = new UTF8ListItem(model.getAlarmTone(),
                                          std::move(alarmTonesRange),
                                          utils::translate("app_bell_settings_alarm_settings_tone"));
        alarmTone->setOnValueChanged([this](const UTF8 &val) {
            if (onToneChange) {
                onToneChange(val);
            }
        });
        alarmTone->onEnter = [this, alarmTone]() {
            if (onToneEnter) {
                onToneEnter(alarmTone->getCurrentValue());
            }
        };
        alarmTone->onExit = [this, alarmTone]() {
            if (onToneExit) {
                onToneExit(alarmTone->getCurrentValue());
            }
        };
        internalData.emplace_back(alarmTone);

        constexpr auto volumeStep = 1U;
        constexpr auto volumeMin  = 1U;
        constexpr auto volumeMax  = 10U;
        internalData.emplace_back(new NumListItem(model.getAlarmVolume(),
                                                  UIntegerSpinner::Range{volumeMin, volumeMax, volumeStep},
                                                  utils::translate("app_bell_settings_alarm_settings_volume")));
        auto alarmVolume          = new NumListItem(model.getAlarmVolume(),
                                           UIntegerSpinner::Range{volumeMin, volumeMax, volumeStep},
                                           utils::translate("app_bell_settings_alarm_settings_volume"));
        alarmVolume->setOnValueChanged([this](const UIntegerSpinner::Type &val) {
            if (onVolumeChange) {
                onVolumeChange(val);
            }
        });
        alarmVolume->onEnter = [this, alarmTone]() {
            if (onVolumeEnter) {
                onVolumeEnter(alarmTone->getCurrentValue());
            }
        };
        alarmVolume->onExit = [this, alarmVolume]() {
            if (onVolumeExit) {
                onVolumeExit(alarmVolume->getCurrentValue());
            }
        };

        internalData.emplace_back(alarmVolume);

        internalData.emplace_back(
            new OnOffListItem(model.getAlarmLightOnOff(), utils::translate("app_bell_settings_alarm_settings_light")));


@@ 40,36 73,4 @@ namespace app::bell_settings
            item->deleteByList = false;
        }
    }

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

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

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

    auto AlarmSettingsListItemProvider::getMinimalItemSpaceRequired() const -> unsigned int
    {
        return style::sidelistview::list_item::w;
    }

    std::vector<BellSideListItemWithCallbacks *> AlarmSettingsListItemProvider::getListItems()
    {
        return internalData;
    }

    void AlarmSettingsListItemProvider::clearData()
    {
        list->reset();
        eraseInternalData();
    }
} // namespace app::bell_settings

M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/AlarmSettingsListItemProvider.hpp => products/BellHybrid/apps/application-bell-settings/models/alarm_settings/AlarmSettingsListItemProvider.hpp +5 -21
@@ 3,34 3,18 @@

#pragma once

#include <models/alarm_settings/AbstractAlarmSettingsModel.hpp>
#include <common/widgets/BellSideListItemWithCallbacks.hpp>
#include <apps-common/InternalModel.hpp>
#include "SettingsListItemProvider.hpp"
#include "AbstractAlarmSettingsModel.hpp"

namespace app::bell_settings
{
    class AlarmSettingsListItemProvider : public app::InternalModel<gui::BellSideListItemWithCallbacks *>,
                                          public gui::ListItemProvider
    class AlarmSettingsListItemProvider : public SettingsListItemProvider
    {
      public:
        explicit AlarmSettingsListItemProvider(AbstractAlarmSettingsModel &model);

        std::vector<gui::BellSideListItemWithCallbacks *> getListItems();

        auto requestRecords(uint32_t offset, 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;

        void clearData();

        std::function<void()> onExit;
        AlarmSettingsListItemProvider(AbstractAlarmSettingsModel &model, std::vector<UTF8> alarmToneRange);

      private:
        void buildListItems();
        void buildListItems(std::vector<UTF8> alarmTonesRange);

        AbstractAlarmSettingsModel &model;
    };

M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/PrewakeUpListItemProvider.cpp => products/BellHybrid/apps/application-bell-settings/models/alarm_settings/PrewakeUpListItemProvider.cpp +47 -48
@@ 1,24 1,24 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "BellSettingsStyle.hpp"
#include <common/widgets/ListItems.hpp>
#include "PrewakeUpListItemProvider.hpp"

#include <common/widgets/ListItems.hpp>
#include <apps-common/ApplicationCommon.hpp>
#include <gui/widgets/ListViewEngine.hpp>
#include <widgets/SoundFileListItem.hpp>
#include <utility>

namespace app::bell_settings
{
    using namespace gui;

    PrewakeUpListItemProvider::PrewakeUpListItemProvider(AbstractPrewakeUpSettingsModel &model) : model{model}
    PrewakeUpListItemProvider::PrewakeUpListItemProvider(AbstractPrewakeUpSettingsModel &model,
                                                         std::vector<UTF8> chimeToneRange)
        : model{model}
    {
        buildListItems();
        buildListItems(std::move(chimeToneRange));
    }

    void PrewakeUpListItemProvider::buildListItems()
    void PrewakeUpListItemProvider::buildListItems(std::vector<UTF8> chimeToneRange)
    {
        constexpr auto itemCount = 4U;
        internalData.reserve(itemCount);


@@ 42,19 42,50 @@ namespace app::bell_settings
        };
        internalData.emplace_back(chimeDuration);

        internalData.emplace_back(
            new SoundFileListItem(model.getChimeTone(),
                                  AlarmSoundType::PreWakeUp,
                                  AlarmSoundDelegate::fromModel(AlarmSoundsModel{AlarmSoundType::PreWakeUp}),
                                  utils::translate("app_bell_settings_alarm_settings_prewake_up_chime_tone")));
        auto chimeTone = new UTF8ListItem(model.getChimeTone(),
                                          std::move(chimeToneRange),
                                          utils::translate("app_bell_settings_alarm_settings_prewake_up_chime_tone"));
        chimeTone->setOnValueChanged([this](const UTF8 &val) {
            if (onToneChange) {
                onToneChange(val);
            }
        });
        chimeTone->onEnter = [this, chimeTone]() {
            if (onToneEnter) {
                onToneEnter(chimeTone->getCurrentValue());
            }
        };
        chimeTone->onExit = [this, chimeTone]() {
            if (onToneExit) {
                onToneExit(chimeTone->getCurrentValue());
            }
        };
        internalData.emplace_back(chimeTone);

        constexpr auto volumeStep = 1U;
        constexpr auto volumeMin  = 1U;
        constexpr auto volumeMax  = 10U;
        internalData.emplace_back(
            new NumListItem(model.getChimeVolume(),
                            UIntegerSpinner::Range{volumeMin, volumeMax, volumeStep},
                            utils::translate("app_bell_settings_alarm_settings_prewake_up_chime_volume")));
        auto volume               = new NumListItem(model.getChimeVolume(),
                                      UIntegerSpinner::Range{volumeMin, volumeMax, volumeStep},
                                      utils::translate("app_bell_settings_alarm_settings_prewake_up_chime_volume"));
        volume->setOnValueChanged([this](const UIntegerSpinner::Type &val) {
            if (onVolumeChange) {
                onVolumeChange(val);
            }
        });

        volume->onEnter = [this, chimeTone]() {
            if (onVolumeEnter) {
                onVolumeEnter(chimeTone->getCurrentValue());
            }
        };

        volume->onExit = [this, volume]() {
            if (onVolumeExit) {
                onVolumeExit(volume->getCurrentValue());
            }
        };
        internalData.emplace_back(volume);

        const auto lightDurationRange = NumWithStringListItem::NumWithStringSpinner::Range{
            NumWithStringListItem::Value{utils::translate("app_settings_toggle_off")},


@@ 77,36 108,4 @@ namespace app::bell_settings
            item->deleteByList = false;
        }
    }

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

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

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

    auto PrewakeUpListItemProvider::getMinimalItemSpaceRequired() const -> unsigned int
    {
        return style::sidelistview::list_item::w;
    }

    std::vector<BellSideListItemWithCallbacks *> PrewakeUpListItemProvider::getListItems()
    {
        return internalData;
    }

    void PrewakeUpListItemProvider::clearData()
    {
        list->reset();
        eraseInternalData();
    }
} // namespace app::bell_settings

M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/PrewakeUpListItemProvider.hpp => products/BellHybrid/apps/application-bell-settings/models/alarm_settings/PrewakeUpListItemProvider.hpp +5 -21
@@ 3,34 3,18 @@

#pragma once

#include <models/alarm_settings/AbstractPrewakeUpSettingsModel.hpp>
#include <common/widgets/BellSideListItemWithCallbacks.hpp>
#include <apps-common/InternalModel.hpp>
#include "SettingsListItemProvider.hpp"
#include "AbstractPrewakeUpSettingsModel.hpp"

namespace app::bell_settings
{
    class PrewakeUpListItemProvider : public app::InternalModel<gui::BellSideListItemWithCallbacks *>,
                                      public gui::ListItemProvider
    class PrewakeUpListItemProvider : public SettingsListItemProvider
    {
      public:
        explicit PrewakeUpListItemProvider(AbstractPrewakeUpSettingsModel &model);

        std::vector<gui::BellSideListItemWithCallbacks *> getListItems();

        auto requestRecords(uint32_t offset, 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;

        void clearData();

        std::function<void()> onExit;
        PrewakeUpListItemProvider(AbstractPrewakeUpSettingsModel &model, std::vector<UTF8> chimeToneRange);

      private:
        void buildListItems();
        void buildListItems(std::vector<UTF8> preWakeupToneRange);

        AbstractPrewakeUpSettingsModel &model;
    };

M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/PrewakeUpSettingsModel.cpp => products/BellHybrid/apps/application-bell-settings/models/alarm_settings/PrewakeUpSettingsModel.cpp +2 -2
@@ 20,12 20,12 @@ namespace app::bell_settings
        return std::stoi(str);
    }

    void PrewakeUpChimeToneModel::setValue(std::string value)
    void PrewakeUpChimeToneModel::setValue(UTF8 value)
    {
        settings.setValue(bell::settings::PrewakeUp::tone, value, settings::SettingsScope::Global);
    }

    std::string PrewakeUpChimeToneModel::getValue() const
    UTF8 PrewakeUpChimeToneModel::getValue() const
    {
        return settings.getValue(bell::settings::PrewakeUp::tone, settings::SettingsScope::Global);
    }

M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/PrewakeUpSettingsModel.hpp => products/BellHybrid/apps/application-bell-settings/models/alarm_settings/PrewakeUpSettingsModel.hpp +3 -3
@@ 17,13 17,13 @@ namespace app::bell_settings
        std::uint8_t getValue() const override;
    };

    class PrewakeUpChimeToneModel : public gui::SettingsModel<std::string>
    class PrewakeUpChimeToneModel : public gui::SettingsModel<UTF8>
    {
      public:
        using SettingsModel::SettingsModel;

        void setValue(std::string value) override;
        std::string getValue() const override;
        void setValue(UTF8 value) override;
        UTF8 getValue() const override;
    };

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

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

#include "SettingsListItemProvider.hpp"
#include <gui/widgets/ListViewEngine.hpp>

namespace app::bell_settings
{

    std::vector<gui::BellSideListItemWithCallbacks *> SettingsListItemProvider::getListItems()
    {
        return internalData;
    }
    auto SettingsListItemProvider::requestRecords(uint32_t offset, uint32_t limit) -> void
    {
        setupModel(offset, limit);
        list->onProviderDataUpdate();
    }
    auto SettingsListItemProvider::getItem(gui::Order order) -> gui::ListItem *
    {
        return getRecord(order);
    }
    auto SettingsListItemProvider::requestRecordsCount() -> unsigned int
    {
        return internalData.size();
    }
    auto SettingsListItemProvider::getMinimalItemSpaceRequired() const -> unsigned int
    {
        return style::sidelistview::list_item::w;
    }
    void SettingsListItemProvider::clearData()
    {
        list->reset();
        eraseInternalData();
    }
} // namespace app::bell_settings

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

#pragma once

#include <common/widgets/BellSideListItemWithCallbacks.hpp>
#include <apps-common/InternalModel.hpp>

namespace app::bell_settings
{

    class SettingsListItemProvider : public app::InternalModel<gui::BellSideListItemWithCallbacks *>,
                                     public gui::ListItemProvider
    {
      public:
        /// Val contains currently chosen tone
        using ToneCallback = std::function<void(const UTF8 &val)>;
        /// Val contains currently chosen volume(1-10 range)
        using VolumeCallback      = std::function<void(const uint32_t &val)>;
        using VolumeEnterCallback = ToneCallback;

        std::vector<gui::BellSideListItemWithCallbacks *> getListItems();

        auto requestRecords(uint32_t offset, 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;

        void clearData();

        std::function<void()> onExit;

        ToneCallback onToneEnter;
        ToneCallback onToneExit;
        ToneCallback onToneChange;

        VolumeEnterCallback onVolumeEnter;
        VolumeCallback onVolumeExit;
        VolumeCallback onVolumeChange;
    };

} // namespace app::bell_settings

M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/SnoozeListItemProvider.cpp => products/BellHybrid/apps/application-bell-settings/models/alarm_settings/SnoozeListItemProvider.cpp +48 -38
@@ 1,23 1,24 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "BellSettingsStyle.hpp"
#include "SnoozeListItemProvider.hpp"
#include <common/widgets/ListItems.hpp>

#include <apps-common/ApplicationCommon.hpp>
#include <gui/widgets/ListViewEngine.hpp>
#include <utility>

namespace app::bell_settings
{
    using namespace gui;

    SnoozeListItemProvider::SnoozeListItemProvider(AbstractSnoozeSettingsModel &model) : model{model}
    SnoozeListItemProvider::SnoozeListItemProvider(AbstractSnoozeSettingsModel &model,
                                                   std::vector<UTF8> chimeTonesRange)
        : model{model}
    {
        buildListItems();
        buildListItems(chimeTonesRange);
    }

    void SnoozeListItemProvider::buildListItems()
    void SnoozeListItemProvider::buildListItems(std::vector<UTF8> chimeTonesRange)
    {
        constexpr auto itemCount = 5U;
        internalData.reserve(itemCount);


@@ 55,48 56,57 @@ namespace app::bell_settings
            }
        };
        internalData.emplace_back(chimeInterval);
        const auto textRange = UTF8Spinner::Range{{"Meditative\nsurprises"}}; // TODO: Full list needed
        internalData.emplace_back(
            new UTF8ListItem(model.getSnoozeChimeTone(),
                             textRange,
                             utils::translate("app_bell_settings_alarm_settings_snooze_chime_tone")));

        auto snoozeChimeTone = new UTF8ListItem(model.getSnoozeChimeTone(),
                                                std::move(chimeTonesRange),
                                                utils::translate("app_bell_settings_alarm_settings_snooze_chime_tone"));
        snoozeChimeTone->setOnValueChanged([this](const UTF8 &val) {
            if (onToneChange) {
                onToneChange(val);
            }
        });
        snoozeChimeTone->onEnter = [this, snoozeChimeTone]() {
            if (onToneEnter) {
                onToneEnter(snoozeChimeTone->getCurrentValue());
            }
        };
        snoozeChimeTone->onExit = [this, snoozeChimeTone]() {
            if (onToneExit) {
                onToneExit(snoozeChimeTone->getCurrentValue());
            }
        };
        internalData.emplace_back(snoozeChimeTone);

        constexpr auto volumeStep = 1U;
        constexpr auto volumeMin  = 1U;
        constexpr auto volumeMax  = 10U;
        internalData.emplace_back(
        auto snoozeChimeVolume =
            new NumListItem(model.getSnoozeChimeVolume(),
                            UIntegerSpinner::Range{volumeMin, volumeMax, volumeStep},
                            utils::translate("app_bell_settings_alarm_settings_snooze_chime_volume")));

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

    auto SnoozeListItemProvider::requestRecords(uint32_t offset, uint32_t limit) -> void
    {
        setupModel(offset, limit);
        list->onProviderDataUpdate();
    }
                            utils::translate("app_bell_settings_alarm_settings_snooze_chime_volume"));
        snoozeChimeVolume->setOnValueChanged([this](const UIntegerSpinner::Type &val) {
            if (onVolumeChange) {
                onVolumeChange(val);
            }
        });

    auto SnoozeListItemProvider::getItem(Order order) -> ListItem *
    {
        return getRecord(order);
    }
        snoozeChimeVolume->onEnter = [this, snoozeChimeTone]() {
            if (onVolumeEnter) {
                onVolumeEnter(snoozeChimeTone->getCurrentValue());
            }
        };

    auto SnoozeListItemProvider::requestRecordsCount() -> unsigned int
    {
        return internalData.size();
    }
        snoozeChimeVolume->onExit = [this, snoozeChimeVolume]() {
            if (onVolumeExit) {
                onVolumeExit(snoozeChimeVolume->getCurrentValue());
            }
        };

    auto SnoozeListItemProvider::getMinimalItemSpaceRequired() const -> unsigned int
    {
        return style::sidelistview::list_item::w;
    }
        internalData.emplace_back(snoozeChimeVolume);

    std::vector<BellSideListItemWithCallbacks *> SnoozeListItemProvider::getListItems()
    {
        return internalData;
        for (auto item : internalData) {
            item->deleteByList = false;
        }
    }

} // namespace app::bell_settings

M products/BellHybrid/apps/application-bell-settings/models/alarm_settings/SnoozeListItemProvider.hpp => products/BellHybrid/apps/application-bell-settings/models/alarm_settings/SnoozeListItemProvider.hpp +5 -19
@@ 3,32 3,18 @@

#pragma once

#include <models/alarm_settings/AbstractSnoozeSettingsModel.hpp>
#include <common/widgets/BellSideListItemWithCallbacks.hpp>
#include <apps-common/InternalModel.hpp>
#include "SettingsListItemProvider.hpp"
#include "AbstractSnoozeSettingsModel.hpp"

namespace app::bell_settings
{
    class SnoozeListItemProvider : public app::InternalModel<gui::BellSideListItemWithCallbacks *>,
                                   public gui::ListItemProvider
    class SnoozeListItemProvider : public SettingsListItemProvider
    {
      public:
        explicit SnoozeListItemProvider(AbstractSnoozeSettingsModel &model);

        std::vector<gui::BellSideListItemWithCallbacks *> getListItems();

        auto requestRecords(uint32_t offset, 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;

        std::function<void()> onExit;
        SnoozeListItemProvider(AbstractSnoozeSettingsModel &model, std::vector<UTF8> chimeTonesRange);

      private:
        void buildListItems();
        void buildListItems(std::vector<UTF8> chimeTonesRange);

        AbstractSnoozeSettingsModel &model;
    };

M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/AlarmSettingsPresenter.cpp => products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/AlarmSettingsPresenter.cpp +35 -2
@@ 7,10 7,39 @@
namespace app::bell_settings
{
    AlarmSettingsPresenter::AlarmSettingsPresenter(std::shared_ptr<AlarmSettingsListItemProvider> provider,
                                                   std::unique_ptr<AbstractAlarmSettingsModel> model)
        : provider(std::move(provider)), model(std::move(model))
                                                   std::unique_ptr<AbstractAlarmSettingsModel> model,
                                                   std::unique_ptr<AbstractAudioModel> audioModel,
                                                   std::unique_ptr<AbstractSoundsRepository> soundsRepository)
        : provider(provider),
          model(std::move(model)), audioModel{std::move(audioModel)}, soundsRepository{std::move(soundsRepository)}
    {
        auto playResponseCb = [this](audio::RetCode retCode, audio::Token token) {
            if (retCode != audio::RetCode::Success || !token.IsValid()) {
                LOG_ERROR("Audio preview callback failed with retcode = %s. Token validity: %d",
                          str(retCode).c_str(),
                          token.IsValid());
                return;
            }
            this->currentToken = token;
        };

        auto playSound = [this, playResponseCb](const UTF8 &val) {
            this->audioModel->play(this->soundsRepository->titleToPath(val).value_or(""),
                                   playResponseCb,
                                   AbstractAudioModel::PlaybackType::Alarm);
        };

        this->provider->onExit = [this]() { getView()->exit(); };

        this->provider->onToneEnter  = playSound;
        this->provider->onToneExit   = [this](const auto &) { stopSound(); };
        this->provider->onToneChange = playSound;

        this->provider->onVolumeEnter  = playSound;
        this->provider->onVolumeExit   = [this](const auto &) { stopSound(); };
        this->provider->onVolumeChange = [this](const auto &val) {
            this->audioModel->setVolume(val, AbstractAudioModel::PlaybackType::Alarm);
        };
    }

    auto AlarmSettingsPresenter::saveData() -> void


@@ 36,4 65,8 @@ namespace app::bell_settings
    {
        provider->clearData();
    }
    void AlarmSettingsPresenter::stopSound()
    {
        this->audioModel->stop(currentToken, nullptr);
    }
} // namespace app::bell_settings

M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/AlarmSettingsPresenter.hpp => products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/AlarmSettingsPresenter.hpp +11 -1
@@ 4,6 4,9 @@
#pragma once

#include <apps-common/BasePresenter.hpp>
#include <apps-common/AudioOperations.hpp>
#include <common/models/AbstractAudioModel.hpp>
#include <common/SoundsRepository.hpp>
#include <memory>

namespace gui


@@ 41,7 44,9 @@ namespace app::bell_settings
    {
      public:
        AlarmSettingsPresenter(std::shared_ptr<AlarmSettingsListItemProvider> provider,
                               std::unique_ptr<AbstractAlarmSettingsModel> model);
                               std::unique_ptr<AbstractAlarmSettingsModel> model,
                               std::unique_ptr<AbstractAudioModel> audioModel,
                               std::unique_ptr<AbstractSoundsRepository> soundsRepository);

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


@@ 49,7 54,12 @@ namespace app::bell_settings
        auto eraseProviderData() -> void override;

      private:
        void stopSound();

        std::shared_ptr<AlarmSettingsListItemProvider> provider;
        std::unique_ptr<AbstractAlarmSettingsModel> model;
        std::unique_ptr<AbstractAudioModel> audioModel;
        std::unique_ptr<AbstractSoundsRepository> soundsRepository;
        audio::Token currentToken;
    };
} // namespace app::bell_settings

M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/PrewakeUpPresenter.cpp => products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/PrewakeUpPresenter.cpp +38 -2
@@ 7,10 7,42 @@
namespace app::bell_settings
{
    PrewakeUpWindowPresenter::PrewakeUpWindowPresenter(std::shared_ptr<PrewakeUpListItemProvider> provider,
                                                       std::unique_ptr<AbstractPrewakeUpSettingsModel> model)
        : provider(std::move(provider)), model(std::move(model))
                                                       std::unique_ptr<AbstractPrewakeUpSettingsModel> model,
                                                       std::unique_ptr<AbstractAudioModel> audioModel,
                                                       std::unique_ptr<AbstractSoundsRepository> soundsRepository)
        : provider(std::move(provider)),
          model(std::move(model)), audioModel{std::move(audioModel)}, soundsRepository{std::move(soundsRepository)}
    {

        auto playResponseCb = [this](audio::RetCode retCode, audio::Token token) {
            if (retCode != audio::RetCode::Success || !token.IsValid()) {
                LOG_ERROR("Audio preview callback failed with retcode = %s. Token validity: %d",
                          str(retCode).c_str(),
                          token.IsValid());
                return;
            }
            this->currentToken = token;
        };

        auto playSound = [this, playResponseCb](const UTF8 &val) {
            currentSoundPath = val;
            this->audioModel->play(this->soundsRepository->titleToPath(currentSoundPath).value_or(""),
                                   playResponseCb,
                                   AbstractAudioModel::PlaybackType::PreWakeup);
        };

        this->provider->onExit = [this]() { getView()->exit(); };

        this->provider->onToneEnter  = playSound;
        this->provider->onToneExit   = [this](const auto &) { stopSound(); };
        this->provider->onToneChange = playSound;

        this->provider->onVolumeEnter  = playSound;
        this->provider->onVolumeExit   = [this](const auto &) { this->audioModel->stop(currentToken, nullptr); };
        this->provider->onVolumeChange = [this, playSound](const auto &val) {
            this->audioModel->setVolume(val, AbstractAudioModel::PlaybackType::PreWakeup);
            playSound(currentSoundPath);
        };
    }

    auto PrewakeUpWindowPresenter::saveData() -> void


@@ 36,4 68,8 @@ namespace app::bell_settings
    {
        provider->clearData();
    }
    void PrewakeUpWindowPresenter::stopSound()
    {
        this->audioModel->stop(currentToken, nullptr);
    }
} // namespace app::bell_settings

M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/PrewakeUpPresenter.hpp => products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/PrewakeUpPresenter.hpp +12 -1
@@ 4,7 4,10 @@
#pragma once

#include <apps-common/BasePresenter.hpp>
#include <apps-common/AudioOperations.hpp>
#include <models/alarm_settings/AbstractPrewakeUpSettingsModel.hpp>
#include <common/models/AbstractAudioModel.hpp>
#include <common/SoundsRepository.hpp>
#include <memory>

namespace gui


@@ 41,7 44,9 @@ namespace app::bell_settings
    {
      public:
        PrewakeUpWindowPresenter(std::shared_ptr<PrewakeUpListItemProvider> provider,
                                 std::unique_ptr<AbstractPrewakeUpSettingsModel> model);
                                 std::unique_ptr<AbstractPrewakeUpSettingsModel> model,
                                 std::unique_ptr<AbstractAudioModel> audioModel,
                                 std::unique_ptr<AbstractSoundsRepository> soundsRepository);

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


@@ 49,7 54,13 @@ namespace app::bell_settings
        auto eraseProviderData() -> void override;

      private:
        void stopSound();

        std::shared_ptr<PrewakeUpListItemProvider> provider;
        std::unique_ptr<AbstractPrewakeUpSettingsModel> model;
        std::unique_ptr<AbstractAudioModel> audioModel;
        std::unique_ptr<AbstractSoundsRepository> soundsRepository;
        audio::Token currentToken;
        UTF8 currentSoundPath;
    };
} // namespace app::bell_settings

M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/SnoozePresenter.cpp => products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/SnoozePresenter.cpp +38 -4
@@ 2,21 2,51 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "SnoozePresenter.hpp"

#include "models/alarm_settings/SnoozeListItemProvider.hpp"

namespace app::bell_settings
{

    SnoozePresenter::SnoozePresenter(std::shared_ptr<SnoozeListItemProvider> provider,
                                     std::unique_ptr<AbstractSnoozeSettingsModel> snoozeSettingsModel)
        : provider{provider}, snoozeSettingsModel{std::move(snoozeSettingsModel)}
                                     std::unique_ptr<AbstractSnoozeSettingsModel> snoozeSettingsModel,
                                     std::unique_ptr<AbstractAudioModel> audioModel,
                                     std::unique_ptr<AbstractSoundsRepository> soundsRepository)
        : provider{provider}, snoozeSettingsModel{std::move(snoozeSettingsModel)}, audioModel{std::move(audioModel)},
          soundsRepository{std::move(soundsRepository)}
    {
        provider->onExit = [this]() { getView()->exit(); };
        auto playResponseCb = [this](audio::RetCode retCode, audio::Token token) {
            if (retCode != audio::RetCode::Success || !token.IsValid()) {
                LOG_ERROR("Audio preview callback failed with retcode = %s. Token validity: %d",
                          str(retCode).c_str(),
                          token.IsValid());
                return;
            }
            this->currentToken = token;
        };

        auto playSound = [this, playResponseCb](const UTF8 &val) {
            currentSoundPath = val;
            this->audioModel->play(this->soundsRepository->titleToPath(currentSoundPath).value_or(""),
                                   playResponseCb,
                                   AbstractAudioModel::PlaybackType::Chime);
        };

        this->provider->onExit = [this]() { getView()->exit(); };

        this->provider->onToneEnter  = playSound;
        this->provider->onToneExit   = [this](const auto &) { stopSound(); };
        this->provider->onToneChange = playSound;

        this->provider->onVolumeEnter  = playSound;
        this->provider->onVolumeChange = [this, playSound](const auto &val) {
            this->audioModel->setVolume(val, AbstractAudioModel::PlaybackType::Chime);
            playSound(currentSoundPath);
        };
    }

    void SnoozePresenter::saveData()
    {
        stopSound();
        for (const auto &item : provider->getListItems()) {
            item->getValue();
        }


@@ 33,4 63,8 @@ namespace app::bell_settings
    {
        return provider;
    }
    void SnoozePresenter::stopSound()
    {
        audioModel->stop(currentToken, nullptr);
    }
} // namespace app::bell_settings

M products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/SnoozePresenter.hpp => products/BellHybrid/apps/application-bell-settings/presenter/alarm_settings/SnoozePresenter.hpp +12 -1
@@ 5,6 5,8 @@

#include <apps-common/BasePresenter.hpp>
#include <models/alarm_settings/AbstractSnoozeSettingsModel.hpp>
#include <common/models/AbstractAudioModel.hpp>
#include <common/SoundsRepository.hpp>
#include <memory>

namespace gui


@@ 36,13 38,22 @@ namespace app::bell_settings
    {
      public:
        SnoozePresenter(std::shared_ptr<SnoozeListItemProvider> provider,
                        std::unique_ptr<AbstractSnoozeSettingsModel> snoozeSettingsModel);
                        std::unique_ptr<AbstractSnoozeSettingsModel> snoozeSettingsModel,
                        std::unique_ptr<AbstractAudioModel> audioModel,
                        std::unique_ptr<AbstractSoundsRepository> soundsRepository);
        auto getPagesProvider() const -> std::shared_ptr<gui::ListItemProvider> override;
        void saveData() override;
        void loadData() override;

      private:
        void stopSound();

        std::shared_ptr<SnoozeListItemProvider> provider;
        std::unique_ptr<AbstractSnoozeSettingsModel> snoozeSettingsModel;
        std::unique_ptr<AbstractAudioModel> audioModel;
        std::unique_ptr<AbstractSoundsRepository> soundsRepository;

        audio::Token currentToken;
        UTF8 currentSoundPath;
    };
} // namespace app::bell_settings

D products/BellHybrid/apps/application-bell-settings/widgets/SoundFileListItem.cpp => products/BellHybrid/apps/application-bell-settings/widgets/SoundFileListItem.cpp +0 -27
@@ 1,27 0,0 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "SoundFileListItem.hpp"

#include <common/data/StyleCommon.hpp>

using namespace gui;

SoundFileListItem::SoundFileListItem(AbstractSettingsModel<std::string> &model,
                                     app::bell_settings::AlarmSoundType soundType,
                                     typename ModelDelegateSpinner<app::bell_settings::AlarmSoundDelegate>::Range range,
                                     const std::string &topDescription)
    : BellSideListItemWithCallbacks(topDescription)
{
    spinner = new ModelDelegateSpinner<app::bell_settings::AlarmSoundDelegate>(std::move(range), Boundaries::Fixed);
    spinner->setMaximumSize(::style::bell_base_layout::w, ::style::bell_base_layout::h);
    spinner->setFont(bell_style::font_center);
    spinner->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Center));
    spinner->setFocusEdges(RectangleEdge::None);
    body->getCenterBox()->addWidget(spinner);

    getValue = [&model, this]() { model.setValue(spinner->getCurrentValue().path.filename()); };
    setValue = [&model, soundType, this]() {
        spinner->setCurrentValue(app::bell_settings::AlarmSoundDelegate{soundType, model.getValue()});
    };
}

D products/BellHybrid/apps/application-bell-settings/widgets/SoundFileListItem.hpp => products/BellHybrid/apps/application-bell-settings/widgets/SoundFileListItem.hpp +0 -25
@@ 1,25 0,0 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <SoundFilesModel.hpp>

#include <apps-common/widgets/spinners/Spinners.hpp>
#include <common/models/AbstractSettingsModel.hpp>
#include <common/widgets/BellSideListItemWithCallbacks.hpp>

namespace gui
{
    class SoundFileListItem : public BellSideListItemWithCallbacks
    {
      public:
        SoundFileListItem(AbstractSettingsModel<std::string> &model,
                          app::bell_settings::AlarmSoundType soundType,
                          typename ModelDelegateSpinner<app::bell_settings::AlarmSoundDelegate>::Range range,
                          const std::string &topDescription = {});

      private:
        ModelDelegateSpinner<app::bell_settings::AlarmSoundDelegate> *spinner{};
    };
} // namespace gui

M products/BellHybrid/apps/common/CMakeLists.txt => products/BellHybrid/apps/common/CMakeLists.txt +5 -0
@@ 12,7 12,9 @@ target_sources(application-bell-common
    PRIVATE
        src/BellPowerOffPresenter.cpp
        src/AlarmModel.cpp
        src/AudioModel.cpp
        src/TimeModel.cpp
        src/SoundsRepository.cpp
        src/windows/BellFinishedWindow.cpp
        src/windows/BellTurnOffWindow.cpp
        src/windows/BellWelcomeWindow.cpp


@@ 30,6 32,7 @@ target_sources(application-bell-common
        src/options/BellShortOptionWindow.cpp
        src/options/OptionBellMenu.cpp
    PUBLIC
        include/common/SoundsRepository.hpp
        include/common/BellPowerOffPresenter.hpp
        include/common/windows/BellFinishedWindow.hpp
        include/common/windows/BellTurnOffWindow.hpp


@@ 37,8 40,10 @@ target_sources(application-bell-common
        include/common/TimeUtils.hpp
        include/common/models/AbstractAlarmModel.hpp
        include/common/models/AbstractSettingsModel.hpp
        include/common/models/AbstractAudioModel.hpp
        include/common/models/AlarmModel.hpp
        include/common/models/TimeModel.hpp
        include/common/models/AudioModel.hpp
        include/common/popups/presenter/AlarmActivatedPresenter.hpp
        include/common/popups/AlarmActivatedWindow.hpp
        include/common/popups/AlarmDeactivatedWindow.hpp

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

#pragma once

#include <module-audio/tags_fetcher/TagsFetcher.hpp>
#include <utf8/UTF8.hpp>

#include <filesystem>
#include <optional>
#include <vector>

class AbstractSoundsRepository
{
  public:
    virtual ~AbstractSoundsRepository()                                               = default;
    virtual std::optional<std::filesystem::path> titleToPath(const UTF8 &title) const = 0;
    virtual std::optional<UTF8> pathToTitle(std::filesystem::path) const              = 0;
    virtual std::vector<UTF8> getSongTitles()                                         = 0;
};

class SoundsRepository : public AbstractSoundsRepository
{
  public:
    explicit SoundsRepository(std::filesystem::path dirToScan);

    std::optional<std::filesystem::path> titleToPath(const UTF8 &title) const override;
    std::optional<UTF8> pathToTitle(std::filesystem::path path) const override;
    std::vector<UTF8> getSongTitles() override;

  private:
    void processEntry(const std::filesystem::recursive_directory_iterator::value_type &entry);

    std::vector<tags::fetcher::Tags> samples;
};

A products/BellHybrid/apps/common/include/common/models/AbstractAudioModel.hpp => products/BellHybrid/apps/common/include/common/models/AbstractAudioModel.hpp +41 -0
@@ 0,0 1,41 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <Audio/AudioCommon.hpp>

#include <string>
#include <functional>

namespace app
{
    using AlarmModelReadyHandler = std::function<void()>;

    class AbstractAudioModel
    {
      public:
        /// 0-10 range
        using Volume = std::uint8_t;

        using OnPlayCallback   = std::function<void(audio::RetCode retCode, audio::Token token)>;
        using OnStopCallback   = OnPlayCallback;
        using OnPauseCallback  = OnPlayCallback;
        using OnResumeCallback = OnPlayCallback;

        enum class PlaybackType
        {
            Chime,
            Alarm,
            PreWakeup
        };

        virtual ~AbstractAudioModel() noexcept                                                            = default;
        virtual void setVolume(Volume volume, PlaybackType playbackType)                                  = 0;
        virtual bool play(const std::string &filePath, const OnPlayCallback &callback, PlaybackType type) = 0;
        virtual bool pause(const audio::Token &token, const OnPauseCallback &callback)                    = 0;
        virtual bool resume(const audio::Token &token, const OnResumeCallback &callback)                  = 0;
        virtual bool stop(const audio::Token &token, const OnStopCallback &callback)                      = 0;
    };

} // namespace app

A products/BellHybrid/apps/common/include/common/models/AudioModel.hpp => products/BellHybrid/apps/common/include/common/models/AudioModel.hpp +31 -0
@@ 0,0 1,31 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "AbstractAudioModel.hpp"
#include <apps-common/AudioOperations.hpp>

namespace app
{
    class ApplicationCommon;
}

namespace app
{
    class AudioModel : public AbstractAudioModel
    {
      public:
        explicit AudioModel(ApplicationCommon *app);

        void setVolume(Volume volume, PlaybackType playbackType) override;
        bool play(const std::string &filePath, const OnPlayCallback &callback, PlaybackType type) override;
        bool pause(const audio::Token &token, const OnPauseCallback &callback) override;
        bool resume(const audio::Token &token, const OnResumeCallback &callback) override;
        bool stop(const audio::Token &token, const OnStopCallback &callback) override;

      private:
        ApplicationCommon *app{};
        AsyncAudioOperations asyncAudioOperations;
    };
} // namespace app

M products/BellHybrid/apps/common/include/common/widgets/BellSideListItemWithCallbacks.hpp => products/BellHybrid/apps/common/include/common/widgets/BellSideListItemWithCallbacks.hpp +1 -0
@@ 16,6 16,7 @@ namespace gui
        std::function<void()> getValue;
        /// Set list item's value and perform custom action.
        std::function<void()> setValue;
        std::function<void()> onEnter;
        std::function<void()> onExit;

      protected:

M products/BellHybrid/apps/common/include/common/widgets/ListItems.hpp => products/BellHybrid/apps/common/include/common/widgets/ListItems.hpp +6 -0
@@ 33,6 33,9 @@ namespace gui
                             const std::string &topDescription    = "",
                             const std::string &bottomDescription = "");

        void setOnValueChanged(std::function<void(const UIntegerSpinner::Type &)> &&cb);
        UIntegerSpinner::Type getCurrentValue();

      private:
        UIntegerSpinner *spinner{};
    };


@@ 64,6 67,9 @@ namespace gui
                              UTF8Spinner::Range range,
                              const std::string &topDescription = "");

        void setOnValueChanged(std::function<void(const UTF8 &)> &&cb);
        UTF8Spinner::Type getCurrentValue();

      private:
        UTF8Spinner *spinner{};
    };

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

#include "models/AudioModel.hpp"
#include <service-audio/AudioServiceAPI.hpp>

namespace
{
    constexpr audio::PlaybackType convertPlaybackType(app::AbstractAudioModel::PlaybackType type)
    {
        using Type = app::AbstractAudioModel::PlaybackType;
        switch (type) {
        case Type::Alarm:
            return audio::PlaybackType::Alarm;
        case Type::Chime:
            return audio::PlaybackType::Alarm;
        case Type::PreWakeup:
            return audio::PlaybackType::Alarm;
        default:
            return audio::PlaybackType::Alarm;
        }
    }
} // namespace

namespace app
{

    AudioModel::AudioModel(ApplicationCommon *app) : app{app}, asyncAudioOperations{app}
    {}
    void AudioModel::setVolume(AbstractAudioModel::Volume volume, PlaybackType playbackType)
    {
        AudioServiceAPI::SetVolume(app, volume, convertPlaybackType(playbackType));
    }
    bool AudioModel::play(const std::string &filePath,
                          const AbstractAudioOperations::OnPlayCallback &callback,
                          PlaybackType type)
    {
        return asyncAudioOperations.play(filePath, callback, convertPlaybackType(type));
    }
    bool AudioModel::pause(const audio::Token &token, const AbstractAudioOperations::OnPauseCallback &callback)
    {
        return asyncAudioOperations.pause(token, callback);
    }
    bool AudioModel::resume(const audio::Token &token, const AbstractAudioOperations::OnResumeCallback &callback)
    {
        return asyncAudioOperations.resume(token, callback);
    }
    bool AudioModel::stop(const audio::Token &token, const AbstractAudioOperations::OnStopCallback &callback)
    {
        return asyncAudioOperations.stop(token, callback);
    }
} // namespace app

M products/BellHybrid/apps/common/src/BellSideListItemWithCallbacks.cpp => products/BellHybrid/apps/common/src/BellSideListItemWithCallbacks.cpp +4 -1
@@ 26,9 26,12 @@ namespace gui
    {
        if (focus) {
            setFocusItem(body);
            if (onEnter) {
                onEnter();
            }
        }
        else {
            setFocusItem(focus ? body : nullptr);
            setFocusItem(nullptr);
            if (onExit) {
                onExit();
            }

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

#include "SoundsRepository.hpp"

#include <algorithm>

namespace fs = std::filesystem;

namespace
{
    constexpr auto allowedExtensions = {".wav", ".mp3", ".flac"};
} // namespace

SoundsRepository::SoundsRepository(std::filesystem::path dirToScan)
{
    for (auto const &entry : std::filesystem::directory_iterator(dirToScan)) {
        processEntry(entry);
    }
}
std::optional<std::filesystem::path> SoundsRepository::titleToPath(const UTF8 &title) const
{
    const auto res =
        std::find_if(samples.begin(), samples.end(), [title](const auto &e) { return e.title == title.c_str(); });
    if (res != samples.end()) {
        return std::filesystem::path{res->filePath};
    }
    return {};
}
std::optional<UTF8> SoundsRepository::pathToTitle(std::filesystem::path path) const
{
    const auto res =
        std::find_if(samples.begin(), samples.end(), [&path](const auto &e) { return e.filePath == path; });
    if (res != samples.end()) {
        return res->title;
    }
    return {};
}

std::vector<UTF8> SoundsRepository::getSongTitles()
{
    std::vector<UTF8> ret;
    std::transform(samples.begin(), samples.end(), std::back_inserter(ret), [](const auto &e) { return e.title; });
    return ret;
}

void SoundsRepository::processEntry(const std::filesystem::recursive_directory_iterator::value_type &entry)
{
    if (fs::is_regular_file(entry)) {
        for (const auto &ext : allowedExtensions) {
            if (fs::path(entry).extension() == ext) {
                samples.emplace_back(tags::fetcher::fetchTags(fs::absolute(entry).string()));
            }
        }
    }
}

M products/BellHybrid/apps/common/src/widgets/ListItems.cpp => products/BellHybrid/apps/common/src/widgets/ListItems.cpp +16 -0
@@ 55,6 55,14 @@ namespace gui
        getValue = [&model, this]() { model.setValue(spinner->getCurrentValue()); };
        setValue = [&model, this]() { spinner->setCurrentValue(model.getValue()); };
    }
    void NumListItem::setOnValueChanged(std::function<void(const UIntegerSpinner::Type &)> &&cb)
    {
        spinner->onValueChanged = cb;
    }
    UIntegerSpinner::Type NumListItem::getCurrentValue()
    {
        return spinner->getCurrentValue();
    }

    NumWithStringListItem::NumWithStringListItem(AbstractSettingsModel<std::uint8_t> &model,
                                                 NumWithStringSpinner::Range range,


@@ 126,4 134,12 @@ namespace gui
        getValue = [&model, this]() { model.setValue(spinner->getCurrentValue()); };
        setValue = [&model, this]() { spinner->setCurrentValue(model.getValue()); };
    }
    void UTF8ListItem::setOnValueChanged(std::function<void(const UTF8 &)> &&cb)
    {
        spinner->onValueChanged = cb;
    }
    UTF8Spinner::Type UTF8ListItem::getCurrentValue()
    {
        return spinner->getCurrentValue();
    }
} // namespace gui

M products/BellHybrid/services/db/include/db/SystemSettings.hpp => products/BellHybrid/services/db/include/db/SystemSettings.hpp +1 -5
@@ 9,11 9,6 @@ namespace bell::settings
    {
        constexpr inline auto unit = "temperature_unit";
    } // namespace Temperature
    namespace Ringing
    {
        constexpr inline auto duration = "ringing_duration";
        constexpr inline auto tone     = "ringing_tone";
    } // namespace Ringing
    namespace Snooze
    {
        constexpr inline auto active   = "snooze_active";


@@ 34,5 29,6 @@ namespace bell::settings
        constexpr inline auto tone        = "alarm_tone";
        constexpr inline auto volume      = "alarm_volume";
        constexpr inline auto lightActive = "alarm_light_active";
        constexpr inline auto duration    = "alarm_duration";
    } // namespace Alarm
};    // namespace bell::settings

M test/harness => test/harness +1 -1
@@ 1,1 1,1 @@
Subproject commit 8aa7fe8ad3276583688f6ae6a7370f7e686e1810
Subproject commit 109327d1a7a73afad9f741e3c17d1e161e8a9c01