~aleteoryx/muditaos

e8612b25981961e7981a7fd39e80c5e057cd6160 — Maciej Gibowicz 1 year, 10 months ago ff089da
[BH-1901] Add long breaks to focus timer application

The user can set the duration and frequency of the long break in the
settings.
M image/system_a/data/lang/Deutsch.json => image/system_a/data/lang/Deutsch.json +4 -0
@@ 33,6 33,10 @@
    "app_bell_focus_time": "Konzent.-Timer",
    "app_bell_focus_repeats": "-",
    "app_bell_focus_short_break": "Kurze Pause",
    "app_bell_focus_long_break": "Lange Pause",
    "app_bell_focus_long_break_after": "-",
    "app_bell_focus_time_once": "-",
    "app_bell_focus_time_many": "-",
    "app_bell_goodbye": "Auf Wiedersehen",
    "app_bell_greeting_msg": [
        "Guten Morgen! Stehen Sie auf"

M image/system_a/data/lang/English.json => image/system_a/data/lang/English.json +4 -0
@@ 34,6 34,10 @@
    "app_bell_focus_time": "Focus timer",
    "app_bell_focus_repeats": "Focus timer repeats",
    "app_bell_focus_short_break": "Short break",
    "app_bell_focus_long_break": "Long break",
    "app_bell_focus_long_break_after": "Long break after",
    "app_bell_focus_time_once": "focus time",
    "app_bell_focus_time_many": "focus times",
    "app_bell_goodbye": "Goodbye",
    "app_bell_greeting_msg": [
        "<text>Good Morning!<br />It's a Beautiful Day!</text>",

M image/system_a/data/lang/Espanol.json => image/system_a/data/lang/Espanol.json +4 -0
@@ 32,6 32,10 @@
    "app_bell_focus_time": "T. de concentración",
    "app_bell_focus_repeats": "-",
    "app_bell_focus_short_break": "Descanso pequeño",
    "app_bell_focus_long_break": "Descanso largo",
    "app_bell_focus_long_break_after": "-",
    "app_bell_focus_time_once": "-",
    "app_bell_focus_time_many": "-",
    "app_bell_goodbye": "Adi\u00f3s",
    "app_bell_greeting_msg": [
        "\u00a1Hola! Lev\u00e1ntate y brilla"

M image/system_a/data/lang/Francais.json => image/system_a/data/lang/Francais.json +4 -0
@@ 34,6 34,10 @@
    "app_bell_focus_time": "Minuteur concen.",
    "app_bell_focus_repeats": "-",
    "app_bell_focus_short_break": "Petite pause",
    "app_bell_focus_long_break": "Longue pause",
    "app_bell_focus_long_break_after": "-",
    "app_bell_focus_time_once": "-",
    "app_bell_focus_time_many": "-",
    "app_bell_goodbye": "Au revoir",
    "app_bell_greeting_msg": [
        "Re-bonjour!"

M image/system_a/data/lang/Polski.json => image/system_a/data/lang/Polski.json +4 -0
@@ 33,6 33,10 @@
    "app_bell_focus_time": "Timer skupienia",
    "app_bell_focus_repeats": "-",
    "app_bell_focus_short_break": "Krótka przerwa",
    "app_bell_focus_long_break": "Długa przerwa",
    "app_bell_focus_long_break_after": "Długa przerwa po",
    "app_bell_focus_time_once": "-",
    "app_bell_focus_time_many": "-",
    "app_bell_goodbye": "Do widzenia",
    "app_bell_greeting_msg": [
        "<text>Dzie\u0144 dobry!<br />Pobudka</text>"

M products/BellHybrid/apps/application-bell-focus-timer/ApplicationFocusTimer.cpp => products/BellHybrid/apps/application-bell-focus-timer/ApplicationFocusTimer.cpp +14 -5
@@ 51,6 51,12 @@ namespace app
            this, focus::models::settings::focusRepeatsName, focus::models::settings::focusRepeatsDefault);
        shortBreakTimeModel = std::make_unique<focus::models::FocusSettingsModel>(
            this, focus::models::settings::shortBreakTimeName, focus::models::settings::shortBreakTimeDefault);
        longBreakTimeModel = std::make_unique<focus::models::FocusSettingsModel>(
            this, focus::models::settings::longBreakTimeName, focus::models::settings::longBreakTimeDefault);
        longBreakOccurrenceModel =
            std::make_unique<focus::models::FocusSettingsModel>(this,
                                                                focus::models::settings::longBreakOccurrenceName,
                                                                focus::models::settings::longBreakOccurrenceDefault);

        batteryModel                 = std::make_unique<app::BatteryModel>(this);
        lowBatteryInfoModel          = std::make_unique<app::LowBatteryInfoModel>();


@@ 72,8 78,11 @@ namespace app
        });

        windowsFactory.attach(focus::window::name::settings, [this](ApplicationCommon *app, const std::string &name) {
            auto presenter = std::make_unique<app::focus::SettingsPresenter>(
                *focusTimeModel, *focusRepeatsModel, *shortBreakTimeModel);
            auto presenter = std::make_unique<app::focus::SettingsPresenter>(*focusTimeModel,
                                                                             *focusRepeatsModel,
                                                                             *shortBreakTimeModel,
                                                                             *longBreakTimeModel,
                                                                             *longBreakOccurrenceModel);
            return std::make_unique<focus::SettingsWindow>(app, std::move(presenter));
        });



@@ 83,9 92,9 @@ namespace app
                                                                               *focusTimeModel,
                                                                               *focusRepeatsModel,
                                                                               *shortBreakTimeModel,
                                                                               std::move(timeModel),
                                                                               *batteryModel,
                                                                               *lowBatteryInfoModel);
                                                                               *longBreakTimeModel,
                                                                               *longBreakOccurrenceModel,
                                                                               std::move(timeModel));
            return std::make_unique<focus::FocusTimerWindow>(app, std::move(presenter));
        });


