~aleteoryx/muditaos

a96ed0ecf7954ff1238a6f5426704f3d1489d0ec — Lukasz Mastalerz 2 years ago ba19e1d
[BH-1828] Add labels to relaxation sound list

Added labels to relaxation
24 files changed, 386 insertions(+), 23 deletions(-)

M harmony_changelog.md
M image/system_a/data/lang/Deutsch.json
M image/system_a/data/lang/English.json
M image/system_a/data/lang/Espanol.json
M image/system_a/data/lang/Francais.json
M image/system_a/data/lang/Polski.json
M module-gui/gui/widgets/ListViewEngine.cpp
M module-gui/gui/widgets/ListViewEngine.hpp
M module-gui/gui/widgets/ListViewWithArrows.cpp
M products/BellHybrid/apps/application-bell-relaxation/CMakeLists.txt
M products/BellHybrid/apps/application-bell-relaxation/data/RelaxationCommon.hpp
M products/BellHybrid/apps/application-bell-relaxation/model/RelaxationSongsModel.cpp
M products/BellHybrid/apps/application-bell-relaxation/model/RelaxationSongsRepository.cpp
M products/BellHybrid/apps/application-bell-relaxation/model/RelaxationSongsRepository.hpp
A products/BellHybrid/apps/application-bell-relaxation/widgets/RelaxationItem.cpp
A products/BellHybrid/apps/application-bell-relaxation/widgets/RelaxationItem.hpp
A products/BellHybrid/apps/application-bell-relaxation/widgets/RelaxationListView.cpp
A products/BellHybrid/apps/application-bell-relaxation/widgets/RelaxationListView.hpp
A products/BellHybrid/apps/application-bell-relaxation/widgets/RelaxationOption.cpp
A products/BellHybrid/apps/application-bell-relaxation/widgets/RelaxationOption.hpp
M products/BellHybrid/apps/application-bell-relaxation/windows/RelaxationMainWindow.cpp
M products/BellHybrid/apps/application-bell-relaxation/windows/RelaxationMainWindow.hpp
M products/BellHybrid/apps/common/include/common/options/OptionBellMenu.hpp
M products/BellHybrid/apps/common/src/options/OptionBellMenu.cpp
M harmony_changelog.md => harmony_changelog.md +1 -0
@@ 11,6 11,7 @@
### Added
* Added shortcuts instruction to settings
* Added brightness fade in functionality
* Added labels to Relaxation

### Changed / Improved
* Optimize the way Relaxation is loading music files

M image/system_a/data/lang/Deutsch.json => image/system_a/data/lang/Deutsch.json +2 -0
@@ 59,6 59,8 @@
    "app_bell_relaxation_once": "einmal",
    "app_bell_relaxation_once_description": "das Lied wird einmal abgespielt",
    "app_bell_relaxation_timer_title": "Timer",
    "app_bell_relaxation_sounds": "Entspannende Sounds",
    "app_bell_relaxation_uploaded_sounds": "Hochgeladene Sounds",
    "app_bell_settings_about": "Information",
    "app_bell_settings_about_info_text": "www.mudita.com",
    "app_bell_settings_about_info_title": "Handbuch & Zertifikat-Info",

M image/system_a/data/lang/English.json => image/system_a/data/lang/English.json +2 -0
@@ 92,6 92,8 @@
    "app_bell_relaxation_once": "once",
    "app_bell_relaxation_once_description": "the song will play one time",
    "app_bell_relaxation_timer_title": "Relaxation time",
    "app_bell_relaxation_sounds": "Relaxation sounds",
    "app_bell_relaxation_uploaded_sounds": "Uploaded sounds",
    "app_bell_reset_message": "<text>Resetting Mudita<br />Harmony</text>",
    "app_bell_settings_about": "About",
    "app_bell_settings_about_info_text": "www.mudita.com",

M image/system_a/data/lang/Espanol.json => image/system_a/data/lang/Espanol.json +2 -0
@@ 58,6 58,8 @@
    "app_bell_relaxation_once": "una vez",
    "app_bell_relaxation_once_description": "la canci\u00f3n se reproducir\u00e1 una vez",
    "app_bell_relaxation_timer_title": "Temporizador",
    "app_bell_relaxation_sounds": "Sonidos de relajaci\u00f3n",
    "app_bell_relaxation_uploaded_sounds": "Sonidos subidos",
    "app_bell_settings_about": "Informaci\u00f3n",
    "app_bell_settings_about_info_text": "www.mudita.com",
    "app_bell_settings_about_info_title": "Manual y certificaci\u00f3n",

