~aleteoryx/muditaos

6719ccf931a6d635b0ffad6dd18a6048a95e99d3 — Dawid Wojtas 1 year, 9 months ago ecd6189
[BH-1940] New progress time widget

This widget allows to display minutes and
also seconds when 1 minute left to the end of
the timer.
M module-apps/apps-common/CMakeLists.txt => module-apps/apps-common/CMakeLists.txt +1 -0
@@ 59,6 59,7 @@ target_sources(apps-common
        widgets/TimeSetFmtSpinner.cpp
        widgets/TimeWidget.cpp
        widgets/TimeFixedWidget.cpp
        widgets/TimeMinuteSecondWidget.cpp
        widgets/DigitsContainer.cpp
        widgets/WidgetsUtils.cpp
        widgets/ProgressTimer.cpp

A module-apps/apps-common/widgets/AbstractProgressTime.hpp => module-apps/apps-common/widgets/AbstractProgressTime.hpp +18 -0
@@ 0,0 1,18 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <time/time_constants.hpp>
#include <cstdint>

namespace gui
{

    class AbstractProgressTime
    {
      public:
        virtual ~AbstractProgressTime()                = default;
        virtual void updateTime(std::uint32_t seconds) = 0;
    };
} // namespace gui

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

#include "ProgressTimerWithBarGraphAndCounter.hpp"


@@ 46,8 46,7 @@ namespace app
            return;
        }
        const auto secondsRemaining = std::chrono::duration_cast<std::chrono::seconds>(duration - elapsed);
        timeWidget->setMinutesBox(secondsRemaining.count() / 60);
        timeWidget->setSecondsBox(secondsRemaining.count() % 60);
        timeWidget->updateTime(secondsRemaining.count());
    }

    void ProgressTimerWithBarGraphAndCounter::updateProgress()