M products/BellHybrid/apps/application-bell-focus-timer/data/FocusCommon.hpp => products/BellHybrid/apps/application-bell-focus-timer/data/FocusCommon.hpp +13 -1
@@ 40,7 40,19 @@ namespace app::focus
        inline constexpr auto shortBreakTimeMin     = 0U;
        inline constexpr auto shortBreakTimeMax     = 15U;
        inline constexpr auto shortBreakTimeStep    = 1U;
        inline constexpr auto shortBreakTimeDefault = 15U;
        inline constexpr auto shortBreakTimeDefault = 5U;
        inline constexpr auto shortBreakTimeName    = "short_break";

        inline constexpr auto longBreakTimeMin     = 0U;
        inline constexpr auto longBreakTimeMax     = 30U;
        inline constexpr auto longBreakTimeStep    = 1U;
        inline constexpr auto longBreakTimeDefault = 15U;
        inline constexpr auto longBreakTimeName    = "long_break_time";

        inline constexpr auto longBreakOccurrenceMin     = 1U;
        inline constexpr auto longBreakOccurrenceMax     = 19U;
        inline constexpr auto longBreakOccurrenceStep    = 1U;
        inline constexpr auto longBreakOccurrenceDefault = 4U;
        inline constexpr auto longBreakOccurrenceName    = "long_break_occurrence";
    } // namespace models::settings
} // namespace app::focus

M products/BellHybrid/apps/application-bell-focus-timer/include/application-bell-focus-timer/ApplicationFocusTimer.hpp => products/BellHybrid/apps/application-bell-focus-timer/include/application-bell-focus-timer/ApplicationFocusTimer.hpp +2 -0
@@ 44,6 44,8 @@ namespace app
        std::unique_ptr<focus::models::FocusSettingsModel> focusTimeModel;
        std::unique_ptr<focus::models::FocusSettingsModel> focusRepeatsModel;
        std::unique_ptr<focus::models::FocusSettingsModel> shortBreakTimeModel;
        std::unique_ptr<focus::models::FocusSettingsModel> longBreakTimeModel;
        std::unique_ptr<focus::models::FocusSettingsModel> longBreakOccurrenceModel;

        std::unique_ptr<AbstractAudioModel> audioModel;
        std::unique_ptr<AbstractBatteryModel> batteryModel;

