~aleteoryx/muditaos

4a4b8617b85d6bb03e5d6259bdef891c10284239 — Piotr Tański 4 years ago be21cb0
[EGD-7260] Fixed meditation timer options

Fixed meditation timer options displaying.
10 files changed, 164 insertions(+), 457 deletions(-)

M module-apps/application-meditation/ApplicationMeditation.cpp
M module-apps/application-meditation/CMakeLists.txt
D module-apps/application-meditation/widgets/MeditationListItems.cpp
D module-apps/application-meditation/widgets/MeditationListItems.hpp
D module-apps/application-meditation/widgets/MeditationModel.cpp
D module-apps/application-meditation/widgets/MeditationModel.hpp
D module-apps/application-meditation/windows/MeditationListViewWindows.cpp
D module-apps/application-meditation/windows/MeditationListViewWindows.hpp
A module-apps/application-meditation/windows/MeditationOptionsWindows.cpp
A module-apps/application-meditation/windows/MeditationOptionsWindows.hpp
M module-apps/application-meditation/ApplicationMeditation.cpp => module-apps/application-meditation/ApplicationMeditation.cpp +1 -1
@@ 2,7 2,7 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "ApplicationMeditation.hpp"
#include "MeditationListViewWindows.hpp"
#include "MeditationOptionsWindows.hpp"
#include "MeditationTimerWindow.hpp"
#include "MeditationWindow.hpp"
#include "Names.hpp"