@@ 73,7 72,7 @@ namespace app
        text = _text;
    }

    void ProgressTimerWithBarGraphAndCounter::attach(gui::TimeFixedWidget *_timeWidget)
    void ProgressTimerWithBarGraphAndCounter::attach(gui::AbstractProgressTime *_timeWidget)
    {
        Expects(_timeWidget != nullptr);
        timeWidget = _timeWidget;

M module-apps/apps-common/widgets/ProgressTimerWithBarGraphAndCounter.hpp => module-apps/apps-common/widgets/ProgressTimerWithBarGraphAndCounter.hpp +6 -6
@@ 1,9 1,9 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once

#include "ProgressTimer.hpp"
#include "TimeFixedWidget.hpp"
#include "AbstractProgressTime.hpp"
#include <Timers/TimerHandle.hpp>
#include <time/time_conversion.hpp>
#include <atomic>


@@ 20,9 20,9 @@ namespace app
{
    class ProgressTimerWithBarGraphAndCounter : public ProgressTimer
    {
        gui::Text *text                  = nullptr;
        gui::Progress *progress          = nullptr;
        gui::TimeFixedWidget *timeWidget = nullptr;
        gui::Text *text{nullptr};
        gui::Progress *progress{nullptr};
        gui::AbstractProgressTime *timeWidget{nullptr};

        void update() override;
        void updateText();


@@ 34,6 34,6 @@ namespace app

        void attach(gui::Progress *_progress);
        void attach(gui::Text *_text);
        void attach(gui::TimeFixedWidget *_timeWidget);
        void attach(gui::AbstractProgressTime *_timeWidget);
    };
} // namespace app

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

#include "TimeFixedWidget.hpp"


@@ 114,6 114,12 @@ namespace gui
        colon->activeItem = false;
    }

    void TimeFixedWidget::updateTime(std::uint32_t sec)
    {
        setMinutesBox(sec / utils::time::secondsInMinute);
        setSecondsBox(sec % utils::time::secondsInMinute);
    }

    void TimeFixedWidget::setMinutesBox(std::uint32_t minutes)
    {
        leftBox.container.setMinutesBox(minutes, getInitialDimensions());

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

#pragma once


@@ 7,11 7,12 @@
#include <Text.hpp>
#include <BoxLayout.hpp>
#include "widgets/DateWidget.hpp"
#include "AbstractProgressTime.hpp"
#include <time/FromTillDate.hpp>

namespace gui
{
    class TimeFixedWidget : public Rect
    class TimeFixedWidget : public Rect, public AbstractProgressTime
    {
      public:
        struct LeftBox


@@ 49,6 50,7 @@ namespace gui
                        std::uint32_t leftBoxSize,
                        std::uint32_t rightBoxSize);

        void updateTime(std::uint32_t sec) override;
        void init(std::uint32_t w, std::uint32_t h);

        void setMinutesBox(std::uint32_t first);

A module-apps/apps-common/widgets/TimeMinuteSecondWidget.cpp => module-apps/apps-common/widgets/TimeMinuteSecondWidget.cpp +130 -0
@@ 0,0 1,130 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "TimeMinuteSecondWidget.hpp"
#include <common/LanguageUtils.hpp>

namespace
{
    std::vector<std::uint32_t> valueToDigits(std::uint32_t value)
    {
        std::vector<std::uint32_t> digits;
        while (value) {
            digits.push_back(value % 10);
            value /= 10;
        }
        std::reverse(digits.begin(), digits.end());
        return digits;
    }

    namespace digit
    {
        constexpr auto width      = 340U;
        constexpr auto height     = 95U;
        constexpr auto topMargin  = 30U;
        constexpr auto digitWidth = 48U;
        constexpr auto font       = style::window::font::supersizeme;
    } // namespace digit

    namespace description
    {
        constexpr auto width     = 226U;
        constexpr auto height    = 33U;
        constexpr auto topMargin = -2;
        constexpr auto font      = style::window::font::big;
    } // namespace description
} // namespace

namespace gui
{
    TimeMinuteSecondWidget::TimeMinuteSecondWidget(Item *parent,
                                                   const std::uint32_t &x,
                                                   const std::uint32_t &y,
                                                   const std::uint32_t &w,
                                                   const std::uint32_t &h,
                                                   DisplayType type)
        : Rect(parent, x, y, w, h), displayType{type}
    {
        buildInterface(w, h);
    }

    void TimeMinuteSecondWidget::buildInterface(const std::uint32_t w, const std::uint32_t h)
    {
        setEdges(gui::RectangleEdge::None);
        mainBox = new gui::VBox(this, 0, 0, w, h);
        mainBox->setAlignment(gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Top));
        mainBox->setEdges(gui::RectangleEdge::None);
        mainBox->activeItem = false;

        digitsContainer = new gui::HBox(mainBox, 0, 0, digit::width, digit::height);
        digitsContainer->setAlignment(
            gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center));
        digitsContainer->setEdges(gui::RectangleEdge::None);
        digitsContainer->setMargins(gui::Margins(0, digit::topMargin, 0, 0));

        for (auto i = 0U; i < maxDigits; i++) {
            digitBox[i] = new gui::VBox(digitsContainer, 0, 0, digit::digitWidth, digit::height);
            digitBox[i]->setAlignment(
                gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center));
            digitBox[i]->setEdges(gui::RectangleEdge::None);
            digitBox[i]->setMargins(gui::Margins(0, 0, 0, 0));

            digitsText[i] = new gui::Label(digitBox[i], 0, 0, 0, 0);
            digitsText[i]->setEdges(gui::RectangleEdge::None);
            digitsText[i]->setMaximumSize(digit::width, digit::height);
            digitsText[i]->setMargins(gui::Margins(0, 0, 0, 0));
            digitsText[i]->setAlignment(
                gui::Alignment{gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center});
            digitsText[i]->setFont(digit::font);

            digitBox[i]->resizeItems();
        }
        digitsContainer->resizeItems();

        descriptionBox = new gui::HBox(mainBox, 0, 0, description::width, description::height);
        descriptionBox->setAlignment(
            gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center));
        descriptionBox->setEdges(gui::RectangleEdge::None);
        descriptionBox->setMargins(gui::Margins(0, description::topMargin, 0, 0));

        description = new gui::Label(descriptionBox, 0, 0, 0, 0);
        description->setEdges(gui::RectangleEdge::None);
        description->setMaximumSize(description::width, description::height);
        description->setMargins(gui::Margins(0, 0, 0, 0));
        description->setAlignment(gui::Alignment{gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center});
        description->setFont(description::font);

        descriptionBox->resizeItems();
        mainBox->resizeItems();
    }

    void TimeMinuteSecondWidget::updateTime(std::uint32_t seconds)
    {
        if (seconds >= utils::time::secondsInMinute || displayType == DisplayType::OnlyMinutes) {
            const auto minutes = (seconds + utils::time::secondsInMinute - 1) / utils::time::secondsInMinute;
            setText(minutes);
            description->setText(utils::language::getCorrectMinutesNumeralForm(minutes));
        }
        else {
            setText(seconds);
            description->setText(utils::language::getCorrectSecondsNumeralForm(seconds));
        }
    }

    void TimeMinuteSecondWidget::setText(std::uint32_t value)
    {
        const auto digits      = valueToDigits(value);
        const auto totalDigits = digits.size();

        for (auto i = 0U; i < maxDigits; i++) {
            if (i < totalDigits) {
                digitsText[i]->setText(std::to_string(digits[i]));
                digitBox[i]->setVisible(true);
            }
            else {
                digitBox[i]->setVisible(false);
            }
        }
        digitsContainer->resizeItems();
    }
} /* namespace gui */