M image/system_a/data/lang/Francais.json => image/system_a/data/lang/Francais.json +2 -0
@@ 60,6 60,8 @@
    "app_bell_relaxation_once": "une fois",
    "app_bell_relaxation_once_description": "le morceau sera lu une fois",
    "app_bell_relaxation_timer_title": "Minuterie",
    "app_bell_relaxation_sounds": "Sons de relaxation",
    "app_bell_relaxation_uploaded_sounds": "Sons t\u00e9l\u00e9charg\u00e9s",
    "app_bell_settings_about": "\u00c0 propos",
    "app_bell_settings_about_info_text": "www.mudita.com",
    "app_bell_settings_about_info_title": "Manuel et certification",

M image/system_a/data/lang/Polski.json => image/system_a/data/lang/Polski.json +2 -0
@@ 59,6 59,8 @@
    "app_bell_relaxation_once": "raz",
    "app_bell_relaxation_once_description": "utw\u00f3r zostanie odtworzony jeden raz",
    "app_bell_relaxation_timer_title": "Wy\u0142\u0105cznik czasowy",
    "app_bell_relaxation_sounds": "D\u017Awi\u0119ki relaksacji",
    "app_bell_relaxation_uploaded_sounds": "Przes\u0142ane d\u017awi\u0119ki",
    "app_bell_settings_about": "O produkcie",
    "app_bell_settings_about_info_text": "www.mudita.com",
    "app_bell_settings_about_info_title": "Instrukcja i informacje dot. certyfikacji",