M module-apps/application-meditation/CMakeLists.txt => module-apps/application-meditation/CMakeLists.txt +2 -6
@@ 22,16 22,12 @@ target_sources(application-meditation
        data/Style.hpp
        widgets/IntervalBox.cpp
        widgets/IntervalBox.hpp
        widgets/MeditationListItems.cpp
        widgets/MeditationListItems.hpp
        widgets/MeditationModel.cpp
        widgets/MeditationModel.hpp
        widgets/MeditationTimer.cpp
        widgets/MeditationTimer.hpp
        widgets/TimerProperty.cpp
        widgets/TimerProperty.hpp
        windows/MeditationListViewWindows.cpp
        windows/MeditationListViewWindows.hpp
        windows/MeditationOptionsWindows.cpp
        windows/MeditationOptionsWindows.hpp
        windows/MeditationTimerWindow.cpp
        windows/MeditationTimerWindow.hpp
        windows/MeditationWindow.cpp

D module-apps/application-meditation/widgets/MeditationListItems.cpp => module-apps/application-meditation/widgets/MeditationListItems.cpp +0 -93
@@ 1,93 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 "MeditationListItems.hpp"
#include "Style.hpp"

#include <i18n/i18n.hpp>

using namespace gui;
namespace listStyle = style::meditation::itemList;

MeditationListItem::MeditationListItem(std::string textValue)
{
    setMargins(Margins(0, style::margins::big, 0, 0));
    setMinimumSize(listStyle::text::Width, listStyle::text::Height);
    setMaximumSize(listStyle::text::Width, listStyle::text::Height);

    setEdges(RectangleEdge::Bottom | RectangleEdge::Top);
    setPenFocusWidth(style::window::default_border_focus_w);
    setPenWidth(style::window::default_border_no_focus_w);

    text = new gui::Label(
        this, listStyle::text::X, listStyle::text::Y, listStyle::text::Width, listStyle::text::Height, textValue);

    style::window::decorate(text);
    text->setFont(style::window::font::medium);
    text->setEllipsis(Ellipsis::Right);
    text->setVisible(true);
}

PreparationTimeItem::PreparationTimeItem(std::chrono::seconds _duration)
    : MeditationListItem(convertToPrintable(_duration)), duration(_duration)
{
    MeditationListItem::text->setFont(style::window::font::big);
    imageSelectionTick = new gui::Image(this,
                                        listStyle::image::X,
                                        listStyle::image::Y,
                                        listStyle::image::Width,
                                        listStyle::image::Height,
                                        "small_tick_W_M");
    imageSelectionTick->setVisible(false);
    imageSelectionTick->setAlignment(Alignment(Alignment::Horizontal::Right));
}

void PreparationTimeItem::select(bool isSelected)
{
    imageSelectionTick->setVisible(isSelected);
}

std::string PreparationTimeItem::convertToPrintable(std::chrono::seconds _duration)
{
    if (_duration.count() > 60) {
        return std::to_string(static_cast<int>((_duration.count()) / 60)) + " m";
    }
    return std::to_string(static_cast<int>(_duration.count())) + " s";
}

OptionItemMeditationCounter::OptionItemMeditationCounter(bool isCounterOn)
    : MeditationListItem(utils::translate("app_meditation_option_show_counter"))
{
    imageOptionOn  = new gui::Image(this,
                                   listStyle::image::X,
                                   listStyle::image::OnOffY,
                                   listStyle::image::Width,
                                   listStyle::image::Height,
                                   "btn_on");
    imageOptionOff = new gui::Image(this,
                                    listStyle::image::X,
                                    listStyle::image::OnOffY,
                                    listStyle::image::Width,
                                    listStyle::image::Height,
                                    "btn_off");

    imageOptionOn->setVisible(isCounterOn);
    imageOptionOff->setVisible(!isCounterOn);
}

void OptionItemMeditationCounter::select(bool isSelected)
{
    imageOptionOn->setVisible(isSelected);
    imageOptionOff->setVisible(!isSelected);
}

OptionItemPreparation::OptionItemPreparation() : MeditationListItem(utils::translate("app_meditation_preparation_time"))
{
    image = new gui::Image(this,
                           listStyle::image::X,
                           listStyle::image::Y,
                           listStyle::image::Width,
                           listStyle::image::Height,
                           "right_label_arrow_border");
    image->setVisible(true);
}

D module-apps/application-meditation/widgets/MeditationListItems.hpp => module-apps/application-meditation/widgets/MeditationListItems.hpp +0 -59
@@ 1,59 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 <gui/widgets/Image.hpp>
#include <gui/widgets/Label.hpp>
#include <gui/widgets/ListItem.hpp>

#include <chrono>

namespace gui
{
    class MeditationListItem : public ListItem
    {
      protected:
        gui::Label *text = nullptr;

      public:
        MeditationListItem() = delete;
        MeditationListItem(std::string text);
        virtual void select(bool isSelected)
        {}
    };

    class PreparationTimeItem : public MeditationListItem
    {
        gui::Image *imageSelectionTick = nullptr;
        std::chrono::seconds duration;
        [[nodiscard]] static std::string convertToPrintable(std::chrono::seconds _duration);

      public:
        explicit PreparationTimeItem(std::chrono::seconds _duration);
        void select(bool isSelected) final;
        [[nodiscard]] std::chrono::seconds getDuration() const noexcept
        {
            return duration;
        }
    };

    class OptionItemMeditationCounter : public MeditationListItem
    {
        gui::Image *imageOptionOn  = nullptr;
        gui::Image *imageOptionOff = nullptr;

      public:
        explicit OptionItemMeditationCounter(bool isCounterOn);
        void select(bool value) final;
    };

    class OptionItemPreparation : public MeditationListItem
    {
        gui::Image *image = nullptr;

      public:
        OptionItemPreparation();
    };

} // namespace gui

D module-apps/application-meditation/widgets/MeditationModel.cpp => module-apps/application-meditation/widgets/MeditationModel.cpp +0 -117
@@ 1,117 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 "ApplicationMeditation.hpp"
#include "MeditationModel.hpp"
#include "Names.hpp"
#include "Style.hpp"

#include <gui/widgets/ListView.hpp>

using namespace gui;

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

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

auto MeditationModel::getMinimalItemSpaceRequired() const -> unsigned int
{
    return style::meditation::itemList::text::Height;
}

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

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

void MeditationModel::clearData()
{
    list->reset();
    eraseInternalData();
}

PreparationTimeModel::PreparationTimeModel(app::Application *app) : MeditationModel(app)
{}

void PreparationTimeModel::clearData()
{
    itemCurrentlySelected = nullptr;
    MeditationModel::clearData();
}

namespace
{
    using namespace std::chrono_literals;
    std::vector<std::chrono::seconds> preparationTimeRecords{5s, 10s, 30s, 1min, 2min, 5min, 10min, 15min, 30min};
} // namespace

void PreparationTimeModel::createData()
{
    auto app = static_cast<app::ApplicationMeditation *>(application);

    for (auto record : ::preparationTimeRecords) {
        auto item = new PreparationTimeItem(record);
        // check if record was already selected by value or default initialized
        if (app->state->preparationTime == item->getDuration()) {
            item->select(true);
            itemCurrentlySelected = item;
        }

        item->activatedCallback = [this, app, item](gui::Item &) {
            LOG_DEBUG("Selecting meditation time period");
            if (itemCurrentlySelected != nullptr) {
                itemCurrentlySelected->select(false);
            }
            item->select(true);
            itemCurrentlySelected = item;

            app->state->preparationTime = item->getDuration();
            application->refreshWindow(RefreshModes::GUI_REFRESH_FAST);
            return true;
        };

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

MeditationOptionsModel::MeditationOptionsModel(app::Application *app) : MeditationModel(app)
{}

void MeditationOptionsModel::createData()
{
    auto app = static_cast<app::ApplicationMeditation *>(application);

    MeditationListItem *item = new OptionItemMeditationCounter(app->state->showCounter);
    item->activatedCallback  = [this, app, item](gui::Item &) {
        LOG_DEBUG("Meditation options: selecting OptionMeditationCounter");
        app->state->showCounter = !app->state->showCounter;
        item->select(app->state->showCounter);
        application->refreshWindow(RefreshModes::GUI_REFRESH_FAST);
        return true;
    };
    internalData.push_back(item);

    item                    = new OptionItemPreparation();
    item->activatedCallback = [this](gui::Item &) {
        LOG_DEBUG("Meditation options: selecting OptionPreparation");
        application->switchWindow(app::window::name::meditation_preparation);
        application->refreshWindow(RefreshModes::GUI_REFRESH_FAST);
        return true;
    };
    internalData.push_back(item);

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

D module-apps/application-meditation/widgets/MeditationModel.hpp => module-apps/application-meditation/widgets/MeditationModel.hpp +0 -50
@@ 1,50 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 "MeditationListItems.hpp"

#include <Application.hpp>
#include <gui/widgets/ListItemProvider.hpp>
#include <InternalModel.hpp>

namespace gui
{
    class MeditationModel : public app::InternalModel<MeditationListItem *>, public gui::ListItemProvider
    {
      protected:
        app::Application *application = nullptr;
        MeditationModel(app::Application *app);

      public:
        virtual void clearData();
        virtual void createData()
        {}

        [[nodiscard]] auto requestRecordsCount() -> unsigned int final;
        [[nodiscard]] auto getMinimalItemSpaceRequired() const -> unsigned int final;
        auto getItem(gui::Order order) -> gui::ListItem * final;
        void requestRecords(const uint32_t offset, const uint32_t limit) final;
    };

    class PreparationTimeModel : public MeditationModel
    {
        MeditationListItem *itemCurrentlySelected = nullptr;

      public:
        explicit PreparationTimeModel(app::Application *app);

        void clearData() final;
        void createData() final;
    };

    class MeditationOptionsModel : public MeditationModel
    {
      public:
        explicit MeditationOptionsModel(app::Application *app);

        void createData() final;
    };

} // namespace gui

D module-apps/application-meditation/windows/MeditationListViewWindows.cpp => module-apps/application-meditation/windows/MeditationListViewWindows.cpp +0 -85
@@ 1,85 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 "MeditationListViewWindows.hpp"
#include "MeditationModel.hpp"
#include "Names.hpp"
#include "Style.hpp"

#include <gui/widgets/Label.hpp>
#include <gui/widgets/ListView.hpp>
#include <i18n/i18n.hpp>

using namespace gui;
namespace listViewWindow = style::meditation::listView::window;

MeditationListViewWindow::MeditationListViewWindow(app::Application *app, std::string windowName)
    : AppWindow(app, std::move(windowName))
{}

void MeditationListViewWindow::buildInterface()
{
    AppWindow::buildInterface();
    model->createData();
    list = new gui::ListView(this,
                             listViewWindow::X,
                             listViewWindow::Y,
                             listViewWindow::Width,
                             listViewWindow::Height,
                             model,
                             gui::listview::ScrollBarType::Fixed);
    setFocusItem(list);
    bottomBar->setText(BottomBar::Side::RIGHT, utils::translate(style::strings::common::back));
}

void MeditationListViewWindow::destroyInterface()
{
    model->clearData();
    erase();
    invalidate();
}

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

void MeditationListViewWindow::invalidate() noexcept
{
    list = nullptr;
}

void MeditationListViewWindow::onBeforeShow(ShowMode mode, SwitchData *data)
{
    list->rebuildList(gui::listview::RebuildType::InPlace);
    list->setVisible(true);
}

MeditationOptionsWindow::MeditationOptionsWindow(app::Application *app)
    : MeditationListViewWindow(app, app::window::name::meditation_options)
{
    model = std::make_shared<MeditationOptionsModel>(app);
    buildInterface();
}

void MeditationOptionsWindow::buildInterface()
{
    MeditationListViewWindow::buildInterface();
    setTitle(utils::translate("common_options"));
    bottomBar->setText(BottomBar::Side::CENTER, utils::translate(style::strings::common::Switch));
}

PreparationTimeWindow::PreparationTimeWindow(app::Application *app)
    : MeditationListViewWindow(app, app::window::name::meditation_preparation)
{
    model = std::make_shared<PreparationTimeModel>(app);
    buildInterface();
}

void PreparationTimeWindow::buildInterface()
{
    MeditationListViewWindow::buildInterface();
    setTitle(utils::translate("app_meditation_preparation_time"));
    bottomBar->setText(BottomBar::Side::CENTER, utils::translate(style::strings::common::select));
}

D module-apps/application-meditation/windows/MeditationListViewWindows.hpp => module-apps/application-meditation/windows/MeditationListViewWindows.hpp +0 -46
@@ 1,46 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 <AppWindow.hpp>

namespace gui
{
    class ListView;
    class MeditationModel;
} // namespace gui

namespace gui
{
    class MeditationListViewWindow : public AppWindow
    {
      protected:
        gui::ListView *list                    = nullptr;
        std::shared_ptr<MeditationModel> model = nullptr;

        void invalidate() noexcept;

      public:
        MeditationListViewWindow(app::Application *, std::string windowName);

        void onBeforeShow(ShowMode mode, SwitchData *data) override;
        void rebuild() override;
        void buildInterface() override;
        void destroyInterface() override;
    };

    class MeditationOptionsWindow : public MeditationListViewWindow
    {
      public:
        explicit MeditationOptionsWindow(app::Application *);
        void buildInterface() final;
    };

    class PreparationTimeWindow : public MeditationListViewWindow
    {
      public:
        explicit PreparationTimeWindow(app::Application *);
        void buildInterface() final;
    };
} // namespace gui

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

#include "ApplicationMeditation.hpp"
#include "MeditationOptionsWindows.hpp"
#include "Names.hpp"

#include <OptionSetting.hpp>
#include <i18n/i18n.hpp>

using namespace gui;

namespace
{
    using namespace std::chrono_literals;
    constexpr std::array<std::chrono::seconds, 9> preparationTimes{5s, 10s, 30s, 1min, 2min, 5min, 10min, 15min, 30min};

    std::string toString(std::chrono::seconds duration)
    {
        if (duration.count() > 60) {
            return std::to_string(static_cast<int>((duration.count()) / 60)) + " m";
        }
        return std::to_string(static_cast<int>(duration.count())) + " s";
    }
} // namespace

MeditationOptionsWindow::MeditationOptionsWindow(app::Application *app)
    : OptionWindow(app, app::window::name::meditation_options)
{
    setTitle(utils::translate("common_options"));
    bottomBar->setText(BottomBar::Side::CENTER, utils::translate(style::strings::common::Switch));
    addOptions(buildOptionsList());
}

std::list<Option> MeditationOptionsWindow::buildOptionsList()
{
    std::list<Option> options;
    addCounterOption(options);
    addPreparationTimeOption(options);
    return options;
}

void MeditationOptionsWindow::addCounterOption(std::list<Option> &options)
{
    auto app = static_cast<app::ApplicationMeditation *>(application);
    options.emplace_back(std::make_unique<option::OptionSettings>(
        utils::translate("app_meditation_option_show_counter"),
        [=](Item &item) {
            app->state->showCounter = !app->state->showCounter;
            refreshOptions(buildOptionsList());
            return true;
        },
        nullptr,
        nullptr,
        app->state->showCounter ? option::SettingRightItem::On : option::SettingRightItem::Off));
}

void MeditationOptionsWindow::addPreparationTimeOption(std::list<Option> &options)
{
    options.emplace_back(std::make_unique<option::OptionSettings>(
        utils::translate("app_meditation_preparation_time"),
        [=](Item &item) {
            application->switchWindow(app::window::name::meditation_preparation);
            return true;
        },
        nullptr,
        nullptr,
        option::SettingRightItem::ArrowBlack));
}

PreparationTimeWindow::PreparationTimeWindow(app::Application *app)
    : OptionWindow(app, app::window::name::meditation_preparation)
{
    setTitle(utils::translate("app_meditation_preparation_time"));
    bottomBar->setText(BottomBar::Side::CENTER, utils::translate(style::strings::common::select));
    bottomBar->setText(BottomBar::Side::RIGHT, utils::translate(style::strings::common::back));
    addOptions(buildOptionsList());
}

std::list<Option> PreparationTimeWindow::buildOptionsList()
{
    auto app = static_cast<app::ApplicationMeditation *>(application);
    std::list<Option> options;
    for (auto &&duration : preparationTimes) {
        addPreparationTimeOption(duration, app, options);
    }
    return options;
}

void PreparationTimeWindow::addPreparationTimeOption(std::chrono::seconds duration,
                                                     app::ApplicationMeditation *app,
                                                     std::list<Option> &options)
{
    options.emplace_back(std::make_unique<gui::option::OptionSettings>(
        toString(duration),
        [=](const gui::Item &item) {
            app->state->preparationTime = duration;
            refreshOptions(buildOptionsList());
            return true;
        },
        nullptr,
        this,
        app->state->preparationTime == duration ? gui::option::SettingRightItem::Checked
                                                : gui::option::SettingRightItem::Disabled));
}

void PreparationTimeWindow::onBeforeShow([[maybe_unused]] ShowMode mode, [[maybe_unused]] SwitchData *data)
{
    selectedItemIndex = getSelectedItemIndex();
    refreshOptions(buildOptionsList(), selectedItemIndex);
}

unsigned int PreparationTimeWindow::getSelectedItemIndex() const
{
    auto app                = static_cast<app::ApplicationMeditation *>(application);
    const auto selectedTime = app->state->preparationTime;
    for (unsigned int i = 0; i < preparationTimes.size(); ++i) {
        if (selectedTime == preparationTimes[i]) {
            return i;
        }
    }
    return 0;
}

A module-apps/application-meditation/windows/MeditationOptionsWindows.hpp => module-apps/application-meditation/windows/MeditationOptionsWindows.hpp +38 -0
@@ 0,0 1,38 @@
// 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 <OptionWindow.hpp>

namespace gui
{
    class MeditationOptionsWindow : public OptionWindow
    {
      public:
        explicit MeditationOptionsWindow(app::Application *);

      private:
        std::list<Option> buildOptionsList();
        void addCounterOption(std::list<Option> &options);
        void addPreparationTimeOption(std::list<Option> &options);
    };

    class PreparationTimeWindow : public OptionWindow
    {
      public:
        explicit PreparationTimeWindow(app::Application *app);

        void onBeforeShow(ShowMode mode, SwitchData *data) override;

      private:
        std::list<Option> buildOptionsList();
        void addPreparationTimeOption(std::chrono::seconds duration,
                                      app::ApplicationMeditation *app,
                                      std::list<Option> &options);

        [[nodiscard]] unsigned int getSelectedItemIndex() const;

        unsigned int selectedItemIndex{0};
    };
} // namespace gui