~aleteoryx/muditaos

8372183e89fc87d393aa53f645516c1909fd829d — Michał Kamoń 5 years ago 9c36407
[EGD-4574] Meditation: fix intervals chime choice to scale with meditation time (#1113)

M changelog.md => changelog.md +1 -0
@@ 17,6 17,7 @@

### Fixed

* `[meditation]` Fix interval chimes choice not scaling with meditation time
* `[meditation]` Fix of too many time options
* `[meditation]` Fixed default counter settings
* `[notes]` Fixed displaying the special characters in a note title.

M module-apps/application-meditation/CMakeLists.txt => module-apps/application-meditation/CMakeLists.txt +2 -2
@@ 11,7 11,7 @@ target_sources(${PROJECT_NAME}
        widgets/MeditationModel.cpp
        widgets/MeditationListItems.cpp
        widgets/IntervalBox.cpp
        widgets/TimerSetter.cpp
        widgets/TimerProperty.cpp
    PUBLIC
        ApplicationMeditation.hpp
        data/Style.hpp


@@ 25,7 25,7 @@ target_sources(${PROJECT_NAME}
        widgets/MeditationModel.hpp
        widgets/MeditationListItems.hpp
        widgets/IntervalBox.hpp
        widgets/TimerSetter.hpp
        widgets/TimerProperty.hpp
)

target_link_libraries(${PROJECT_NAME}

M module-apps/application-meditation/widgets/IntervalBox.cpp => module-apps/application-meditation/widgets/IntervalBox.cpp +42 -23
@@ 4,6 4,8 @@
#include "IntervalBox.hpp"

#include "application-meditation/data/Style.hpp"
#include "Style.hpp"
#include "TimerProperty.hpp"
#include "InputEvent.hpp"

#include <module-utils/i18n/i18n.hpp>


@@ 18,9 20,10 @@ namespace
        minutes{0}, minutes{2}, minutes{5}, minutes{10}, minutes{15}, minutes{30}};
} // namespace

IntervalBox::IntervalBox(Item *parent, const uint32_t x, const uint32_t y, const uint32_t w, const uint32_t h)
    : BoxLayout(parent, x, y, w, h)
IntervalBox::IntervalBox(Item *parent, uint32_t x, uint32_t y, uint32_t w, uint32_t h, TimerProperty *timerSetter)
    : BoxLayout(parent, x, y, w, h), timerSetter(timerSetter)
{
    assert(timerSetter);
    build();
}



@@ 28,12 31,12 @@ void IntervalBox::build()
{
    namespace boxStyle = style::meditation::intervalBox;

    Label *topLabel = new Label(this,
                                boxStyle::topLabel::X,
                                boxStyle::topLabel::Y,
                                boxStyle::topLabel::Width,
                                boxStyle::topLabel::Height,
                                utils::localize.get("app_meditation_interval_chime"));
    auto topLabel = new Label(this,
                              boxStyle::topLabel::X,
                              boxStyle::topLabel::Y,
                              boxStyle::topLabel::Width,
                              boxStyle::topLabel::Height,
                              utils::localize.get("app_meditation_interval_chime"));
    topLabel->setAlignment(Alignment(Alignment::Horizontal::Left, Alignment::Vertical::Bottom));
    topLabel->setFont(style::window::font::verysmall);
    topLabel->setEdges(RectangleEdge::None);


@@ 46,6 49,7 @@ void IntervalBox::build()
    bottomLabel->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Center));
    bottomLabel->setFont(style::window::font::small);
    bottomLabel->setEdges(RectangleEdge::Bottom);
    bottomLabel->setPenWidth(style::window::default_border_rect_no_focus);

    leftSwitchArrow  = new gui::Image(bottomLabel,
                                     boxStyle::arrow::LeftX,


@@ 60,22 64,28 @@ void IntervalBox::build()
                                      boxStyle::arrow::Height,
                                      "right_label_arrow");

    leftSwitchArrow->setVisible(false);
    rightSwitchArrow->setVisible(false);

    updateIntervals(ChimeIntervalList::Direction::Next);
    leftSwitchArrow->setVisible(false);
    rightSwitchArrow->setVisible(false);
}

