[BH-2091] Remove timer from loop mode in Relaxation

* Removed timer logic that would refresh
the entire loop mode screen in Relaxation.
The contents of the screen doesn't change
unless there's a user activity or time
update, so the timer is not needed.
This should improve battery life in
Relaxation loop mode.
* Minor cleanups.
This commit is contained in:
Lefucjusz
2025-01-08 17:15:49 +01:00
committed by Marcin Łyda
parent ca171b7d1f
commit e84aa4a52f
16 changed files with 86 additions and 153 deletions

View File

@@ -7,6 +7,7 @@
### Added
### Changed / Improved
* Optimized power consumption in Relaxation loop mode
## [2.9.1 2024-12-16]

View File

@@ -1,9 +1,9 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#pragma once
namespace app::relaxation
{
constexpr auto timerValueDBRecordName = "RelaxationTimerValue";
inline constexpr auto timerValueDBRecordName = "RelaxationTimerValue";
} // namespace app::relaxation

View File

@@ -1,8 +1,7 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#include "RelaxationRunningLoopPresenter.hpp"
#include "data/RelaxationCommon.hpp"
#include "widgets/RelaxationPlayer.hpp"
#include <common/models/TimeModel.hpp>
@@ -17,93 +16,55 @@ namespace app::relaxation
: settings{settings}, player{player}, batteryModel{battery}, timeModel{std::move(timeModel)}
{}
void RelaxationRunningLoopPresenter::setTimer(std::unique_ptr<app::TimerWithCallbacks> &&_timer)
{
timer = std::move(_timer);
timer->registerOnFinishedCallback([this]() {
onFinished();
getView()->onFinished();
});
}
void RelaxationRunningLoopPresenter::activate(const db::multimedia_files::MultimediaFilesRecord &song)
{
Expects(timer != nullptr);
AbstractAudioModel::PlaybackMode mode;
const auto value = settings->getValue(timerValueDBRecordName, settings::SettingsScope::AppLocal);
if (utils::is_number(value) && utils::getNumericValue<int>(value) != 0) {
timer->reset(std::chrono::minutes{utils::getNumericValue<int>(value)});
mode = AbstractAudioModel::PlaybackMode::Loop;
}
else {
const auto songLength = std::chrono::seconds{song.audioProperties.songLength};
mode = AbstractAudioModel::PlaybackMode::Single;
if (songLength > std::chrono::seconds::zero()) {
timer->reset(songLength);
}
else {
getView()->handleError();
return;
}
}
auto onStartCallback = [this](audio::RetCode retCode) {
if (retCode == audio::RetCode::Success) {
timer->start();
}
else {
if (retCode != audio::RetCode::Success) {
getView()->handleError();
}
};
auto onFinishedCallback = [this](AbstractAudioModel::PlaybackFinishStatus status) {
if (status == AbstractAudioModel::PlaybackFinishStatus::Error) {
timer->stop();
if (status != AbstractAudioModel::PlaybackFinishStatus::Normal) {
getView()->handleDeletedFile(); // Deleted file is currently the only error handled by player
}
};
player.start(song.fileInfo.path, mode, std::move(onStartCallback), std::move(onFinishedCallback));
player.start(song.fileInfo.path,
AbstractAudioModel::PlaybackMode::Loop,
std::move(onStartCallback),
std::move(onFinishedCallback));
}
void RelaxationRunningLoopPresenter::stop()
{
onFinished();
timer->stop();
}
void RelaxationRunningLoopPresenter::onFinished()
{
auto onStopCallback = [this](audio::RetCode retCode) {};
auto onStopCallback = [](audio::RetCode retCode) {};
player.stop(std::move(onStopCallback));
}
void RelaxationRunningLoopPresenter::pause()
{
if (not timer->isStopped()) {
auto onPauseCallback = [this](audio::RetCode retCode) {
if (retCode == audio::RetCode::Success) {
timer->stop();
getView()->onPaused();
}
};
player.pause(std::move(onPauseCallback));
}
auto onPauseCallback = [this](audio::RetCode retCode) {
if (retCode == audio::RetCode::Success) {
getView()->onPaused();
}
};
player.pause(std::move(onPauseCallback));
}
void RelaxationRunningLoopPresenter::resume()
{
if (timer->isStopped()) {
auto onResumeCallback = [this](audio::RetCode retCode) {
if (retCode == audio::RetCode::Success) {
timer->start();
getView()->resume();
}
};
player.resume(std::move(onResumeCallback));
}
auto onResumeCallback = [this](audio::RetCode retCode) {
if (retCode == audio::RetCode::Success) {
getView()->resume();
}
};
player.resume(std::move(onResumeCallback));
}
void RelaxationRunningLoopPresenter::handleUpdateTimeEvent()
@@ -121,12 +82,7 @@ namespace app::relaxation
getView()->setTimeFormat(timeModel->getTimeFormat());
}
bool RelaxationRunningLoopPresenter::isTimerStopped()
{
return timer->isStopped();
}
Store::Battery RelaxationRunningLoopPresenter::getBatteryState()
Store::Battery RelaxationRunningLoopPresenter::getBatteryState() const
{
return batteryModel.getLevelState();
}

View File

@@ -1,10 +1,9 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#pragma once
#include <apps-common/BasePresenter.hpp>
#include <apps-common/widgets/TimerWithCallbacks.hpp>
#include <common/models/BatteryModel.hpp>
#include <module-utils/EventStore/EventStore.hpp>
#include <module-db/Interface/MultimediaFilesRecord.hpp>
@@ -17,10 +16,12 @@ namespace app
class AbstractBatteryModel;
class ApplicationCommon;
} // namespace app
namespace gui
{
class Item;
} // namespace gui
namespace settings
{
class Settings;
@@ -35,7 +36,6 @@ namespace app::relaxation
{
public:
virtual ~View() = default;
virtual void onFinished() = 0;
virtual void onPaused() = 0;
virtual void resume() = 0;
virtual void setTime(std::time_t newTime) = 0;
@@ -51,13 +51,11 @@ namespace app::relaxation
virtual void stop() = 0;
virtual void pause() = 0;
virtual void resume() = 0;
virtual bool isTimerStopped() = 0;
virtual void setTimer(std::unique_ptr<app::TimerWithCallbacks> &&timer) = 0;
virtual void handleUpdateTimeEvent() = 0;
virtual bool isPaused() = 0;
virtual void onBeforeShow() = 0;
virtual Store::Battery getBatteryState() = 0;
virtual bool isBatteryCharging(Store::Battery::State state) const = 0;
[[nodiscard]] virtual Store::Battery getBatteryState() const = 0;
[[nodiscard]] virtual bool isBatteryCharging(Store::Battery::State state) const = 0;
};
};
@@ -65,30 +63,28 @@ namespace app::relaxation
class RelaxationRunningLoopPresenter : public RelaxationRunningLoopContract::Presenter
{
settings::Settings *settings = nullptr;
public:
RelaxationRunningLoopPresenter(settings::Settings *settings,
AbstractRelaxationPlayer &player,
AbstractBatteryModel &batteryModel,
std::unique_ptr<AbstractTimeModel> timeModel);
private:
settings::Settings *settings{nullptr};
AbstractRelaxationPlayer &player;
AbstractBatteryModel &batteryModel;
std::unique_ptr<app::TimerWithCallbacks> timer;
std::unique_ptr<AbstractTimeModel> timeModel;
void activate(const db::multimedia_files::MultimediaFilesRecord &tags) override;
void stop() override;
void pause() override;
void resume() override;
bool isTimerStopped() override;
void setTimer(std::unique_ptr<app::TimerWithCallbacks> &&_timer) override;
void handleUpdateTimeEvent() override;
bool isPaused() override;
void onBeforeShow() override;
Store::Battery getBatteryState() override;
bool isBatteryCharging(Store::Battery::State state) const override;
[[nodiscard]] Store::Battery getBatteryState() const override;
[[nodiscard]] bool isBatteryCharging(Store::Battery::State state) const override;
void onFinished();
public:
RelaxationRunningLoopPresenter(settings::Settings *settings,
AbstractRelaxationPlayer &player,
AbstractBatteryModel &batteryModel,
std::unique_ptr<AbstractTimeModel> timeModel);
};
} // namespace app::relaxation

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#pragma once
@@ -65,7 +65,13 @@ namespace app::relaxation
class RelaxationRunningProgressPresenter : public RelaxationRunningProgressContract::Presenter
{
settings::Settings *settings = nullptr;
public:
RelaxationRunningProgressPresenter(settings::Settings *settings,
AbstractRelaxationPlayer &player,
std::unique_ptr<AbstractTimeModel> timeModel);
private:
settings::Settings *settings{nullptr};
AbstractRelaxationPlayer &player;
std::unique_ptr<app::TimerWithCallbacks> timer;
std::unique_ptr<AbstractTimeModel> timeModel;
@@ -83,10 +89,5 @@ namespace app::relaxation
void onBeforeShow() override;
void onFinished();
public:
RelaxationRunningProgressPresenter(settings::Settings *settings,
AbstractRelaxationPlayer &player,
std::unique_ptr<AbstractTimeModel> timeModel);
};
} // namespace app::relaxation

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#include "RelaxationTimerSelectPresenter.hpp"
@@ -66,5 +66,4 @@ namespace app::relaxation
{
lowBatteryInfoModel.handleInfo();
}
} // namespace app::relaxation

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#include "RelaxationPlayer.hpp"
@@ -27,7 +27,7 @@ namespace app::relaxation
recentFilePath = filePath;
playbackMode = mode;
auto onPlayerFinished = [callback = finishedCallback, this](Status status) {
auto onPlayerFinished = [callback = finishedCallback](Status status) {
if (status == Status::Error) {
callback(status); // Playback finished with error
}
@@ -38,8 +38,7 @@ namespace app::relaxation
auto fadeParams = audio::FadeParams{.mode = getFadeMode(), .playbackDuration = playbackDuration};
audioModel.setPlaybackFinishedCb(std::move(onPlayerFinished));
audioModel.play(
filePath, Type::Multimedia, playbackMode, std::move(stateChangeCallback), std::move(fadeParams));
audioModel.play(filePath, Type::Multimedia, playbackMode, std::move(stateChangeCallback), fadeParams);
}
audio::Fade RelaxationPlayer::getFadeMode() const
@@ -65,7 +64,7 @@ namespace app::relaxation
audioModel.resume(std::move(callback));
}
bool RelaxationPlayer::isPaused()
bool RelaxationPlayer::isPaused() const noexcept
{
return paused;
}

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#pragma once
@@ -30,9 +30,9 @@ namespace app::relaxation
virtual void stop(AbstractAudioModel::OnStateChangeCallback &&callback) = 0;
virtual void pause(AbstractAudioModel::OnStateChangeCallback &&callback) = 0;
virtual void resume(AbstractAudioModel::OnStateChangeCallback &&callback) = 0;
virtual AbstractAudioModel::PlaybackMode getCurrentMode() const noexcept = 0;
virtual audio::Fade getFadeMode() const = 0;
virtual bool isPaused() = 0;
[[nodiscard]] virtual AbstractAudioModel::PlaybackMode getCurrentMode() const noexcept = 0;
[[nodiscard]] virtual audio::Fade getFadeMode() const = 0;
[[nodiscard]] virtual bool isPaused() const noexcept = 0;
};
class RelaxationPlayer : public AbstractRelaxationPlayer
@@ -49,9 +49,9 @@ namespace app::relaxation
void stop(AbstractAudioModel::OnStateChangeCallback &&callback) override;
void pause(AbstractAudioModel::OnStateChangeCallback &&callback) override;
void resume(AbstractAudioModel::OnStateChangeCallback &&callback) override;
AbstractAudioModel::PlaybackMode getCurrentMode() const noexcept override;
audio::Fade getFadeMode() const override;
bool isPaused() override;
[[nodiscard]] AbstractAudioModel::PlaybackMode getCurrentMode() const noexcept override;
[[nodiscard]] audio::Fade getFadeMode() const override;
[[nodiscard]] bool isPaused() const noexcept override;
AbstractRelaxationFadeModel &fadeModel;
AbstractAudioModel &audioModel;

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#include "RelaxationRunningLoopWindow.hpp"
@@ -9,13 +9,10 @@
#include <ApplicationBellRelaxation.hpp>
#include <apps-common/widgets/BellBaseLayout.hpp>
#include <apps-common/widgets/ProgressTimer.hpp>
#include <Units.hpp>
namespace
{
constexpr auto relaxationLoopTimerName{"RelaxationLoopTimer"};
constexpr std::chrono::seconds relaxationLoopTimerPeriod{1};
constexpr units::SOC dischargingLevelShowTop{20};
std::string adjustDisplayedTitle(const UTF8 &title, const std::uint32_t maxCharsInLine)
@@ -72,7 +69,6 @@ namespace gui
void RelaxationRunningLoopWindow::buildInterface()
{
AppWindow::buildInterface();
configureTimer();
buildLayout();
}
@@ -129,16 +125,6 @@ namespace gui
mainVBox->resizeItems();
}
void RelaxationRunningLoopWindow::configureTimer()
{
auto timer = std::make_unique<app::ProgressTimer>(application,
*this,
relaxationLoopTimerName,
relaxationLoopTimerPeriod,
app::ProgressCountdownMode::Increasing);
presenter->setTimer(std::move(timer));
}
bool RelaxationRunningLoopWindow::onInput(const InputEvent &inputEvent)
{
if (inputEvent.isShortRelease()) {
@@ -159,11 +145,6 @@ namespace gui
return AppWindow::onInput(inputEvent);
}
void RelaxationRunningLoopWindow::onFinished()
{
application->returnToPreviousWindow();
}
void RelaxationRunningLoopWindow::onPaused()
{
application->switchWindow(gui::window::name::relaxationPaused);

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#pragma once
@@ -37,7 +37,6 @@ namespace gui
void setTime(std::time_t newTime) override;
void setTimeFormat(utils::time::Locale::TimeFormat fmt) override;
RefreshModes updateTime() override;
void onFinished() override;
void onPaused() override;
void resume() override;
bool updateBatteryStatus() override;
@@ -45,6 +44,5 @@ namespace gui
void handleDeletedFile() override;
void buildLayout();
void configureTimer();
};
} // namespace gui

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#include "RelaxationRunningProgressWindow.hpp"
@@ -157,6 +157,7 @@ namespace gui
timer->setVisible(false);
pauseBox->setVisible(true);
mainVBox->resizeItems();
application->refreshWindow(RefreshModes::GUI_REFRESH_DEEP);
}
void RelaxationRunningProgressWindow::resume()
@@ -164,6 +165,7 @@ namespace gui
timer->setVisible(true);
pauseBox->setVisible(false);
mainVBox->resizeItems();
application->refreshWindow(RefreshModes::GUI_REFRESH_DEEP);
}
void RelaxationRunningProgressWindow::configureTimer()

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#include "RelaxationTimerSelectWindow.hpp"
@@ -19,12 +19,12 @@ namespace
constexpr minutes onceValue{minutes::zero()};
constexpr minutes loopValue{8760h};
const std::string getOnceValueText()
std::string getOnceValueText()
{
return utils::translate("app_bell_relaxation_once");
}
const std::string getLoopValueText()
std::string getLoopValueText()
{
return utils::translate("app_bell_relaxation_loop");
}
@@ -61,6 +61,7 @@ namespace
return range;
}
} // namespace
namespace gui
{
@@ -107,9 +108,8 @@ namespace gui
spinner->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Center));
spinner->setEdges(RectangleEdge::None);
spinner->setFocusEdges(RectangleEdge::None);
auto currentValue = timerValueToUTF8(presenter->getCurrentTimerValue());
spinner->set_value(std::move(currentValue));
spinner->onValueChanged = [this](const auto &) {
spinner->set_value(timerValueToUTF8(presenter->getCurrentTimerValue()));
spinner->onValueChanged = [this]([[maybe_unused]] const auto &value) {
body->setMinMaxArrowsVisibility(spinner->is_min(), spinner->is_max());
updateBottomDescription();
};
@@ -150,12 +150,12 @@ namespace gui
void RelaxationTimerSelectWindow::registerCallbacks()
{
dimensionChangedCallback = [&](Item &, const BoundingBox &newDim) -> bool {
dimensionChangedCallback = [&]([[maybe_unused]] Item &item, const BoundingBox &newDim) -> bool {
body->setArea({0, 0, newDim.w, newDim.h});
return true;
};
focusChangedCallback = [&](Item &) {
focusChangedCallback = [&]([[maybe_unused]] Item &item) {
setFocusItem(focus ? body : nullptr);
if (focus) {
setFocusItem(body);
@@ -190,7 +190,7 @@ namespace gui
: gui::window::name::relaxationRunningProgress;
auto audioSwitchData = std::make_unique<RelaxationSwitchData>(std::move(audioContext));
audioSwitchData->ignoreCurrentWindowOnStack = true;
application->switchWindow(std::move(switchWindowName), std::move(audioSwitchData));
application->switchWindow(switchWindowName, std::move(audioSwitchData));
};
const auto batteryState = presenter->getBatteryState();
@@ -212,5 +212,4 @@ namespace gui
}
return AppWindow::onInput(inputEvent);
}
} // namespace gui

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#include "WhatsNewMainPresenter.hpp"
@@ -27,7 +27,7 @@ namespace app::whatsnew
settings->setValue(settings::SystemProperties::osCurrentVersion, VERSION, settings::SettingsScope::Global);
}
auto WhatsNewMainPresenter::getFeaturesCount() -> bool
auto WhatsNewMainPresenter::getFeaturesCount() -> std::size_t
{
return model.getFeatures().size();
}

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#pragma once
@@ -34,7 +34,7 @@ namespace app::whatsnew
public:
virtual ~Presenter() = default;
virtual auto setCurrentOsVersion() -> void = 0;
virtual auto getFeaturesCount() -> bool = 0;
virtual auto getFeaturesCount() -> std::size_t = 0;
virtual auto showFeatures() -> void = 0;
};
};
@@ -48,7 +48,7 @@ namespace app::whatsnew
AbstractLowBatteryInfoModel &lowBatteryInfoModel,
settings::Settings *settings);
auto setCurrentOsVersion() -> void override;
auto getFeaturesCount() -> bool override;
auto getFeaturesCount() -> std::size_t override;
auto showFeatures() -> void override;
private:

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#include <serial-number-parser/SerialNumberParser.hpp>
@@ -48,6 +48,11 @@ namespace serial_number_parser
/* New serial number constants */
constexpr auto colourCodeOffset = 4;
const std::map<char, std::string> colourCodeToColourMap{{'G', grayColor}, {'B', blackColor}};
bool isHarmonyPro(const std::string &serialNumber)
{
return (serialNumber.substr(modelCodeOffset, modelCodeLength) == harmonyProModelCode);
}
} // namespace
bool isOldSerialNumberFormat(const std::string &serialNumber)
@@ -55,11 +60,6 @@ namespace serial_number_parser
return (serialNumber.find_first_not_of("0123456789") == std::string::npos);
}
bool isHarmonyPro(const std::string &serialNumber)
{
return (serialNumber.substr(modelCodeOffset, modelCodeLength) == harmonyProModelCode);
}
std::optional<VersionMetadata> getDeviceVersionMetadata(const std::string &serialNumber)
{
if (isOldSerialNumberFormat(serialNumber)) {

View File

@@ -1,7 +1,8 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#pragma once
#include "Common.hpp"
#include <optional>