A module-apps/apps-common/widgets/TimeMinuteSecondWidget.hpp => module-apps/apps-common/widgets/TimeMinuteSecondWidget.hpp +43 -0
@@ 0,0 1,43 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <Label.hpp>
#include <BoxLayout.hpp>
#include "AbstractProgressTime.hpp"

namespace gui
{
    class TimeMinuteSecondWidget : public Rect, public AbstractProgressTime
    {
      public:
        enum class DisplayType
        {
            MinutesThenSeconds,
            OnlyMinutes
        };

        TimeMinuteSecondWidget(Item *parent,
                               const std::uint32_t &x,
                               const std::uint32_t &y,
                               const std::uint32_t &w,
                               const std::uint32_t &h,
                               DisplayType type = DisplayType::OnlyMinutes);

        void updateTime(std::uint32_t sec) override;
        void buildInterface(std::uint32_t w, std::uint32_t h);
        void setText(std::uint32_t value);

      private:
        DisplayType displayType;

        static constexpr auto maxDigits{3U};
        VBox *mainBox{nullptr};
        HBox *descriptionBox{nullptr};
        HBox *digitsContainer{nullptr};
        VBox *digitBox[maxDigits]{nullptr};
        Label *digitsText[maxDigits]{nullptr};
        Label *description{nullptr};
    };
} // namespace gui

M products/BellHybrid/apps/application-bell-focus-timer/windows/FocusTimerWindow.cpp => products/BellHybrid/apps/application-bell-focus-timer/windows/FocusTimerWindow.cpp +6 -2
@@ 77,8 77,12 @@ namespace app::focus
        clock->setAlignment(gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center));
        clock->setMargins(gui::Margins(0, runningStyle::clock::marginTop, 0, 0));

        timer = new gui::TimeFixedWidget(mainVBox, 0, 0, runningStyle::timer::maxSizeX, runningStyle::timer::maxSizeY);
        timer->setFontAndDimensions(runningStyle::timer::font);
        timer = new gui::TimeMinuteSecondWidget(mainVBox,
                                                0,
                                                0,
                                                runningStyle::timer::maxSizeX,
                                                runningStyle::timer::maxSizeY,
                                                gui::TimeMinuteSecondWidget::DisplayType::MinutesThenSeconds);
        timer->setMinimumSize(runningStyle::timer::maxSizeX, runningStyle::timer::maxSizeY);
        timer->setMargins(gui::Margins(0, runningStyle::timer::marginTop, 0, 0));
        timer->setAlignment(gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center));

M products/BellHybrid/apps/application-bell-focus-timer/windows/FocusTimerWindow.hpp => products/BellHybrid/apps/application-bell-focus-timer/windows/FocusTimerWindow.hpp +8 -8
@@ 8,7 8,7 @@

#include <Text.hpp>
#include <apps-common/widgets/BarGraph.hpp>
#include <apps-common/widgets/TimeFixedWidget.hpp>
#include <apps-common/widgets/TimeMinuteSecondWidget.hpp>
#include <common/widgets/BellStatusClock.hpp>
#include <gui/widgets/Icon.hpp>
#include <apps-common/windows/AppWindow.hpp>


@@ 35,13 35,13 @@ namespace app::focus

      private:
        std::unique_ptr<FocusTimerContract::Presenter> presenter;
        gui::VBox *mainVBox                   = nullptr;
        gui::ArcProgressBar *progress         = nullptr;
        gui::TimeFixedWidget *timer           = nullptr;
        gui::TextFixedSize *bottomDescription = nullptr;
        gui::Icon *iconPause                  = nullptr;
        gui::Icon *iconRing                   = nullptr;
        gui::BellStatusClock *clock           = nullptr;
        gui::VBox *mainVBox{nullptr};
        gui::ArcProgressBar *progress{nullptr};
        gui::TimeMinuteSecondWidget *timer{nullptr};
        gui::TextFixedSize *bottomDescription{nullptr};
        gui::Icon *iconPause{nullptr};
        gui::Icon *iconRing{nullptr};
        gui::BellStatusClock *clock{nullptr};

        void setTime(std::time_t newTime) override;
        void setTimeFormat(utils::time::Locale::TimeFormat fmt) override;