M products/BellHybrid/apps/application-bell-focus-timer/ApplicationFocusTimer.cpp => products/BellHybrid/apps/application-bell-focus-timer/ApplicationFocusTimer.cpp +10 -1
@@ 11,7 11,10 @@
#include "presenter/FocusSettingsPresenter.hpp"
#include "presenter/FocusTimerPresenter.hpp"
+#include "common/models/TimeModel.hpp"
#include <common/models/AudioModel.hpp>
+#include <common/windows/SessionPausedWindow.hpp>
+#include <common/windows/BellFinishedWindow.hpp>
#include <system/messages/SentinelRegistrationMessage.hpp>
namespace app
@@ 63,11 66,17 @@ namespace app
});
windowsFactory.attach(focus::window::name::timer, [this](ApplicationCommon *app, const std::string &name) {
+ auto timeModel = std::make_unique<app::TimeModel>();
auto presenter = std::make_unique<app::focus::FocusTimerPresenter>(
- app, settings.get(), *batteryModel, *lowBatteryInfoModel);
+ app, settings.get(), std::move(timeModel), *batteryModel, *lowBatteryInfoModel);
return std::make_unique<focus::FocusTimerWindow>(app, std::move(presenter));
});
+ windowsFactory.attach(gui::window::session_paused::sessionPaused,
+ [](ApplicationCommon *app, const std::string &name) {
+ return std::make_unique<gui::SessionPausedWindow>(app);
+ });
+
attachPopups({gui::popup::ID::AlarmActivated,
gui::popup::ID::AlarmDeactivated,
gui::popup::ID::PowerOff,
M products/BellHybrid/apps/application-bell-focus-timer/data/FocusCommon.hpp => products/BellHybrid/apps/application-bell-focus-timer/data/FocusCommon.hpp +9 -0
@@ 4,6 4,9 @@
#pragma once
#include <AppWindowConstants.hpp>
+#include <Paths.hpp>
+#include <filesystem>
+#include <string>
namespace app::focus
{
@@ 15,4 18,10 @@ namespace app::focus
inline constexpr auto settings = "FocusTimerSettingsWindow";
inline constexpr auto timer = "FocusTimerSessionWindow";
} // namespace window::name
+
+ inline std::filesystem::path getFocusTimeAudioPath()
+ {
+ return paths::audio::proprietary() / paths::audio::focusTimer() / "FocusTimer_Gong.mp3";
+ }
+
} // namespace app::focus
A products/BellHybrid/apps/application-bell-focus-timer/data/FocusTimerStyle.hpp => products/BellHybrid/apps/application-bell-focus-timer/data/FocusTimerStyle.hpp +72 -0
@@ 0,0 1,72 @@
+// 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 <Style.hpp>
+#include "widgets/BellBaseLayout.hpp"
+
+namespace app::focusTimerStyle
+{
+ namespace runningStyle
+ {
+ namespace progress
+ {
+ inline constexpr auto radius = 192u;
+ inline constexpr auto penWidth = 3u;
+ inline constexpr auto verticalDeviationDegrees = 38u;
+ } // namespace progress
+
+ namespace timer
+ {
+ inline constexpr auto font = style::window::font::supersizeme;
+ inline constexpr auto maxSizeX = 340u;
+ inline constexpr auto maxSizeY = 198u;
+ inline constexpr auto marginTop = 19u;
+ } // namespace timer
+
+ namespace pauseIcon
+ {
+ inline constexpr auto image = "big_pause";
+ inline constexpr auto maxSizeX = 203u;
+ inline constexpr auto maxSizeY = 203u;
+ inline constexpr auto marginTop = timer::marginTop - (maxSizeY - timer::maxSizeY);
+ } // namespace pauseIcon
+
+ namespace ringIcon
+ {
+ inline constexpr auto image = "big_bell_ringing";
+ inline constexpr auto maxSizeX = 220u;
+ inline constexpr auto maxSizeY = 203u;
+ inline constexpr auto marginTop = timer::marginTop - (maxSizeY - timer::maxSizeY);
+ } // namespace ringIcon
+
+ namespace bottomDescription
+ {
+ inline constexpr auto marginTop = 38u;
+ inline constexpr auto maxSizeX = style::bell_base_layout::w;
+ inline constexpr auto maxSizeY = 42u;
+ inline constexpr auto font = style::window::font::verybig;
+ } // namespace bottomDescription
+
+ namespace clock
+ {
+ inline constexpr auto marginTop = 17u;
+ inline constexpr auto maxSizeX = 340u;
+ inline constexpr auto maxSizeY = 84u;
+ } // namespace clock
+ } // namespace runningStyle
+
+ namespace timerStyle
+ {
+ namespace text
+ {
+ inline constexpr auto font = style::window::font::supersizemelight;
+ }
+
+ namespace minute
+ {
+ inline constexpr auto font = style::window::font::largelight;
+ }
+ } // namespace timerStyle
+} // namespace app::focusTimerStyle
M products/BellHybrid/apps/application-bell-focus-timer/presenter/FocusTimerPresenter.cpp => products/BellHybrid/apps/application-bell-focus-timer/presenter/FocusTimerPresenter.cpp +173 -2
@@ 3,13 3,184 @@
#include "FocusTimerPresenter.hpp"
+#include "FocusCommon.hpp"
+#include "Application.hpp"
+#include "widgets/ProgressTimer.hpp"
+
+#include <common/LanguageUtils.hpp>
+#include <common/models/TimeModel.hpp>
+#include <common/windows/BellFinishedWindow.hpp>
+#include <service-db/Settings.hpp>
+
+namespace
+{
+ static constexpr std::chrono::milliseconds betweenSessionDelayTime{5000};
+} // namespace
+
namespace app::focus
{
+
FocusTimerPresenter::FocusTimerPresenter(app::ApplicationCommon *app,
settings::Settings *settings,
+ std::unique_ptr<AbstractTimeModel> timeModel,
AbstractBatteryModel &batteryModel,
AbstractLowBatteryInfoModel &lowBatteryInfoModel)
- : app{app}, settings{settings}, batteryModel{batteryModel}, lowBatteryInfoModel{lowBatteryInfoModel}
- {}
+ : app{app}, settings{settings}, batteryModel{batteryModel},
+ lowBatteryInfoModel{lowBatteryInfoModel}, timeModel{std::move(timeModel)}
+ {
+ // focusSessionDuration = std::chrono::minutes{
+ // utils::getNumericValue<int>(settings->getValue(focusDBRecordName,
+ // settings::SettingsScope::AppLocal))};
+ // shortBreakDuration = std::chrono::minutes{
+ // utils::getNumericValue<int>(settings->getValue(focusDBRecordName,
+ // settings::SettingsScope::AppLocal))};
+ // focusSessionsLeft =
+ // utils::getNumericValue<int>(settings->getValue(focusDBRecordName,
+ // settings::SettingsScope::AppLocal));
+
+ focusSessionDuration = std::chrono::minutes{25};
+ shortBreakDuration = std::chrono::minutes{5};
+
+ allFocusSessionsCount = 10;
+ focusSessionsLeft = allFocusSessionsCount;
+
+ betweenSessionTimer = sys::TimerFactory::createSingleShotTimer(
+ app, "betweenSessionTimer", betweenSessionDelayTime, [this](sys::Timer &) { executeNextStep(); });
+ }
+
+ void FocusTimerPresenter::setTimer(std::unique_ptr<app::TimerWithCallbacks> &&_timer)
+ {
+ timer = std::move(_timer);
+ timer->registerOnFinishedCallback([this]() { executeNextStep(); });
+ }
+
+ void FocusTimerPresenter::handleUpdateTimeEvent()
+ {
+ getView()->setTime(timeModel->getCurrentTime());
+ }
+
+ void FocusTimerPresenter::start()
+ {
+ static_cast<app::Application *>(app)->suspendIdleTimer();
+ startTime();
+ }
+
+ void FocusTimerPresenter::stop()
+ {
+ finish();
+ }
+
+ bool FocusTimerPresenter::isTimerStopped()
+ {
+ return timer->isStopped();
+ }
+
+ bool FocusTimerPresenter::isAllSessionsFinished()
+ {
+ return currentTimerPhase == FocusTimerPhase::AllFocusSessionsEnded;
+ }
+
+ void FocusTimerPresenter::pause()
+ {
+ betweenSessionTimer.stop();
+ timer->stop();
+ getView()->pause();
+ }
+
+ void FocusTimerPresenter::resume()
+ {
+ isMiddleTimeBetweenBreakAndFocus() ? executeNextStep() : timer->start();
+ getView()->resume();
+ }
+
+ void FocusTimerPresenter::abandon()
+ {
+ finish();
+ }
+
+ void FocusTimerPresenter::finish()
+ {
+ timer->stop();
+ betweenSessionTimer.stop();
+ app->switchWindow(focus::window::name::main);
+ }
+
+ void FocusTimerPresenter::executeNextStep()
+ {
+ switch (currentTimerPhase) {
+ case FocusTimerPhase::FocusTime:
+ focusSessionsLeft--;
+ if (focusSessionsLeft == 0) {
+ currentTimerPhase = FocusTimerPhase::AllFocusSessionsEnded;
+ getView()->onAllFocusSessionsFinished();
+ startTime();
+ }
+ else {
+ currentTimerPhase = FocusTimerPhase::FocusTimeEnded;
+ getView()->onFocusSessionFinished();
+ startTime();
+ }
+ break;
+
+ case FocusTimerPhase::FocusTimeEnded:
+ currentTimerPhase = FocusTimerPhase::ShortBreakTime;
+ getView()->onShortBreakStarted();
+ startTime();
+ break;
+
+ case FocusTimerPhase::ShortBreakTime:
+ currentTimerPhase = FocusTimerPhase::ShortBreakTimeEnded;
+ getView()->onShortBreakFinished();
+ startTime();
+ break;
+
+ case FocusTimerPhase::ShortBreakTimeEnded:
+ currentTimerPhase = FocusTimerPhase::FocusTime;
+ getView()->onFocusSessionStarted();
+ startTime();
+ break;
+
+ case FocusTimerPhase::AllFocusSessionsEnded:
+ finish();
+ break;
+ }
+ }
+
+ void FocusTimerPresenter::onBeforeShow()
+ {
+ getView()->setTimeFormat(timeModel->getTimeFormat());
+ }
+
+ void FocusTimerPresenter::startTime()
+ {
+ switch (currentTimerPhase) {
+ case FocusTimerPhase::FocusTime:
+ timer->reset(std::chrono::minutes(focusSessionDuration));
+ timer->start();
+ break;
+
+ case FocusTimerPhase::ShortBreakTime:
+ timer->reset(std::chrono::minutes(shortBreakDuration));
+ timer->start();
+ break;
+
+ case FocusTimerPhase::FocusTimeEnded:
+ case FocusTimerPhase::ShortBreakTimeEnded:
+ case FocusTimerPhase::AllFocusSessionsEnded:
+ betweenSessionTimer.start();
+ break;
+ }
+ }
+
+ bool FocusTimerPresenter::isMiddleTimeBetweenBreakAndFocus()
+ {
+ switch (currentTimerPhase) {
+ case FocusTimerPhase::FocusTimeEnded:
+ case FocusTimerPhase::ShortBreakTimeEnded:
+ return true;
+ default:
+ return false;
+ }
+ }
} // namespace app::focus
M products/BellHybrid/apps/application-bell-focus-timer/presenter/FocusTimerPresenter.hpp => products/BellHybrid/apps/application-bell-focus-timer/presenter/FocusTimerPresenter.hpp +65 -2
@@ 7,6 7,15 @@
#include <apps-common/ApplicationCommon.hpp>
#include <common/models/BatteryModel.hpp>
#include <common/models/LowBatteryInfoModel.hpp>
+#include <apps-common/widgets/TimerWithCallbacks.hpp>
+#include <time/time_locale.hpp>
+#include "widgets/ProgressTimer.hpp"
+
+namespace app
+{
+ class AbstractTimeModel;
+ class ApplicationCommon;
+} // namespace app
namespace app::focus
{
@@ 16,28 25,82 @@ namespace app::focus
class View
{
public:
- virtual ~View() noexcept = default;
+ virtual ~View() noexcept = default;
+ virtual void onAllFocusSessionsFinished() = 0;
+ virtual void onFocusSessionStarted() = 0;
+ virtual void onFocusSessionFinished() = 0;
+ virtual void onShortBreakStarted() = 0;
+ virtual void onShortBreakFinished() = 0;
+ virtual void setTime(std::time_t newTime) = 0;
+ virtual void setTimeFormat(utils::time::Locale::TimeFormat fmt) = 0;
+ virtual void pause() = 0;
+ virtual void resume() = 0;
};
class Presenter : public BasePresenter<View>
{
public:
- virtual ~Presenter() noexcept = default;
+ virtual ~Presenter() noexcept = default;
+ virtual void setTimer(std::unique_ptr<app::TimerWithCallbacks> &&timer) = 0;
+ virtual void handleUpdateTimeEvent() = 0;
+ virtual bool isTimerStopped() = 0;
+ virtual bool isAllSessionsFinished() = 0;
+ virtual void start() = 0;
+ virtual void stop() = 0;
+ virtual void pause() = 0;
+ virtual void resume() = 0;
+ virtual void abandon() = 0;
+ virtual void finish() = 0;
+ virtual void onBeforeShow() = 0;
};
};
class FocusTimerPresenter : public FocusTimerContract::Presenter
{
public:
+ enum class FocusTimerPhase
+ {
+ FocusTime,
+ FocusTimeEnded,
+ ShortBreakTime,
+ ShortBreakTimeEnded,
+ AllFocusSessionsEnded
+ };
FocusTimerPresenter(app::ApplicationCommon *app,
settings::Settings *settings,
+ std::unique_ptr<AbstractTimeModel> timeModel,
AbstractBatteryModel &batteryModel,
AbstractLowBatteryInfoModel &lowBatteryInfoModel);
+ void setTimer(std::unique_ptr<app::TimerWithCallbacks> &&_timer) override;
+ void handleUpdateTimeEvent() override;
+ bool isTimerStopped() override;
+ bool isAllSessionsFinished() override;
+ void start() override;
+ void stop() override;
+ void pause() override;
+ void resume() override;
+ void abandon() override;
+ void finish() override;
+ void onBeforeShow() override;
+ void startTime();
+
private:
app::ApplicationCommon *app{nullptr};
settings::Settings *settings{nullptr};
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::uint32_t allFocusSessionsCount;
+ std::uint32_t focusSessionsLeft;
+ FocusTimerPhase currentTimerPhase = FocusTimerPhase::FocusTime;
+
+ void executeNextStep();
+ bool isMiddleTimeBetweenBreakAndFocus();
};
} // namespace app::focus
M products/BellHybrid/apps/application-bell-focus-timer/windows/FocusTimerWindow.cpp => products/BellHybrid/apps/application-bell-focus-timer/windows/FocusTimerWindow.cpp +223 -0
@@ 2,10 2,27 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "FocusTimerWindow.hpp"
+#include <data/FocusTimerStyle.hpp>
+#include <Application.hpp>
+#include <products/BellHybrid/services/audio/include/audio/AudioMessage.hpp>
+#include <apps-common/widgets/BellBaseLayout.hpp>
#include <apps-common/ApplicationCommon.hpp>
+#include <apps-common/widgets/ProgressTimerWithBarGraphAndCounter.hpp>
#include <module-gui/gui/input/InputEvent.hpp>
+namespace
+{
+ constexpr auto focusTimerProgressTimerName{"FocusProgressTimer"};
+ constexpr std::chrono::seconds focusTimerProgressTimerPeriod{1};
+ constexpr auto focusTimerProgressMode{app::ProgressCountdownMode::Increasing};
+ constexpr auto focusTimerText{"Focus timer"};
+ constexpr auto timeToFocusText{"Time to focus"};
+ constexpr auto shortBreakTimeText{"Short break"};
+ constexpr auto timeForBreakText{"Time for a break"};
+ constexpr auto endOfAllSessionText{"Well done!"};
+} // namespace
+
namespace app::focus
{
FocusTimerWindow::FocusTimerWindow(app::ApplicationCommon *app,
@@ 20,10 37,216 @@ namespace app::focus
void FocusTimerWindow::buildInterface()
{
AppWindow::buildInterface();
+
+ statusBar->setVisible(false);
+ header->setTitleVisibility(false);
+ navBar->setVisible(false);
+
+ buildLayout();
+ configureTimer();
+ }
+
+ void FocusTimerWindow::buildLayout()
+ {
+ using namespace app::focusTimerStyle;
+ const auto progressArcRadius = runningStyle::progress::radius;
+ const auto progressArcWidth = runningStyle::progress::penWidth;
+ const auto arcStartAngle =
+ -90 - runningStyle::progress::verticalDeviationDegrees; // -90 to start drawing the circle from top
+ const auto arcSweepAngle = 360 - (2 * runningStyle::progress::verticalDeviationDegrees);
+ const auto arcProgressSteps = 1000;
+
+ gui::Arc::ShapeParams arcParams;
+ arcParams.setCenterPoint(gui::Point(getWidth() / 2, getHeight() / 2))
+ .setRadius(progressArcRadius)
+ .setStartAngle(arcStartAngle)
+ .setSweepAngle(arcSweepAngle)
+ .setPenWidth(progressArcWidth)
+ .setBorderColor(gui::ColorFullBlack);
+
+ progress = new gui::ArcProgressBar(this,
+ arcParams,
+ gui::ArcProgressBar::ProgressDirection::CounterClockwise,
+ gui::ArcProgressBar::ProgressChange::DecrementFromFull);
+ progress->setMaximum(arcProgressSteps);
+
+ mainVBox = new gui::VBox(this, 0, 0, style::window_width, style::window_height);
+
+ clock = new gui::BellStatusClock(mainVBox);
+ clock->setMaximumSize(runningStyle::clock::maxSizeX, runningStyle::clock::maxSizeY);
+ 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->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));
+
+ iconPause = new gui::Icon(mainVBox, 0, 0, 0, 0, {}, {});
+ iconPause->setMinimumSize(runningStyle::pauseIcon::maxSizeX, runningStyle::pauseIcon::maxSizeY);
+ iconPause->setMargins(gui::Margins(0, runningStyle::pauseIcon::marginTop, 0, 0));
+ iconPause->setAlignment(gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Top));
+ iconPause->image->set(runningStyle::pauseIcon::image, gui::ImageTypeSpecifier::W_G);
+ iconPause->setVisible(false);
+
+ iconRing = new gui::Icon(mainVBox, 0, 0, 0, 0, {}, {});
+ iconRing->setMinimumSize(runningStyle::ringIcon::maxSizeX, runningStyle::ringIcon::maxSizeY);
+ iconRing->setMargins(gui::Margins(0, runningStyle::ringIcon::marginTop, 0, 0));
+ iconRing->setAlignment(gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Top));
+ iconRing->image->set(runningStyle::ringIcon::image, gui::ImageTypeSpecifier::W_G);
+ iconRing->setVisible(false);
+
+ bottomDescription = new gui::TextFixedSize(mainVBox, 0, 0, 250, 80);
+ bottomDescription->setMaximumSize(runningStyle::bottomDescription::maxSizeX,
+ runningStyle::bottomDescription::maxSizeY);
+ bottomDescription->setFont(runningStyle::bottomDescription::font);
+ bottomDescription->setMargins(gui::Margins(0, 0, 0, 0));
+ bottomDescription->activeItem = false;
+ bottomDescription->setAlignment(
+ gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Top));
+ bottomDescription->setRichText(focusTimerText);
+ bottomDescription->drawUnderline(false);
+ bottomDescription->setVisible(true);
+
+ mainVBox->resizeItems();
+ }
+
+ void FocusTimerWindow::onBeforeShow(gui::ShowMode mode, gui::SwitchData *data)
+ {
+ AppWindow::onBeforeShow(mode, data);
+ presenter->onBeforeShow();
+ updateTime();
+ if (mode == gui::ShowMode::GUI_SHOW_INIT) {
+ playGong();
+ presenter->start();
+ }
}
bool FocusTimerWindow::onInput(const gui::InputEvent &inputEvent)
{
+ if (inputEvent.isShortRelease(gui::KeyCode::KEY_ENTER)) {
+ if (presenter->isAllSessionsFinished()) {
+ presenter->finish();
+ }
+ if (presenter->isTimerStopped()) {
+ presenter->resume();
+ }
+ else {
+ presenter->pause();
+ }
+ return true;
+ }
+ if (inputEvent.isShortRelease(gui::KeyCode::KEY_RF)) {
+ static_cast<app::Application *>(application)->resumeIdleTimer();
+ presenter->abandon();
+ return true;
+ }
+
return AppWindow::onInput(inputEvent);
}
+
+ void FocusTimerWindow::onAllFocusSessionsFinished()
+ {
+ timer->setVisible(false);
+ iconPause->setVisible(false);
+ iconRing->setVisible(true);
+ bottomDescription->setVisible(true);
+ bottomDescription->setText(endOfAllSessionText);
+ mainVBox->resizeItems();
+ playGong();
+ }
+
+ void FocusTimerWindow::onFocusSessionStarted()
+ {
+ timer->setVisible(true);
+ iconPause->setVisible(false);
+ iconRing->setVisible(false);
+ bottomDescription->setVisible(true);
+ bottomDescription->setText(focusTimerText);
+ mainVBox->resizeItems();
+ }
+
+ void FocusTimerWindow::onFocusSessionFinished()
+ {
+ timer->setVisible(false);
+ iconPause->setVisible(false);
+ iconRing->setVisible(true);
+ bottomDescription->setVisible(true);
+ bottomDescription->setText(timeForBreakText);
+ mainVBox->resizeItems();
+ playGong();
+ }
+
+ void FocusTimerWindow::onShortBreakStarted()
+ {
+ timer->setVisible(true);
+ iconPause->setVisible(false);
+ iconRing->setVisible(false);
+ bottomDescription->setVisible(true);
+ bottomDescription->setText(shortBreakTimeText);
+ mainVBox->resizeItems();
+ }
+
+ void FocusTimerWindow::onShortBreakFinished()
+ {
+ timer->setVisible(false);
+ iconPause->setVisible(false);
+ iconRing->setVisible(true);
+ bottomDescription->setVisible(true);
+ bottomDescription->setText(timeToFocusText);
+ mainVBox->resizeItems();
+ playGong();
+ }
+
+ void FocusTimerWindow::pause()
+ {
+ timer->setVisible(false);
+ iconPause->setVisible(true);
+ iconRing->setVisible(false);
+ mainVBox->resizeItems();
+ }
+
+ void FocusTimerWindow::resume()
+ {
+ timer->setVisible(true);
+ iconPause->setVisible(false);
+ iconRing->setVisible(false);
+ mainVBox->resizeItems();
+ }
+
+ void FocusTimerWindow::configureTimer()
+ {
+ auto progressTimer = std::make_unique<app::ProgressTimerWithBarGraphAndCounter>(
+ application, *this, focusTimerProgressTimerName, focusTimerProgressTimerPeriod, focusTimerProgressMode);
+ progressTimer->attach(progress);
+ progressTimer->attach(timer);
+ presenter->setTimer(std::move(progressTimer));
+ }
+
+ void FocusTimerWindow::setTime(std::time_t newTime)
+ {
+ clock->setTime(newTime);
+ clock->setTimeFormatSpinnerVisibility(true);
+ }
+
+ void FocusTimerWindow::setTimeFormat(utils::time::Locale::TimeFormat fmt)
+ {
+ clock->setTimeFormat(fmt);
+ }
+
+ gui::RefreshModes FocusTimerWindow::updateTime()
+ {
+ if (presenter != nullptr) {
+ presenter->handleUpdateTimeEvent();
+ }
+ return gui::RefreshModes::GUI_REFRESH_FAST;
+ }
+
+ void FocusTimerWindow::playGong()
+ {
+ auto msg = std::make_shared<service::AudioStartPlaybackRequest>(app::focus::getFocusTimeAudioPath(),
+ audio::PlaybackType::Meditation);
+ application->bus.sendUnicast(std::move(msg), service::audioServiceName);
+ }
} // namespace app::focus
M products/BellHybrid/apps/application-bell-focus-timer/windows/FocusTimerWindow.hpp => products/BellHybrid/apps/application-bell-focus-timer/windows/FocusTimerWindow.hpp +29 -0
@@ 6,6 6,11 @@
#include "data/FocusCommon.hpp"
#include "presenter/FocusTimerPresenter.hpp"
+#include <Text.hpp>
+#include <apps-common/widgets/BarGraph.hpp>
+#include <apps-common/widgets/TimeFixedWidget.hpp>
+#include <common/widgets/BellStatusClock.hpp>
+#include <gui/widgets/Icon.hpp>
#include <apps-common/windows/AppWindow.hpp>
namespace app::focus
@@ 17,10 22,34 @@ namespace app::focus
std::unique_ptr<FocusTimerContract::Presenter> &&windowPresenter,
const std::string &name = window::name::timer);
+ void onBeforeShow(gui::ShowMode mode, gui::SwitchData *data) override;
void buildInterface() override;
bool onInput(const gui::InputEvent &inputEvent) override;
+ void onAllFocusSessionsFinished() override;
+ void onFocusSessionStarted() override;
+ void onFocusSessionFinished() override;
+ void onShortBreakStarted() override;
+ void onShortBreakFinished() override;
+ void pause() override;
+ void resume() override;
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;
+
+ void setTime(std::time_t newTime) override;
+ void setTimeFormat(utils::time::Locale::TimeFormat fmt) override;
+ gui::RefreshModes updateTime() override;
+
+ void buildLayout();
+ void configureTimer();
+
+ void playGong();
};
} // namespace app::focus
M products/BellHybrid/assets/assets_common.json => products/BellHybrid/assets/assets_common.json +1 -0
@@ 86,6 86,7 @@
{"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/bg_sounds/Woodland_Ambiance.mp3", "output": "assets/audio/relaxation/Woodland_Ambiance.mp3"},
{"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/meditation/Meditation_Gong.mp3", "output": "assets/audio/meditation/Meditation_Gong.mp3"},
{"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/meditation/Meditation_End.mp3", "output": "assets/audio/meditation/Meditation_End.mp3"},
+ {"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/focus_timer/FocusTimer_Gong.mp3", "output": "assets/audio/focus_timer/FocusTimer_Gong.mp3"},
{"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/prewakeup/Joyful_Awakening.mp3", "output": "assets/audio/prewakeup/Joyful_Awakening.mp3"},
{"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/prewakeup/Morning_Spirit.mp3", "output": "assets/audio/prewakeup/Morning_Spirit.mp3"},
{"name": "release_audio.tgz", "tarfile" :"./image/assets/audio/bell/prewakeup/Radiant_Morning.mp3", "output": "assets/audio/prewakeup/Radiant_Morning.mp3"},
M products/BellHybrid/paths/Paths.cpp => products/BellHybrid/paths/Paths.cpp +5 -0
@@ 44,6 44,11 @@ std::filesystem::path paths::audio::meditation() noexcept
return "meditation";
}
+std::filesystem::path paths::audio::focusTimer() noexcept
+{
+ return "focus_timer";
+}
+
std::filesystem::path paths::audio::colorOfNoises() noexcept
{
return "noises";
M products/BellHybrid/paths/Paths.hpp => products/BellHybrid/paths/Paths.hpp +1 -0
@@ 17,6 17,7 @@ namespace paths
std::filesystem::path bedtimeReminder() noexcept;
std::filesystem::path relaxation() noexcept;
std::filesystem::path meditation() noexcept;
+ std::filesystem::path focusTimer() noexcept;
std::filesystem::path colorOfNoises() noexcept;
} // namespace audio
} // namespace paths