bool IntervalBox::onFocus(bool state)
{
    if (state) {
        rescaleIntervals();
        bottomLabel->setPenWidth(style::window::default_border_focus_w);
        bottomLabel->setFont(style::window::font::smallbold);
    }
    else {
        bottomLabel->setPenWidth(style::window::default_border_rect_no_focus);
        bottomLabel->setFont(style::window::font::small);
    }
    leftSwitchArrow->setVisible(state && showLeftArrowOnFocus);
    rightSwitchArrow->setVisible(state && showRightArrowOnFocus);
    auto currentMeditationTime = timerSetter->getTime();
    leftSwitchArrow->setVisible(state &&
                                chimeIntervals.hasNext(ChimeIntervalList::Direction::Previous, currentMeditationTime));
    rightSwitchArrow->setVisible(state &&
                                 chimeIntervals.hasNext(ChimeIntervalList::Direction::Next, currentMeditationTime));
    return true;
}



@@ 96,25 106,30 @@ bool IntervalBox::onInput(const InputEvent &inputEvent)

void IntervalBox::updateIntervals(ChimeIntervalList::Direction direction)
{
    if (!chimeIntervals.moveToNext(direction)) {
    auto currentMeditationTime = timerSetter->getTime();
    if (!chimeIntervals.moveToNext(direction, currentMeditationTime)) {
        return;
    }
    intervalValue = chimeIntervals.getCurrent();
    bottomLabel->setText(ChimeIntervalList::toPrintableInterval(intervalValue));

    showLeftArrowOnFocus  = chimeIntervals.hasNext(ChimeIntervalList::Direction::Previous);
    showRightArrowOnFocus = chimeIntervals.hasNext(ChimeIntervalList::Direction::Next);
    leftSwitchArrow->setVisible(chimeIntervals.hasNext(ChimeIntervalList::Direction::Previous, currentMeditationTime));
    rightSwitchArrow->setVisible(chimeIntervals.hasNext(ChimeIntervalList::Direction::Next, currentMeditationTime));
}

    leftSwitchArrow->setVisible(showLeftArrowOnFocus);
    rightSwitchArrow->setVisible(showRightArrowOnFocus);
void IntervalBox::rescaleIntervals()
{
    while (intervalValue >= timerSetter->getTime() && intervalValue != minutes{0}) {
        updateIntervals(ChimeIntervalList::Direction::Previous);
    }
}

IntervalBox::ChimeIntervalList::ChimeIntervalList() : intervals(::chimeIntervals), current(intervals.begin())
{}

bool IntervalBox::ChimeIntervalList::moveToNext(Direction direction) noexcept
bool IntervalBox::ChimeIntervalList::moveToNext(Direction direction, std::chrono::minutes meditationTime) noexcept
{
    if (!hasNext(direction)) {
    if (!hasNext(direction, meditationTime)) {
        return false;
    }
    if (direction == Direction::Next) {


@@ 126,12 141,16 @@ bool IntervalBox::ChimeIntervalList::moveToNext(Direction direction) noexcept
    return true;
}

bool IntervalBox::ChimeIntervalList::hasNext(Direction direction) const noexcept
bool IntervalBox::ChimeIntervalList::hasNext(Direction direction, std::chrono::minutes meditationTime) const noexcept
{
    if (direction == Direction::Next) {
        return std::next(current) != intervals.end();
    if (direction == Direction::Previous) {
        return current != intervals.begin();
    }
    auto result = std::next(current) != intervals.end();
    if (result) {
        result = *std::next(current) < meditationTime;
    }
    return current != intervals.begin();
    return result;
}

std::string IntervalBox::ChimeIntervalList::toPrintableInterval(std::chrono::minutes value)

M module-apps/application-meditation/widgets/IntervalBox.hpp => module-apps/application-meditation/widgets/IntervalBox.hpp +9 -7
@@ 12,6 12,8 @@

namespace gui
{
    class TimerProperty;

    class IntervalBox : public BoxLayout
    {
        class ChimeIntervalList


@@ 28,34 30,34 @@ namespace gui

            ChimeIntervalList();

            std::chrono::minutes getCurrent() const noexcept
            [[nodiscard]] std::chrono::minutes getCurrent() const noexcept
            {
                return *current;
            }

            bool moveToNext(Direction dir) noexcept;
            [[nodiscard]] bool hasNext(Direction dir) const noexcept;
            bool moveToNext(Direction dir, std::chrono::minutes meditationTime) noexcept;
            [[nodiscard]] bool hasNext(Direction dir, std::chrono::minutes meditationTime) const noexcept;

            [[nodiscard]] static std::string toPrintableInterval(std::chrono::minutes time);
        } chimeIntervals;

        TimerProperty *timerSetter = nullptr;
        Label *bottomLabel      = nullptr;
        Image *leftSwitchArrow  = nullptr;
        Image *rightSwitchArrow = nullptr;

        bool showLeftArrowOnFocus  = true;
        bool showRightArrowOnFocus = true;
        std::chrono::minutes intervalValue{0};

        void build();
        void updateIntervals(ChimeIntervalList::Direction dir);
        void rescaleIntervals();

      public:
        IntervalBox(Item *parent, const uint32_t x, const uint32_t y, const uint32_t w, const uint32_t h);
        IntervalBox(Item *parent, uint32_t x, uint32_t y, uint32_t w, uint32_t h, TimerProperty *timerSetter);

        bool onFocus(bool isFocused) final;
        bool onInput(const InputEvent &inputEvent) final;
        std::chrono::seconds getIntervalValue() const noexcept
        [[nodiscard]] std::chrono::seconds getIntervalValue() const noexcept
        {
            return std::chrono::seconds{intervalValue};
        }

R module-apps/application-meditation/widgets/TimerSetter.cpp => module-apps/application-meditation/widgets/TimerProperty.cpp +11 -11
@@ 1,20 1,20 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "TimerSetter.hpp"
#include "TimerProperty.hpp"
#include <application-meditation/data/Style.hpp>
#include <module-utils/i18n/i18n.hpp>
#include <module-utils/Utils.hpp>

using namespace gui;

TimerSetter::TimerSetter(Item *parent, const uint32_t x, const uint32_t y, const uint32_t w, const uint32_t h)
TimerProperty::TimerProperty(Item *parent, const uint32_t x, const uint32_t y, const uint32_t w, const uint32_t h)
    : Rect(parent, x, y, w, h)
{
    build();
}

void TimerSetter::build()
void TimerProperty::build()
{
    const Point boxCenter(getX() + (getWidth() / 2), getY() + (getHeight() / 2));



@@ 51,7 51,7 @@ void TimerSetter::build()
    timeUnitLabel->setText(utils::localize.get("app_meditation_minutes"));
}

bool TimerSetter::onFocus(bool isFocused)
bool TimerProperty::onFocus(bool isFocused)
{
    circle->setFocus(isFocused);
    if (isFocused) {


@@ 64,7 64,7 @@ bool TimerSetter::onFocus(bool isFocused)
    return true;
}

bool TimerSetter::onInput(const InputEvent &inputEvent)
bool TimerProperty::onInput(const InputEvent &inputEvent)
{
    bool handled = false;
    if (inputEvent.isShortPress()) {


@@ 88,7 88,7 @@ bool TimerSetter::onInput(const InputEvent &inputEvent)
    return handled;
}

void TimerSetter::setMeditationTime()
void TimerProperty::setMeditationTime()
{
    const auto meditationTime = static_cast<int>(state.getTime().count());
    timeLabel->setText(utils::to_string(meditationTime));


@@ 100,19 100,19 @@ void TimerSetter::setMeditationTime()
    }
}

std::chrono::seconds TimerSetter::getTime() noexcept
std::chrono::minutes TimerProperty::getTime() noexcept
{
    state.checkBounds();
    return state.getTime();
}

void TimerSetter::State::checkBounds() noexcept
void TimerProperty::State::checkBounds() noexcept
{
    timeInMinutes       = std::clamp(timeInMinutes, minimalValue, maximalValue);
    resetValueOnNumeric = true;
}

void TimerSetter::State::putNumericValue(int digit) noexcept
void TimerProperty::State::putNumericValue(int digit) noexcept
{
    if (resetValueOnNumeric) {
        timeInMinutes       = 0;


@@ 124,7 124,7 @@ void TimerSetter::State::putNumericValue(int digit) noexcept
    }
}

void TimerSetter::State::increment() noexcept
void TimerProperty::State::increment() noexcept
{
    auto it = std::upper_bound(std::begin(timeArr), std::end(timeArr), timeInMinutes);
    if (it == std::end(timeArr)) {


@@ 134,7 134,7 @@ void TimerSetter::State::increment() noexcept
    resetValueOnNumeric = true;
}

void TimerSetter::State::decrement() noexcept
void TimerProperty::State::decrement() noexcept
{
    auto it =
        std::upper_bound(std::rbegin(timeArr), std::rend(timeArr), timeInMinutes, [](int a, int b) { return a > b; });

R module-apps/application-meditation/widgets/TimerSetter.hpp => module-apps/application-meditation/widgets/TimerProperty.hpp +3 -3
@@ 12,7 12,7 @@

namespace gui
{
    class TimerSetter : public Rect
    class TimerProperty : public Rect
    {
        class State
        {


@@ 49,11 49,11 @@ namespace gui
        void setMeditationTime();

      public:
        TimerSetter(Item *parent, const uint32_t x, const uint32_t y, const uint32_t w, const uint32_t h);
        TimerProperty(Item *parent, const uint32_t x, const uint32_t y, const uint32_t w, const uint32_t h);

        bool onFocus(bool isFocused) final;
        bool onInput(const InputEvent &inputEvent) final;
        [[nodiscard]] std::chrono::seconds getTime() noexcept;
        [[nodiscard]] std::chrono::minutes getTime() noexcept;
    };

} // namespace gui

M module-apps/application-meditation/windows/MeditationWindow.cpp => module-apps/application-meditation/windows/MeditationWindow.cpp +8 -7
@@ 5,7 5,7 @@

#include "application-meditation/windows/Names.hpp"
#include "application-meditation/widgets/IntervalBox.hpp"
#include "application-meditation/widgets/TimerSetter.hpp"
#include "application-meditation/widgets/TimerProperty.hpp"
#include "application-meditation/data/Style.hpp"
#include "application-meditation/data/MeditationTimerData.hpp"
#include "application-meditation/ApplicationMeditation.hpp"


@@ 42,11 42,11 @@ namespace gui
        bottomBar->setActive(BottomBar::Side::CENTER, true);
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::start));

        timeSetter = new TimerSetter(this,
                                     style::meditation::timer::X,
                                     style::meditation::timer::Y,
                                     style::meditation::timer::Width,
                                     style::meditation::timer::Height);
        timeSetter = new TimerProperty(this,
                                       style::meditation::timer::X,
                                       style::meditation::timer::Y,
                                       style::meditation::timer::Width,
                                       style::meditation::timer::Height);
        timeSetter->setEdges(RectangleEdge::None);
        setFocusItem(timeSetter);



@@ 54,7 54,8 @@ namespace gui
                                      style::meditation::intervalBox::X,
                                      style::meditation::intervalBox::Y,
                                      style::meditation::intervalBox::Width,
                                      style::meditation::intervalBox::Height);
                                      style::meditation::intervalBox::Height,
                                      timeSetter);
        intervalBox->setEdges(RectangleEdge::None);

        intervalBox->setNavigationItem(NavigationDirection::UP, timeSetter);

M module-apps/application-meditation/windows/MeditationWindow.hpp => module-apps/application-meditation/windows/MeditationWindow.hpp +2 -2
@@ 8,7 8,7 @@
namespace gui
{
    class IntervalBox;
    class TimerSetter;
    class TimerProperty;

    class MeditationWindow : public AppWindow
    {


@@ 23,7 23,7 @@ namespace gui

      private:
        void invalidate() noexcept;
        TimerSetter *timeSetter  = nullptr;
        TimerProperty *timeSetter = nullptr;
        IntervalBox *intervalBox = nullptr;
    };
} // namespace gui