M harmony_changelog.md => harmony_changelog.md +2 -0
@@ 17,10 17,12 @@
### Added
* Added error handling for incorrect audio formats and corrupted files inside Relaxation app
+* Added error message when files limit is exceeded in Relaxation app
### Changed
* Added new field to deviceInfo endpoint
+* Changed order in which files are displayed in Relaxation
## [1.9.0 2023-04-03]
M image/system_a/data/lang/Deutsch.json => image/system_a/data/lang/Deutsch.json +1 -0
@@ 667,6 667,7 @@
"app_bell_relaxation_looped": "geschlungen",
"app_bell_relaxation_loop_description": "der Titel wird abgespielt, bis Sie ihn ausschalten",
"app_bell_relaxation_error_message": "Nicht unterstütztes Dateiformat",
+ "app_bell_relaxation_limit_error_message": "<text>Datenlimit überschritten.<br />Es könnte zu Fehlern kommen.</text>",
"app_bell_onboarding_info_rotate": "Drehen um auszuwählen",
"app_bell_onboarding_info_light_click": "Leichter Klick um fortzufahren",
"app_bell_onboarding_info_deep_click_warning": "Sie haben tief gedrückt",
M image/system_a/data/lang/English.json => image/system_a/data/lang/English.json +1 -0
@@ 716,6 716,7 @@
"app_bell_relaxation_looped": "looped",
"app_bell_relaxation_loop_description": "the song will play until you turn it off",
"app_bell_relaxation_error_message": "Unsupported media type",
+ "app_bell_relaxation_limit_error_message": "<text>File limit exceeded.<br />Not all files may be displayed<br />correctly</text>",
"app_bell_turn_off_question": "Turn off Mudita Harmony?",
"app_bell_goodbye": "Goodbye",
"app_bell_reset_message": "<text>Resetting Mudita<br />Harmony</text>",
M image/system_a/data/lang/Espanol.json => image/system_a/data/lang/Espanol.json +1 -0
@@ 683,6 683,7 @@
"app_bell_relaxation_looped": "en bucle",
"app_bell_relaxation_loop_description": "la canción se reproducirá hasta que la apagues",
"app_bell_relaxation_error_message": "Formato de archivo no admitido",
+ "app_bell_relaxation_limit_error_message": "<text>Límite de archivos alcanzado,<br />pueden producirse errores.</text>",
"app_bell_settings_home_view": "Vista de inicio",
"app_bell_settings_alarm_settings": "Ajustes de alarma",
"app_bell_settings_alarm_settings_title": "Ajustes de alarma",
M image/system_a/data/lang/Francais.json => image/system_a/data/lang/Francais.json +1 -0
@@ 654,6 654,7 @@
"app_bell_relaxation_looped": "en boucle",
"app_bell_relaxation_loop_description": "le morceau sera lu jusqu'à ce que vous l'éteigniez",
"app_bell_relaxation_error_message": "<text>Format de fichier non pris en<br></br>charge</text>",
+ "app_bell_relaxation_limit_error_message": "<text>Limite de fichiers excédée.<br />Risque de problèmes<br />d'affichage</text>",
"app_bell_settings_home_view": "Écran d'accueil",
"app_bell_settings_alarm_settings": "Alarme",
"app_bell_settings_alarm_settings_title": "Alarme",
M image/system_a/data/lang/Polski.json => image/system_a/data/lang/Polski.json +1 -0
@@ 706,6 706,7 @@
"app_bell_relaxation_looped": "zapętlony",
"app_bell_relaxation_loop_description": "utwór będzie odtwarzany do momentu wyłączenia go",
"app_bell_relaxation_error_message": "Nieobsługiwany format pliku",
+ "app_bell_relaxation_limit_error_message": "<text>Przekroczono limit plików.<br />Nie wszystkie pliki mogą być<br />wyświetlone poprawnie</text>",
"app_bell_settings_alarm_settings_prewake_up": "Wstępne budzenie",
"app_bell_settings_alarm_settings_prewake_up_chime_top_description": "Wstępne budzenie",
"app_bell_settings_alarm_settings_prewake_up_chime_bottom_description": "przed alarmem",
M module-apps/application-music-player/tests/MockSongsRepository.hpp => module-apps/application-music-player/tests/MockSongsRepository.hpp +5 -1
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once
@@ 21,6 21,10 @@ namespace testing::app::music
getMusicFilesList,
(std::uint32_t offset, std::uint32_t limit, const OnGetMusicFilesListCallback &callback),
(override));
+ MOCK_METHOD(void,
+ getMusicFilesListByPaths,
+ (std::uint32_t offset, std::uint32_t limit, const OnGetMusicFilesListCallback &callback),
+ (override));
MOCK_METHOD(void, initCache, (), (override));
MOCK_METHOD(std::size_t, getFileIndex, (const std::string &filePath), (const override));
MOCK_METHOD(std::string, getNextFilePath, (const std::string &filePath), (const override));
M module-apps/apps-common/models/SongsRepository.cpp => module-apps/apps-common/models/SongsRepository.cpp +42 -24
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "SongsRepository.hpp"
@@ 56,33 56,23 @@ namespace app::music
task->execute(application, this);
}
- void SongsRepository::getMusicFilesList(std::uint32_t offset,
- std::uint32_t limit,
+ void SongsRepository::getMusicFilesList(const std::uint32_t offset,
+ const std::uint32_t limit,
const OnGetMusicFilesListCallback &callback)
{
- auto query = std::make_unique<db::multimedia_files::query::GetLimitedByPaths>(pathPrefixes, offset, limit);
- auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::MultimediaFiles);
-
- task->setCallback([this, callback, offset](auto response) {
- auto result = dynamic_cast<db::multimedia_files::query::GetLimitedResult *>(response);
- musicFilesViewCache.records.clear();
-
- if (result == nullptr) {
- return false;
- }
+ musicFilesViewCache.records.clear();
+ getMusicFilesList(pathPrefixes, offset, limit, callback);
+ }
- for (auto &record : result->getResult()) {
- musicFilesViewCache.records.push_back(record);
- }
- musicFilesViewCache.recordsOffset = offset;
- musicFilesViewCache.recordsCount = result->getCount();
+ void SongsRepository::getMusicFilesListByPaths(const std::uint32_t offset,
+ const std::uint32_t limit,
+ const OnGetMusicFilesListCallback &callback)
+ {
- if (callback) {
- callback(musicFilesViewCache.records, musicFilesViewCache.recordsCount);
- }
- return true;
- });
- task->execute(application, this);
+ musicFilesViewCache.records.clear();
+ for (const auto &pathPrefix : pathPrefixes) {
+ getMusicFilesList({pathPrefix}, offset, limit, callback);
+ }
}
std::size_t SongsRepository::getCachedFileIndex(const std::string &filePath) const
@@ 270,4 260,32 @@ namespace app::music
return getCachedViewEntryByFilePath(filePath);
}
+ void SongsRepository::getMusicFilesList(const std::vector<std::string> &paths,
+ const std::uint32_t offset,
+ const std::uint32_t limit,
+ const OnGetMusicFilesListCallback &callback)
+ {
+
+ auto taskCallback = [this, callback, offset](auto response) {
+ auto result = dynamic_cast<db::multimedia_files::query::GetLimitedResult *>(response);
+ if (result == nullptr) {
+ return false;
+ }
+ for (auto &record : result->getResult()) {
+ musicFilesViewCache.records.push_back(record);
+ }
+ musicFilesViewCache.recordsOffset = offset;
+ musicFilesViewCache.recordsCount = result->getCount();
+
+ if (callback) {
+ callback(musicFilesViewCache.records, musicFilesViewCache.recordsCount);
+ }
+ return true;
+ };
+ auto query = std::make_unique<db::multimedia_files::query::GetLimitedByPaths>(
+ std::vector<std::string>{paths}, offset, limit);
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::MultimediaFiles);
+ task->setCallback(taskCallback);
+ task->execute(application, this);
+ }
} // namespace app::music
M module-apps/apps-common/models/SongsRepository.hpp => module-apps/apps-common/models/SongsRepository.hpp +20 -9
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once
@@ 50,12 50,15 @@ namespace app::music
virtual ~AbstractSongsRepository() noexcept = default;
- virtual void initCache() = 0;
- virtual void getMusicFilesList(std::uint32_t offset,
- std::uint32_t limit,
- const OnGetMusicFilesListCallback &callback) = 0;
- virtual std::string getNextFilePath(const std::string &filePath) const = 0;
- virtual std::string getPreviousFilePath(const std::string &filePath) const = 0;
+ virtual void initCache() = 0;
+ virtual void getMusicFilesList(uint32_t offset,
+ uint32_t limit,
+ const OnGetMusicFilesListCallback &callback) = 0;
+ virtual void getMusicFilesListByPaths(std::uint32_t offset,
+ std::uint32_t limit,
+ const OnGetMusicFilesListCallback &callback) = 0;
+ virtual std::string getNextFilePath(const std::string &filePath) const = 0;
+ virtual std::string getPreviousFilePath(const std::string &filePath) const = 0;
virtual std::optional<db::multimedia_files::MultimediaFilesRecord> getRecord(
const std::string &filePath) const = 0;
virtual void updateRepository(const std::string &filePath) = 0;
@@ 68,8 71,11 @@ namespace app::music
std::unique_ptr<AbstractTagsFetcher> tagsFetcher,
const std::vector<std::string> &pathPrefixes);
- void initCache();
- void getMusicFilesList(std::uint32_t offset, std::uint32_t limit, const OnGetMusicFilesListCallback &callback);
+ void initCache() override;
+ void getMusicFilesList(uint32_t offset, uint32_t limit, const OnGetMusicFilesListCallback &callback) override;
+ void getMusicFilesListByPaths(std::uint32_t offset,
+ std::uint32_t limit,
+ const OnGetMusicFilesListCallback &callback) override;
std::string getNextFilePath(const std::string &filePath) const override;
std::string getPreviousFilePath(const std::string &filePath) const override;
std::optional<db::multimedia_files::MultimediaFilesRecord> getRecord(
@@ 124,5 130,10 @@ namespace app::music
bool newFrontDataCallback(const std::vector<db::multimedia_files::MultimediaFilesRecord> &records,
unsigned int repoRecordsCount,
std::uint32_t offset);
+
+ void getMusicFilesList(const std::vector<std::string> &paths,
+ std::uint32_t offset,
+ std::uint32_t limit,
+ const OnGetMusicFilesListCallback &callback);
};
} // namespace app::music
M products/BellHybrid/apps/application-bell-relaxation/CMakeLists.txt => products/BellHybrid/apps/application-bell-relaxation/CMakeLists.txt +1 -0
@@ 37,6 37,7 @@ target_sources(application-bell-relaxation
data/RelaxationStyle.hpp
data/RelaxationAudioData.hpp
data/RelaxationSwitchData.hpp
+ data/RelaxationErrorData.hpp
widgets/RelaxationPlayer.hpp
windows/RelaxationMainWindow.hpp
presenter/RelaxationMainWindowPresenter.hpp
A products/BellHybrid/apps/application-bell-relaxation/data/RelaxationErrorData.hpp => products/BellHybrid/apps/application-bell-relaxation/data/RelaxationErrorData.hpp +30 -0
@@ 0,0 1,30 @@
+// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+#include <SwitchData.hpp>
+
+namespace gui
+{
+
+ enum class RelaxationErrorType
+ {
+ UnsupportedMediaType,
+ FilesLimitExceeded
+
+ };
+
+ class RelaxationErrorData : public SwitchData
+ {
+ RelaxationErrorType errorType;
+
+ public:
+ explicit RelaxationErrorData(const RelaxationErrorType &relaxationErrorType) : errorType{relaxationErrorType}
+ {}
+
+ [[nodiscard]] RelaxationErrorType getErrorType()
+ {
+ return errorType;
+ }
+ };
+} // namespace gui
M products/BellHybrid/apps/application-bell-relaxation/presenter/RelaxationMainWindowPresenter.cpp => products/BellHybrid/apps/application-bell-relaxation/presenter/RelaxationMainWindowPresenter.cpp +9 -6
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "RelaxationMainWindowPresenter.hpp"
@@ 6,8 6,8 @@
namespace
{
- constexpr auto soundsRepoOffset = 0;
- constexpr auto soundsRepoLimit = 100;
+ constexpr auto offset = 0;
+ constexpr auto filesLimitPerPath = 100;
} // namespace
namespace app::relaxation
@@ 19,12 19,15 @@ namespace app::relaxation
void RelaxationMainWindowPresenter::loadAudioRecords()
{
- soundsRepository->getMusicFilesList(
- soundsRepoOffset,
- soundsRepoLimit,
+ soundsRepository->getMusicFilesListByPaths(
+ offset,
+ filesLimitPerPath,
[this](const std::vector<db::multimedia_files::MultimediaFilesRecord> &records,
unsigned int repoRecordsCount) {
getView()->setSoundsList(records);
+ if (repoRecordsCount > filesLimitPerPath) {
+ getView()->handleError();
+ }
return true;
});
}
M products/BellHybrid/apps/application-bell-relaxation/presenter/RelaxationMainWindowPresenter.hpp => products/BellHybrid/apps/application-bell-relaxation/presenter/RelaxationMainWindowPresenter.hpp +2 -1
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once
@@ 22,6 22,7 @@ namespace app::relaxation
virtual ~View() = default;
virtual void setSoundsList(std::vector<db::multimedia_files::MultimediaFilesRecord> songs) = 0;
+ virtual void handleError() = 0;
};
class Presenter : public BasePresenter<RelaxationMainWindowContract::View>
M products/BellHybrid/apps/application-bell-relaxation/windows/RelaxationErrorWindow.cpp => products/BellHybrid/apps/application-bell-relaxation/windows/RelaxationErrorWindow.cpp +28 -11
@@ 2,13 2,18 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "RelaxationErrorWindow.hpp"
-#include <data/RelaxationSwitchData.hpp>
+#include <data/RelaxationErrorData.hpp>
#include <data/RelaxationStyle.hpp>
#include <ApplicationBellRelaxation.hpp>
-#include <gui/widgets/Icon.hpp>
#include <apps-common/widgets/BellBaseLayout.hpp>
+namespace
+{
+ constexpr auto unsupportedMediaMessage = "app_bell_relaxation_error_message";
+ constexpr auto exceededFilesLimitMessage = "app_bell_relaxation_limit_error_message";
+} // namespace
+
namespace gui
{
RelaxationErrorWindow::RelaxationErrorWindow(
@@ 30,14 35,8 @@ namespace gui
{
statusBar->setVisible(false);
- auto icon = new Icon(this,
- 0,
- 0,
- style::window_width,
- style::window_height,
- "big_information",
- utils::translate("app_bell_relaxation_error_message"),
- ImageTypeSpecifier::W_G);
+ icon = new Icon(
+ this, 0, 0, style::window_width, style::window_height, "big_information", "", ImageTypeSpecifier::W_G);
icon->image->setMargins({0, gui::relaxationStyle::error::imageMarginTop, 0, 0});
icon->text->setFont(style::window::font::verybiglight);
const auto textPadding = icon->text->getPadding();
@@ 45,7 44,6 @@ namespace gui
{textPadding.left, gui::relaxationStyle::error::textPaddingTop, textPadding.right, textPadding.bottom});
icon->text->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Center));
icon->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Top));
-
icon->resizeItems();
}
@@ 57,6 55,25 @@ namespace gui
};
}
+ void RelaxationErrorWindow::onBeforeShow(ShowMode mode, SwitchData *data)
+ {
+ if (data && typeid(*data) == typeid(RelaxationErrorData)) {
+ auto *errorData = static_cast<RelaxationErrorData *>(data);
+ switch (errorData->getErrorType()) {
+ case RelaxationErrorType::UnsupportedMediaType: {
+ icon->text->setRichText(utils::translate(unsupportedMediaMessage));
+ break;
+ }
+
+ case RelaxationErrorType::FilesLimitExceeded: {
+ icon->text->setRichText(utils::translate(exceededFilesLimitMessage));
+ break;
+ }
+ }
+ }
+ WindowWithTimer::onBeforeShow(mode, data);
+ }
+
bool RelaxationErrorWindow::onInput(const InputEvent &inputEvent)
{
if (inputEvent.isShortRelease(KeyCode::KEY_ENTER) || inputEvent.isShortRelease(KeyCode::KEY_RF)) {
M products/BellHybrid/apps/application-bell-relaxation/windows/RelaxationErrorWindow.hpp => products/BellHybrid/apps/application-bell-relaxation/windows/RelaxationErrorWindow.hpp +4 -0
@@ 5,6 5,7 @@
#include "presenter/RelaxationErrorPresenter.hpp"
#include <apps-common/popups/WindowWithTimer.hpp>
+#include <gui/widgets/Icon.hpp>
#include <memory>
namespace gui
@@ 19,10 20,13 @@ namespace gui
private:
std::unique_ptr<app::relaxation::RelaxationErrorContract::Presenter> presenter;
+ std::string errorText;
+ gui::Icon *icon = nullptr;
void buildInterface() override;
bool onInput(const gui::InputEvent &inputEvent) override;
void registerCallbacks();
void buildLayout();
+ void onBeforeShow(ShowMode mode, SwitchData *data) override;
};
} // namespace gui
M products/BellHybrid/apps/application-bell-relaxation/windows/RelaxationMainWindow.cpp => products/BellHybrid/apps/application-bell-relaxation/windows/RelaxationMainWindow.cpp +7 -1
@@ 3,6 3,7 @@
#include "RelaxationMainWindow.hpp"
#include <data/RelaxationAudioData.hpp>
+#include <data/RelaxationErrorData.hpp>
#include <ApplicationBellRelaxation.hpp>
#include <common/options/OptionBellMenu.hpp>
@@ 41,7 42,6 @@ namespace gui
for (const auto &sound : sounds) {
addRecord(sound);
}
-
addOptions(std::move(menuOptionList));
}
@@ 58,4 58,10 @@ namespace gui
application->switchWindow(gui::window::name::relaxationTimerSelect, std::move(switchData));
}
+ void RelaxationMainWindow::handleError()
+ {
+ auto switchData = std::make_unique<RelaxationErrorData>(RelaxationErrorType::FilesLimitExceeded);
+ application->switchWindow(gui::window::name::relaxationError, std::move(switchData));
+ }
+
} // namespace gui
M products/BellHybrid/apps/application-bell-relaxation/windows/RelaxationMainWindow.hpp => products/BellHybrid/apps/application-bell-relaxation/windows/RelaxationMainWindow.hpp +2 -2
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once
@@ 19,7 19,7 @@ namespace gui
std::unique_ptr<app::relaxation::RelaxationMainWindowContract::Presenter> presenter;
void buildInterface() override;
-
+ void handleError() override;
void setSoundsList(std::vector<db::multimedia_files::MultimediaFilesRecord> soundsTags);
void onActivated(const db::multimedia_files::MultimediaFilesRecord &selectedSound);
};
M products/BellHybrid/apps/application-bell-relaxation/windows/RelaxationRunningLoopWindow.cpp => products/BellHybrid/apps/application-bell-relaxation/windows/RelaxationRunningLoopWindow.cpp +3 -1
@@ 4,6 4,7 @@
#include "RelaxationRunningLoopWindow.hpp"
#include <data/RelaxationStyle.hpp>
#include <data/RelaxationSwitchData.hpp>
+#include <data/RelaxationErrorData.hpp>
#include <ApplicationBellRelaxation.hpp>
#include <apps-common/widgets/BellBaseLayout.hpp>
@@ 224,6 225,7 @@ namespace gui
}
void RelaxationRunningLoopWindow::handleError()
{
- application->switchWindow(gui::window::name::relaxationError);
+ auto switchData = std::make_unique<RelaxationErrorData>(RelaxationErrorType::UnsupportedMediaType);
+ application->switchWindow(gui::window::name::relaxationError, std::move(switchData));
}
} // namespace gui
M products/BellHybrid/apps/application-bell-relaxation/windows/RelaxationRunningProgressWindow.cpp => products/BellHybrid/apps/application-bell-relaxation/windows/RelaxationRunningProgressWindow.cpp +3 -1
@@ 4,6 4,7 @@
#include "RelaxationRunningProgressWindow.hpp"
#include <data/RelaxationStyle.hpp>
#include <data/RelaxationSwitchData.hpp>
+#include <data/RelaxationErrorData.hpp>
#include <ApplicationBellRelaxation.hpp>
#include <audio/AudioMessage.hpp>
@@ 174,7 175,8 @@ namespace gui
void RelaxationRunningProgressWindow::handleError()
{
- application->switchWindow(gui::window::name::relaxationError);
+ auto switchData = std::make_unique<RelaxationErrorData>(RelaxationErrorType::UnsupportedMediaType);
+ application->switchWindow(gui::window::name::relaxationError, std::move(switchData));
}
} // namespace gui