M products/BellHybrid/apps/application-bell-focus-timer/presenter/FocusSettingsPresenter.cpp => products/BellHybrid/apps/application-bell-focus-timer/presenter/FocusSettingsPresenter.cpp +72 -3
@@ 12,13 12,43 @@
#include <common/widgets/list_items/MinutesWithOff.hpp>
#include <common/widgets/list_items/Multiplicity.hpp>

namespace
{
    class FocusTimeMultiplicity : public app::list_items::Numeric
    {
      public:
        FocusTimeMultiplicity(spinner_type::range &&range,
                              gui::AbstractSettingsModel<spinner_type::value_type> &model,
                              const std::string &topDescription    = "",
                              const std::string &bottomDescription = "")
            : Numeric{std::move(range), model, topDescription, bottomDescription}
        {}

      private:
        auto getMultiplicityForm(std::uint32_t val) -> std::string
        {
            return (val == 1) ? utils::translate("app_bell_focus_time_once")
                              : utils::translate("app_bell_focus_time_many");
        }

        auto control_bottom_description(const spinner_type::value_type &value) -> void final
        {
            bottomText->setRichText(getMultiplicityForm(value));
        }
    };
} // namespace

namespace app::focus
{
    using namespace gui;
    SettingsPresenter::SettingsPresenter(models::FocusSettingsModel &focusTimeModel,
                                         models::FocusSettingsModel &focusRepeatsModel,
                                         models::FocusSettingsModel &shortBreakTimeModel)
        : focusTimeModel{focusTimeModel}, focusRepeatsModel{focusRepeatsModel}, shortBreakTimeModel{shortBreakTimeModel}
                                         models::FocusSettingsModel &shortBreakTimeModel,
                                         models::FocusSettingsModel &longBreakTimeModel,
                                         models::FocusSettingsModel &longBreakOccurrenceModel)
        : focusTimeModel{focusTimeModel}, focusRepeatsModel{focusRepeatsModel},
          shortBreakTimeModel{shortBreakTimeModel}, longBreakTimeModel{longBreakTimeModel},
          longBreakOccurrenceModel{longBreakOccurrenceModel}
    {
        auto focusTime = new list_items::Numeric{
            list_items::Numeric::spinner_type::range{


@@ 43,8 73,47 @@ namespace app::focus
            utils::translate("app_bell_focus_short_break"),
            utils::translate("common_minutes_lower_genitive")};

        auto longBreakTime = new list_items::MinutesWithOff{
            list_items::MinutesWithOff::spinner_type::range{models::settings::longBreakTimeMin,
                                                            models::settings::longBreakTimeMax,
                                                            models::settings::longBreakTimeStep},
            longBreakTimeModel,
            utils::translate("app_bell_focus_long_break"),
            utils::translate("common_minutes_lower_genitive")};

        auto longBreakOccurrence = new FocusTimeMultiplicity{
            FocusTimeMultiplicity::spinner_type::range{models::settings::longBreakOccurrenceMin,
                                                       models::settings::longBreakOccurrenceMax,
                                                       models::settings::longBreakOccurrenceStep},
            longBreakOccurrenceModel,
            utils::translate("app_bell_focus_long_break_after"),
            utils::translate("app_bell_focus_time_many")};

        listItemsProvider = std::make_shared<BellListItemProvider>(
            BellListItemProvider::Items{focusTime, focusRepeats, shortBreakTime});
            BellListItemProvider::Items{focusTime, focusRepeats, shortBreakTime, longBreakTime, longBreakOccurrence});

        focusRepeats->onExit = [this, focusRepeats, longBreakOccurrence]() {
            const auto currentValue = longBreakOccurrence->value();
            const std::uint8_t maxValue =
                std::max(models::settings::longBreakOccurrenceMin, focusRepeats->value() - 1U);
            longBreakOccurrence->set_range(list_items::Multiplicity::spinner_type::range{
                models::settings::longBreakOccurrenceMin, maxValue, models::settings::longBreakOccurrenceStep});
            longBreakOccurrence->set_value(std::min(currentValue, maxValue));
        };

        shortBreakTime->onEnter = [this, focusRepeats]() {
            if (focusRepeats->value() == 1) {
                // when the user sets only one focus session, the break settings does not matter because we do not
                // display any break after the last focus session
                getView()->exit();
            }
        };

        longBreakOccurrence->onEnter = [this, longBreakTime]() {
            if (longBreakTime->value() == 0) {
                getView()->exit();
            }
        };

        for (auto &item : listItemsProvider->getListItems()) {
            item->setValue();

M products/BellHybrid/apps/application-bell-focus-timer/presenter/FocusSettingsPresenter.hpp => products/BellHybrid/apps/application-bell-focus-timer/presenter/FocusSettingsPresenter.hpp +6 -1
@@ 26,6 26,7 @@ namespace app::focus
        {
          public:
            virtual ~View() noexcept = default;
            virtual void exit()      = 0;
        };

        class Presenter : public BasePresenter<View>


@@ 46,7 47,9 @@ namespace app::focus
      public:
        SettingsPresenter(models::FocusSettingsModel &focusTimeModel,
                          models::FocusSettingsModel &focusRepeatsModel,
                          models::FocusSettingsModel &shortBreakTimeModel);
                          models::FocusSettingsModel &shortBreakTimeModel,
                          models::FocusSettingsModel &longBreakTimeModel,
                          models::FocusSettingsModel &longBreakOccurrenceModel);

        void loadData() override;
        void saveData() override;


@@ 59,6 62,8 @@ namespace app::focus
        models::FocusSettingsModel &focusTimeModel;
        models::FocusSettingsModel &focusRepeatsModel;
        models::FocusSettingsModel &shortBreakTimeModel;
        models::FocusSettingsModel &longBreakTimeModel;
        models::FocusSettingsModel &longBreakOccurrenceModel;
        std::shared_ptr<BellListItemProvider> listItemsProvider;
    };
} // namespace app::focus