M module-gui/gui/widgets/ListViewEngine.cpp => module-gui/gui/widgets/ListViewEngine.cpp +1 -1
@@ 545,7 545,7 @@ namespace gui

    void ListViewEngine::updateCountOfElementsAboveCurrentPage()
    {
        unsigned countOfElementsAboveCurrentPage = startIndex;
        const auto countOfElementsAboveCurrentPage = startIndex;
        if (onElementsAboveOfCurrentPageChangeCallback) {
            onElementsAboveOfCurrentPageChangeCallback(countOfElementsAboveCurrentPage);
        }

M module-gui/gui/widgets/ListViewEngine.hpp => module-gui/gui/widgets/ListViewEngine.hpp +1 -1
@@ 187,7 187,7 @@ namespace gui
        /// Callback to be called on rebuild preparation - in example to on demand clear provider data.
        std::function<void()> prepareRebuildCallback;

        void reset();
        virtual void reset();
        virtual void clear();
        void onClose();


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

#include "ListViewWithArrows.hpp"


@@ 13,7 13,7 @@ namespace gui
                                           unsigned int w,
                                           unsigned int h,
                                           std::shared_ptr<ListItemProvider> prov)
        : Rect{parent, x, y, w, h}, ListViewEngine(prov)
        : Rect{parent, x, y, w, h}, ListViewEngine(std::move(prov))
    {
        this->setEdges(RectangleEdge::None);
        createLayout();

M products/BellHybrid/apps/application-bell-relaxation/CMakeLists.txt => products/BellHybrid/apps/application-bell-relaxation/CMakeLists.txt +6 -0
@@ 23,6 23,9 @@ target_sources(application-bell-relaxation
        presenter/RelaxationLowBatteryPresenter.cpp
        presenter/RelaxationErrorPresenter.cpp
        widgets/RelaxationPlayer.cpp
        widgets/RelaxationListView.cpp
        widgets/RelaxationOption.cpp
        widgets/RelaxationItem.cpp
        windows/RelaxationMainWindow.cpp
        windows/RelaxationPausedWindow.cpp
        windows/RelaxationRunningProgressWindow.cpp


@@ 39,7 42,10 @@ target_sources(application-bell-relaxation
        data/RelaxationSwitchData.hpp
        data/RelaxationErrorData.hpp
        widgets/RelaxationPlayer.hpp
        widgets/RelaxationListView.hpp
        widgets/RelaxationOption.hpp
        windows/RelaxationMainWindow.hpp
        widgets/RelaxationItem.cpp
        presenter/RelaxationMainWindowPresenter.hpp
        presenter/RelaxationRunningProgressPresenter.hpp
        presenter/RelaxationRunningLoopPresenter.hpp

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

#pragma once


@@ 6,4 6,11 @@
namespace app::relaxation
{
    constexpr auto timerValueDBRecordName = "RelaxationTimerValue";
}

    enum class MusicType
    {
        Relaxation,
        User,
        Undefined
    };
} // namespace app::relaxation

M products/BellHybrid/apps/application-bell-relaxation/model/RelaxationSongsModel.cpp => products/BellHybrid/apps/application-bell-relaxation/model/RelaxationSongsModel.cpp +16 -1
@@ 3,7 3,21 @@

#include "RelaxationSongsModel.hpp"
#include "common/options/OptionBellMenu.hpp"
#include "widgets/RelaxationOption.hpp"

namespace
{
    app::relaxation::MusicType getTypeFromPath(const std::string &path,
                                               const std::map<app::relaxation::MusicType, std::string> &pathPrefixes)
    {
        for (const auto &[type, pathPrefix] : pathPrefixes) {
            if (path.find(pathPrefix) != std::string::npos) {
                return type;
            }
        }
        return app::relaxation::MusicType::Relaxation;
    }
} // namespace
namespace app::relaxation
{



@@ 42,7 56,8 @@ namespace app::relaxation
            return nullptr;
        }

        auto item = new gui::option::OptionBellMenu(
        auto item = new gui::option::RelaxationOption(
            getTypeFromPath(sound->fileInfo.path, songsRepository->getPathPrefixes()),
            sound->tags.title,
            [=]([[maybe_unused]] gui::Item &item) {
                activateCallback(*sound);

M products/BellHybrid/apps/application-bell-relaxation/model/RelaxationSongsRepository.cpp => products/BellHybrid/apps/application-bell-relaxation/model/RelaxationSongsRepository.cpp +5 -2
@@ 70,7 70,7 @@ namespace app::relaxation
        std::uint32_t limit,
        const RelaxationSongsRepository::OnGetMusicFilesListCallback &viewUpdateCallback)
    {
        auto taskCallback = [this, viewUpdateCallback, offset, musicType](auto response) {
        auto taskCallback = [this, viewUpdateCallback, offset](auto response) {
            auto result = dynamic_cast<db::multimedia_files::query::GetLimitedResult *>(response);
            if (result == nullptr) {
                return false;


@@ 113,7 113,6 @@ namespace app::relaxation
        musicFilesViewCache.records.clear();
        std::uint32_t totalFilesCount{0};
        const auto lastFileIndex = offset + limit;

        if (filesPerType.empty()) {
            getMusicFiles(MusicType::Relaxation, offset, limit, callback);
        }


@@ 135,5 134,9 @@ namespace app::relaxation
            }
        }
    }
    std::map<MusicType, std::string> &RelaxationSongsRepository::getPathPrefixes()
    {
        return pathPrefixes;
    }

} // namespace app::relaxation

M products/BellHybrid/apps/application-bell-relaxation/model/RelaxationSongsRepository.hpp => products/BellHybrid/apps/application-bell-relaxation/model/RelaxationSongsRepository.hpp +2 -5
@@ 3,15 3,11 @@

#pragma once

#include "data/RelaxationCommon.hpp"
#include <apps-common/models/SongsRepository.hpp>
#include <memory>
namespace app::relaxation
{
    enum class MusicType
    {
        Relaxation,
        User
    };

    class RelaxationSongsRepository : public app::AsyncCallbackReceiver
    {


@@ 28,6 24,7 @@ namespace app::relaxation

        std::uint32_t getRecordsCount();
        void updateFilesCount();
        std::map<MusicType, std::string> &getPathPrefixes();

      private:
        ApplicationCommon *application;

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

#include "RelaxationItem.hpp"
#include "common/options/OptionBellMenu.hpp"

namespace
{
    constexpr auto linesMaxNumber = 1U;
}

namespace gui
{
    RelaxationItem::RelaxationItem(app::relaxation::MusicType musicType) : musicType(musicType)
    {}

    app::relaxation::MusicType RelaxationItem::getMusicType()
    {
        return musicType;
    }

    RelaxationMarkerItem::RelaxationMarkerItem(const UTF8 &labelText)
    {
        setMinimumSize(style::bell_options::default_text_width, style::bell_options::h);
        setMargins(gui::Margins(0, style::bell_options::option_margin, 0, style::bell_options::option_margin));
        setAlignment(gui::Alignment::Horizontal::Center);
        activatedCallback    = nullptr;
        focusChangedCallback = nullptr;

        auto labelBodyHBox = new gui::HBox(this, 0, 0, 0, 0);
        labelBodyHBox->setAlignment(
            gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center));
        style::window::decorate(labelBodyHBox);

        auto text = new gui::TextFixedSize(labelBodyHBox, 0, 0, 0, 0);
        text->setLines(linesMaxNumber);
        text->setTextType(gui::TextType::SingleLine);
        text->drawUnderline(false);
        text->setAlignment(gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center));
        text->setMaximumSize(style::bell_options::default_text_width, style::bell_options::h);
        text->setFont(style::window::font::verybigbold);

        text->setRichText(labelText);
        dimensionChangedCallback = [labelBodyHBox](gui::Item &, const gui::BoundingBox &newDim) -> bool {
            labelBodyHBox->setArea({0, 0, newDim.w, newDim.h});
            return true;
        };
        activeItem = false;
    }

} // namespace gui

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

#pragma once

#include "data/RelaxationCommon.hpp"
#include "ListItem.hpp"
#include "widgets/TextWithIconsWidget.hpp"
namespace gui
{
    class RelaxationItem : public ListItem
    {
      private:
        app::relaxation::MusicType musicType{};

      public:
        explicit RelaxationItem(app::relaxation::MusicType musicType);
        app::relaxation::MusicType getMusicType();
    };

    class RelaxationMarkerItem : public ListItem
    {
      public:
        explicit RelaxationMarkerItem(const UTF8 &labelText);
    };
} // namespace gui

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

#include "RelaxationListView.hpp"
#include "widgets/RelaxationOption.hpp"
#include "RelaxationItem.hpp"
#include <TextFixedSize.hpp>

namespace
{

    constexpr auto maxItemDisplayed{4U};

    const std::map<app::relaxation::MusicType, std::string> typeToLabel{
        {app::relaxation::MusicType::Relaxation, "app_bell_relaxation_sounds"},
        {app::relaxation::MusicType::User, "app_bell_relaxation_uploaded_sounds"}};

    gui::RelaxationMarkerItem *createMarkerItem(app::relaxation::MusicType musicType)
    {
        const auto label = UTF8(utils::translate(typeToLabel.at(musicType)));
        return new gui::RelaxationMarkerItem(label);
    }

} // namespace

namespace gui
{
    RelaxationListView::RelaxationListView(Item *parent,
                                           unsigned int x,
                                           unsigned int y,
                                           unsigned int w,
                                           unsigned int h,
                                           std::shared_ptr<ListItemProvider> prov)
        : ListViewWithArrows(parent, x, y, w, h, std::move(prov))
    {
        body->dimensionChangedCallback = [&](gui::Item &, const BoundingBox &newDim) -> bool { return true; };
    }

    void RelaxationListView::addItemsOnPage()
    {
        currentPageSize = 0;
        itemsOnPage     = 0;
        labelAdded      = false;
        getSlotsLeft();

        ListItem *item = nullptr;
        while ((item = provider->getItem(getOrderFromDirection())) != nullptr) {
            /* If direction is top-to-bottom, add label mark before adding relaxation item. */
            if (direction == listview::Direction::Bottom) {
                addLabelMarker(item);
            }
            /* Check if new item fits, if it does - add it, if not - handle label insertion
             * case for bottom-to-top navigation direction. */
            if (getSlotsLeft() > 0) {
                body->addWidget(item);
                itemsOnPage++;
            }
            else {
                break;
            }
            /* If direction is bottom-to-top, add label mark after adding relaxation item. */
            if (direction == listview::Direction::Top) {
                addLabelMarker(item);
            }
            currentPageSize++;
        }

        recalculateStartIndex();

        if (!labelAdded) {
            currentMarker = MusicType::Undefined;
        }
    }

    void RelaxationListView::addLabelMarker(ListItem *item)
    {
        const auto relaxationItem = dynamic_cast<gui::RelaxationItem *>(item);
        if (relaxationItem == nullptr) {
            return;
        };
        previousType = currentType;
        currentType  = relaxationItem->getMusicType();

        switch (direction) {
        case listview::Direction::Bottom:
            if (currentType != previousType && currentType != currentMarker) {
                body->addWidget(createMarkerItem(currentType));
                updateState(currentType);
            }
            break;

        case listview::Direction::Top:
            if (currentType != previousType && previousType != currentMarker) {
                const auto initialSlotsLeft = getSlotsLeft();

                body->removeWidget(relaxationItem);
                body->addWidget(createMarkerItem(previousType));
                updateState(previousType);

                /* Add item to body even if it won't fit to avoid manual memory
                 * management for item, but apply correction to currentPageSize
                 * if it is not visible. */
                body->addWidget(relaxationItem);

                if (initialSlotsLeft == 0) {
                    currentPageSize--;
                    itemsOnPage--;
                }
            }
            else {
                const auto nextItemExist = provider->getItem(getOrderFromDirection()) != nullptr;
                if (!nextItemExist && getSlotsLeft() == 1) {
                    body->addWidget(createMarkerItem(currentType));
                    updateState(currentType);
                }
                // Setting back iterator to proper position
                provider->getItem(getOppositeOrderFromDirection());
            }
            break;
        }
    }

    std::size_t RelaxationListView::getSlotsLeft()
    {
        if (itemsOnPage > maxItemDisplayed) {
            return 0;
        }
        return maxItemDisplayed - itemsOnPage;
    }

    void RelaxationListView::reset()
    {
        currentMarker = MusicType::Undefined;
        previousType  = MusicType::Undefined;
        currentType   = MusicType::Undefined;
        ListViewEngine::reset();
    }

    void RelaxationListView::updateState(RelaxationListView::MusicType newMarker)
    {
        currentMarker = newMarker;
        itemsOnPage++;
        labelAdded = true;
    }

} // namespace gui

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

#pragma once

#include <apps-common/ApplicationCommon.hpp>
#include <ListViewWithArrows.hpp>
#include "data/RelaxationCommon.hpp"

namespace gui
{
    class ListItemProvider;

    class RelaxationListView : public ListViewWithArrows
    {
        using MusicType = app::relaxation::MusicType;

      public:
        RelaxationListView(Item *parent,
                           unsigned int x,
                           unsigned int y,
                           unsigned int w,
                           unsigned int h,
                           std::shared_ptr<ListItemProvider> prov);

        void reset() override;

      private:
        void addItemsOnPage() override;
        void addLabelMarker(ListItem *item);
        std::size_t getSlotsLeft();
        void updateState(MusicType newMarker);

        MusicType currentType{MusicType::Undefined};
        MusicType previousType{MusicType::Undefined};
        MusicType currentMarker{MusicType::Undefined};
        std::uint32_t itemsOnPage{0};
        bool labelAdded{false};
    };

} // namespace gui

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

#include "RelaxationOption.hpp"

#include <utility>
namespace gui::option
{

    RelaxationOption::RelaxationOption(app::relaxation::MusicType musicType,
                                       const UTF8 &text,
                                       std::function<bool(Item &)> activatedCallback,
                                       std::function<bool(Item &)> focusChangedCallback,
                                       gui::AppWindow *app)
        : OptionBellMenu(text, std::move(activatedCallback), std::move(focusChangedCallback), app), musicType(musicType)
    {}

    auto RelaxationOption::build() const -> ListItem *
    {
        auto relaxationItem = new RelaxationItem(musicType);
        OptionBellMenu::prepareListItem(relaxationItem);
        return relaxationItem;
    }

} // namespace gui::option

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

#pragma once

#include "data/RelaxationCommon.hpp"
#include "RelaxationItem.hpp"
#include <common/options/OptionBellMenu.hpp>
namespace gui::option
{
    class RelaxationOption : public OptionBellMenu
    {
      private:
        app::relaxation::MusicType musicType{app::relaxation::MusicType::Undefined};

      public:
        RelaxationOption(app::relaxation::MusicType musicType,
                         const UTF8 &text,
                         std::function<bool(Item &)> activatedCallback,
                         std::function<bool(Item &)> focusChangedCallback,
                         AppWindow *app);

        [[nodiscard]] auto build() const -> ListItem * override;
    };
} // namespace gui::option

M products/BellHybrid/apps/application-bell-relaxation/windows/RelaxationMainWindow.cpp => products/BellHybrid/apps/application-bell-relaxation/windows/RelaxationMainWindow.cpp +2 -1
@@ 30,7 30,7 @@ namespace gui
        header->setTitleVisibility(false);
        navBar->setVisible(false);

        songList = new gui::ListViewWithArrows(
        songList = new gui::RelaxationListView(
            this, 0, 0, style::window_width, style::window_height, presenter->getSongsModel());
        songList->applySizeRestrictions(style::bell_options_list::w,
                                        style::bell_options_list::h,


@@ 71,6 71,7 @@ namespace gui
    void RelaxationMainWindow::rebuild()
    {
        presenter->updateRecordsCount();
        songList->reset();
        songList->rebuildList(gui::listview::RebuildType::Full);
    }


M products/BellHybrid/apps/application-bell-relaxation/windows/RelaxationMainWindow.hpp => products/BellHybrid/apps/application-bell-relaxation/windows/RelaxationMainWindow.hpp +2 -1
@@ 4,6 4,7 @@
#pragma once

#include "presenter/RelaxationMainWindowPresenter.hpp"
#include "widgets/RelaxationListView.hpp"

#include <common/options/BellOptionWindow.hpp>



@@ 18,7 19,7 @@ namespace gui
      private:
        std::unique_ptr<app::relaxation::RelaxationMainWindowContract::Presenter> presenter;

        gui::ListViewWithArrows *songList = nullptr;
        gui::RelaxationListView *songList = nullptr;

        void buildInterface() override;
        void handleError() override;

M products/BellHybrid/apps/common/include/common/options/OptionBellMenu.hpp => products/BellHybrid/apps/common/include/common/options/OptionBellMenu.hpp +4 -1
@@ 16,12 16,15 @@ namespace gui::option
{
    class OptionBellMenu : public option::Base
    {
      private:

      protected:
        UTF8 text;
        std::function<bool(Item &)> activatedCallback    = nullptr;
        std::function<bool(Item &)> focusChangedCallback = nullptr;
        AppWindow *app                                   = nullptr;

        void prepareListItem(ListItem *item) const;

      public:
        OptionBellMenu(const UTF8 &text,
                       std::function<bool(Item &)> activatedCallback,

M products/BellHybrid/apps/common/src/options/OptionBellMenu.cpp => products/BellHybrid/apps/common/src/options/OptionBellMenu.cpp +11 -6
@@ 10,13 10,14 @@ namespace
    constexpr auto ellipsisSpace  = 2u;
    constexpr auto linesMaxNumber = 1u;

    UTF8 adjustTextLength(const UTF8 &text, const std::uint32_t maxCharsInLine)
    UTF8 adjustTextLength(const UTF8 &textToDisplay, std::uint32_t maxCharsInLine)
    {
        if (maxCharsInLine < text.length()) {
            return text.substr(0, maxCharsInLine - ellipsisSpace) + ellipsis;
        if (maxCharsInLine < textToDisplay.length()) {
            return textToDisplay.substr(0, maxCharsInLine - ellipsisSpace) + ellipsis;
        }
        return text;
        return textToDisplay;
    }

} // namespace

namespace gui::option


@@ 24,6 25,12 @@ namespace gui::option
    auto OptionBellMenu::build() const -> ListItem *
    {
        auto optionItem = new gui::ListItem();
        prepareListItem(optionItem);
        return optionItem;
    }

    void OptionBellMenu::prepareListItem(ListItem *optionItem) const
    {
        optionItem->setMinimumSize(style::bell_options::default_text_width, style::bell_options::h);
        optionItem->setMargins(Margins(0, style::bell_options::option_margin, 0, style::bell_options::option_margin));
        optionItem->setAlignment(gui::Alignment::Horizontal::Center);


@@ 48,7 55,5 @@ namespace gui::option
            optionBodyHBox->setArea({0, 0, newDim.w, newDim.h});
            return true;
        };

        return optionItem;
    }
} // namespace gui::option