// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "IntervalBox.hpp" #include "application-meditation/data/Style.hpp" #include "Style.hpp" #include "TimerProperty.hpp" #include "InputEvent.hpp" #include #include using namespace gui; namespace { using minutes = std::chrono::minutes; const static std::vector chimeIntervals{ minutes{0}, minutes{2}, minutes{5}, minutes{10}, minutes{15}, minutes{30}}; } // namespace 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(); } void IntervalBox::build() { namespace boxStyle = style::meditation::intervalBox; 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); bottomLabel = new Label(this, boxStyle::bottomLabel::X, boxStyle::bottomLabel::Y, boxStyle::bottomLabel::Width, boxStyle::bottomLabel::Height); 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, boxStyle::arrow::Y, boxStyle::arrow::Width, boxStyle::arrow::Height, "left_label_arrow"); rightSwitchArrow = new gui::Image(bottomLabel, boxStyle::arrow::RightX, boxStyle::arrow::Y, boxStyle::arrow::Width, boxStyle::arrow::Height, "right_label_arrow"); 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); } auto currentMeditationTime = timerSetter->getTime(); leftSwitchArrow->setVisible(state && chimeIntervals.hasNext(ChimeIntervalList::Direction::Previous, currentMeditationTime)); rightSwitchArrow->setVisible(state && chimeIntervals.hasNext(ChimeIntervalList::Direction::Next, currentMeditationTime)); return true; } bool IntervalBox::onInput(const InputEvent &inputEvent) { if (inputEvent.isShortPress()) { if (inputEvent.is(KeyCode::KEY_LEFT)) { updateIntervals(ChimeIntervalList::Direction::Previous); return true; } else if (inputEvent.is(KeyCode::KEY_RIGHT)) { updateIntervals(ChimeIntervalList::Direction::Next); return true; } } return false; } void IntervalBox::updateIntervals(ChimeIntervalList::Direction direction) { auto currentMeditationTime = timerSetter->getTime(); if (!chimeIntervals.moveToNext(direction, currentMeditationTime)) { return; } intervalValue = chimeIntervals.getCurrent(); bottomLabel->setText(ChimeIntervalList::toPrintableInterval(intervalValue)); leftSwitchArrow->setVisible(chimeIntervals.hasNext(ChimeIntervalList::Direction::Previous, currentMeditationTime)); rightSwitchArrow->setVisible(chimeIntervals.hasNext(ChimeIntervalList::Direction::Next, currentMeditationTime)); } 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, std::chrono::minutes meditationTime) noexcept { if (!hasNext(direction, meditationTime)) { return false; } if (direction == Direction::Next) { current++; } else { current--; } return true; } bool IntervalBox::ChimeIntervalList::hasNext(Direction direction, std::chrono::minutes meditationTime) const noexcept { if (direction == Direction::Previous) { return current != intervals.begin(); } auto result = std::next(current) != intervals.end(); if (result) { result = *std::next(current) < meditationTime; } return result; } std::string IntervalBox::ChimeIntervalList::toPrintableInterval(std::chrono::minutes value) { if (value.count() == 0) { return utils::localize.get("app_meditation_interval_none"); } const std::string toReplace = "%0"; std::string temp = utils::localize.get("app_meditation_interval_every_x_minutes"); temp.replace(temp.find(toReplace), toReplace.size(), std::to_string(static_cast(value.count()))); return temp; }