M products/BellHybrid/apps/application-bell-focus-timer/presenter/FocusTimerPresenter.cpp => products/BellHybrid/apps/application-bell-focus-timer/presenter/FocusTimerPresenter.cpp +27 -11
@@ 33,17 33,17 @@ namespace app::focus
                                             models::FocusSettingsModel &focusTimeModel,
                                             models::FocusSettingsModel &focusRepeatsModel,
                                             models::FocusSettingsModel &shortBreakTimeModel,
                                             std::unique_ptr<AbstractTimeModel> timeModel,
                                             AbstractBatteryModel &batteryModel,
                                             AbstractLowBatteryInfoModel &lowBatteryInfoModel)
        : app{app}, focusTimeModel{focusTimeModel}, focusRepeatsModel{focusRepeatsModel},
          shortBreakTimeModel{shortBreakTimeModel}, batteryModel{batteryModel},
          lowBatteryInfoModel{lowBatteryInfoModel}, timeModel{std::move(timeModel)}
                                             models::FocusSettingsModel &longBreakTimeModel,
                                             models::FocusSettingsModel &longBreakOccurrenceModel,
                                             std::unique_ptr<AbstractTimeModel> timeModel)
        : app{app}, timeModel{std::move(timeModel)}
    {
        focusSessionDuration  = std::chrono::minutes{focusTimeModel.getValue()};
        shortBreakDuration    = std::chrono::minutes{shortBreakTimeModel.getValue()};
        allFocusSessionsCount = focusRepeatsModel.getValue();
        focusSessionsLeft     = allFocusSessionsCount;
        longBreakDuration     = std::chrono::minutes{longBreakTimeModel.getValue()};
        longBreakOccurrence   = longBreakOccurrenceModel.getValue();

        betweenSessionTimer = sys::TimerFactory::createSingleShotTimer(
            app, delayBetweenSessionsTimerName, delayBetweenSessions, [this]([[maybe_unused]] sys::Timer &t) {


@@ 138,12 138,13 @@ namespace app::focus
            break;

        case FocusTimerPhase::ShortBreakTime:
            currentTimerPhase = FocusTimerPhase::ShortBreakTimeEnded;
        case FocusTimerPhase::LongBreakTime:
            currentTimerPhase = FocusTimerPhase::BreakTimeEnded;
            getView()->showTimeForFocusInfo();
            startTime();
            break;

        case FocusTimerPhase::ShortBreakTimeEnded:
        case FocusTimerPhase::BreakTimeEnded:
            currentTimerPhase = FocusTimerPhase::FocusTime;
            getView()->showFocusSessionCountdown();
            startTime();


@@ 180,8 181,13 @@ namespace app::focus
            timer->start();
            break;

        case FocusTimerPhase::LongBreakTime:
            timer->reset(longBreakDuration);
            timer->start();
            break;

        case FocusTimerPhase::FocusTimeEnded:
        case FocusTimerPhase::ShortBreakTimeEnded:
        case FocusTimerPhase::BreakTimeEnded:
        case FocusTimerPhase::AllFocusSessionsEnded:
            betweenSessionTimer.start();
            break;


@@ 192,20 198,26 @@ namespace app::focus
    {
        switch (currentTimerPhase) {
        case FocusTimerPhase::FocusTimeEnded:
        case FocusTimerPhase::ShortBreakTimeEnded:
        case FocusTimerPhase::BreakTimeEnded:
            return true;
        default:
            return false;
        }
    }

    bool FocusTimerPresenter::isTimeForLongBreak()
    {
        const auto focusSessionsElapsed = allFocusSessionsCount - focusSessionsLeft;
        return (longBreakDuration.count() > 0) && ((focusSessionsElapsed % longBreakOccurrence) == 0);
    }

    FocusTimerPresenter::FocusTimerPhase FocusTimerPresenter::handleInfoAfterFocusPhase()
    {
        if (focusSessionsLeft == 0) {
            getView()->showEndOfAllSessionsInfo();
            return FocusTimerPhase::AllFocusSessionsEnded;
        }
        if (shortBreakDuration.count() > 0) {
        if (shortBreakDuration.count() > 0 || isTimeForLongBreak()) {
            getView()->showTimeForBreakInfo();
        }
        else {


@@ 216,6 228,10 @@ namespace app::focus

    FocusTimerPresenter::FocusTimerPhase FocusTimerPresenter::handleCountdownAfterFocusPhase()
    {
        if (isTimeForLongBreak()) {
            getView()->showLongBreakCountdown();
            return FocusTimerPhase::LongBreakTime;
        }
        if (shortBreakDuration.count() > 0) {
            getView()->showShortBreakCountdown();
            return FocusTimerPhase::ShortBreakTime;

M products/BellHybrid/apps/application-bell-focus-timer/presenter/FocusTimerPresenter.hpp => products/BellHybrid/apps/application-bell-focus-timer/presenter/FocusTimerPresenter.hpp +11 -10
@@ 33,6 33,7 @@ namespace app::focus

            virtual void showFocusSessionCountdown()                        = 0;
            virtual void showShortBreakCountdown()                          = 0;
            virtual void showLongBreakCountdown()                           = 0;
            virtual void showTimeForFocusInfo()                             = 0;
            virtual void showTimeForBreakInfo()                             = 0;
            virtual void showEndOfAllSessionsInfo()                         = 0;


@@ 68,9 69,9 @@ namespace app::focus
                            models::FocusSettingsModel &focusTimeModel,
                            models::FocusSettingsModel &focusRepeatsModel,
                            models::FocusSettingsModel &shortBreakTimeModel,
                            std::unique_ptr<AbstractTimeModel> timeModel,
                            AbstractBatteryModel &batteryModel,
                            AbstractLowBatteryInfoModel &lowBatteryInfoModel);
                            models::FocusSettingsModel &longBreakTimeModel,
                            models::FocusSettingsModel &longBreakOccurrenceModel,
                            std::unique_ptr<AbstractTimeModel> timeModel);

        void setTimer(std::unique_ptr<app::TimerWithCallbacks> &&_timer) override;
        void handleUpdateTimeEvent() override;


@@ 92,28 93,28 @@ namespace app::focus
            FocusTime,
            FocusTimeEnded,
            ShortBreakTime,
            ShortBreakTimeEnded,
            LongBreakTime,
            BreakTimeEnded,
            AllFocusSessionsEnded
        };

        app::ApplicationCommon *app{nullptr};
        models::FocusSettingsModel &focusTimeModel;
        models::FocusSettingsModel &focusRepeatsModel;
        models::FocusSettingsModel &shortBreakTimeModel;
        AbstractBatteryModel &batteryModel;
        AbstractLowBatteryInfoModel &lowBatteryInfoModel;

        std::unique_ptr<app::TimerWithCallbacks> timer;
        sys::TimerHandle betweenSessionTimer;
        std::unique_ptr<AbstractTimeModel> timeModel;

        std::chrono::minutes focusSessionDuration;
        std::chrono::minutes shortBreakDuration;
        std::chrono::minutes longBreakDuration;
        std::uint32_t allFocusSessionsCount;
        std::uint32_t focusSessionsLeft;
        FocusTimerPhase currentTimerPhase = FocusTimerPhase::FocusTime;
        std::uint32_t longBreakOccurrence;
        FocusTimerPhase currentTimerPhase{FocusTimerPhase::FocusTime};

        void executeNextStep();
        bool isMiddleTimeBetweenBreakAndFocus();
        bool isTimeForLongBreak();
        FocusTimerPhase handleInfoAfterFocusPhase();
        FocusTimerPhase handleCountdownAfterFocusPhase();
    };

M products/BellHybrid/apps/application-bell-focus-timer/windows/FocusSettingsWindow.cpp => products/BellHybrid/apps/application-bell-focus-timer/windows/FocusSettingsWindow.cpp +10 -3
@@ 4,6 4,7 @@
#include "FocusSettingsWindow.hpp"

#include <common/data/StyleCommon.hpp>
#include <common/windows/BellFinishedWindow.hpp>
#include <apps-common/ApplicationCommon.hpp>
#include <module-gui/gui/input/InputEvent.hpp>
#include <module-gui/gui/widgets/SideListView.hpp>


@@ 55,8 56,7 @@ namespace app::focus
            return true;
        }
        if (inputEvent.isShortRelease(KeyCode::KEY_ENTER)) {
            isSaveNeeded = true;
            switchToExitWindow();
            exit();
            return true;
        }
        if (inputEvent.isShortRelease(KeyCode::KEY_RF)) {


@@ 68,7 68,8 @@ namespace app::focus

    void SettingsWindow::switchToExitWindow()
    {
        application->switchWindow(window::name::main);
        application->switchWindow(gui::window::bell_finished::defaultName,
                                  BellFinishedWindowData::Factory::create("circle_success_big", window::name::main));
    }

    void SettingsWindow::onClose(const CloseReason reason)


@@ 82,4 83,10 @@ namespace app::focus
            }
        }
    }

    void SettingsWindow::exit()
    {
        isSaveNeeded = true;
        switchToExitWindow();
    }
} // namespace app::focus

M products/BellHybrid/apps/application-bell-focus-timer/windows/FocusSettingsWindow.hpp => products/BellHybrid/apps/application-bell-focus-timer/windows/FocusSettingsWindow.hpp +1 -0
@@ 27,6 27,7 @@ namespace app::focus
        void onClose(CloseReason reason) override;
        bool onInput(const gui::InputEvent &inputEvent) override;
        void rebuild() override;
        void exit() override;

      private:
        void switchToExitWindow();

M products/BellHybrid/apps/application-bell-focus-timer/windows/FocusTimerWindow.cpp => products/BellHybrid/apps/application-bell-focus-timer/windows/FocusTimerWindow.cpp +10 -0
@@ 191,6 191,16 @@ namespace app::focus
        mainVBox->resizeItems();
    }

    void FocusTimerWindow::showLongBreakCountdown()
    {
        timer->setVisible(true);
        iconPause->setVisible(false);
        iconRing->setVisible(false);
        bottomDescription->setVisible(true);
        bottomDescription->setText(utils::translate("app_bell_focus_long_break"));
        mainVBox->resizeItems();
    }

    void FocusTimerWindow::showTimeForFocusInfo()
    {
        timer->setVisible(false);

M products/BellHybrid/apps/application-bell-focus-timer/windows/FocusTimerWindow.hpp => products/BellHybrid/apps/application-bell-focus-timer/windows/FocusTimerWindow.hpp +1 -0
@@ 27,6 27,7 @@ namespace app::focus
        bool onInput(const gui::InputEvent &inputEvent) override;
        void showFocusSessionCountdown() override;
        void showShortBreakCountdown() override;
        void showLongBreakCountdown() override;
        void showTimeForFocusInfo() override;
        void showTimeForBreakInfo() override;
        void showEndOfAllSessionsInfo() override;