M module-apps/application-music-player/ApplicationMusicPlayer.cpp => module-apps/application-music-player/ApplicationMusicPlayer.cpp +9 -5
@@ 27,7 27,7 @@ namespace app
class MusicPlayerPriv
{
public:
- std::shared_ptr<app::music_player::SongsModelInterface> songsModel;
+ std::shared_ptr<app::music::SongsModelInterface> songsModel;
std::shared_ptr<app::music_player::SongsContract::Presenter> songsPresenter;
};
} // namespace music_player::internal
@@ 46,15 46,19 @@ namespace app
bus.channels.push_back(sys::BusChannel::ServiceAudioNotifications);
- auto tagsFetcher = std::make_unique<app::music_player::ServiceAudioTagsFetcher>(this);
- auto songsRepository = std::make_unique<app::music_player::SongsRepository>(this, std::move(tagsFetcher));
- priv->songsModel = std::make_unique<app::music_player::SongsModel>(this, std::move(songsRepository));
+ auto tagsFetcher = std::make_unique<app::music::ServiceAudioTagsFetcher>(this);
+
+ const auto musicPlayerFilesPath = purefs::createPath(purefs::dir::getUserDiskPath(), "music").string();
+ auto songsRepository =
+ std::make_unique<app::music::SongsRepository>(this, std::move(tagsFetcher), musicPlayerFilesPath);
+
+ priv->songsModel = std::make_unique<app::music::SongsModel>(this, std::move(songsRepository));
auto audioOperations = std::make_unique<app::AsyncAudioOperations>(this);
priv->songsPresenter =
std::make_unique<app::music_player::SongsPresenter>(this, priv->songsModel, std::move(audioOperations));
// callback used when playing state is changed
- using SongState = app::music_player::SongState;
+ using SongState = app::music::SongState;
std::function<void(SongState)> autolockCallback = [this](SongState isPlaying) {
if (isPlaying == SongState::Playing) {
LOG_DEBUG("Preventing autolock while playing track.");
M module-apps/application-music-player/CMakeLists.txt => module-apps/application-music-player/CMakeLists.txt +0 -5
@@ 14,9 14,7 @@ target_sources(application-music-player
PRIVATE
ApplicationMusicPlayer.cpp
AudioNotificationsHandler.cpp
- models/SongContext.cpp
models/SongsModel.cpp
- models/SongsRepository.cpp
presenters/SongsPresenter.cpp
widgets/SongItem.cpp
windows/MusicPlayerMainWindow.cpp
@@ 24,10 22,7 @@ target_sources(application-music-player
PRIVATE
AudioNotificationsHandler.hpp
data/MusicPlayerStyle.hpp
- models/SongContext.hpp
models/SongsModel.hpp
- models/SongsRepository.hpp
- models/SongsModelInterface.hpp
presenters/SongsPresenter.hpp
widgets/SongItem.hpp
windows/MusicPlayerMainWindow.cpp
M module-apps/application-music-player/include/application-music-player/ApplicationMusicPlayer.hpp => module-apps/application-music-player/include/application-music-player/ApplicationMusicPlayer.hpp +2 -1
@@ 5,6 5,7 @@
#include <Application.hpp>
#include <Audio/decoder/Decoder.hpp>
+#include <purefs/filesystem_paths.hpp>
#include <atomic>
namespace gui
@@ 14,7 15,7 @@ namespace gui
namespace window
{
inline constexpr auto track_info_window = "Track Info";
- inline constexpr auto all_songs_window = "All Songs";
+ inline constexpr auto all_songs_window = "All Songs";
}; // namespace window
}; // namespace name
}; // namespace gui
M module-apps/application-music-player/models/SongsModel.cpp => module-apps/application-music-player/models/SongsModel.cpp +7 -7
@@ 9,7 9,7 @@
#include <service-audio/AudioServiceAPI.hpp>
#include <time/time_conversion.hpp>
-namespace app::music_player
+namespace app::music
{
SongsListItemProvider::SongsListItemProvider(ApplicationCommon *app) : DatabaseModel(app)
@@ 90,10 90,10 @@ namespace app::music_player
OnSetNavBarTemporaryCallback navBarTemporaryMode,
OnRestoreNavBarTemporaryCallback navBarRestoreFromTemporaryMode)
{
- this->shortReleaseCallback = shortReleaseCallback;
- this->longPressCallback = longPressCallback;
- this->navBarTemporaryMode = navBarTemporaryMode;
- this->navBarRestoreFromTemporaryMode = navBarRestoreFromTemporaryMode;
+ this->shortReleaseCallback = shortReleaseCallback;
+ this->longPressCallback = longPressCallback;
+ this->navBarTemporaryMode = navBarTemporaryMode;
+ this->navBarRestoreFromTemporaryMode = navBarRestoreFromTemporaryMode;
songsRepository->initCache();
}
@@ 135,7 135,7 @@ namespace app::music_player
void SongsModel::setCurrentSongContext(SongContext context)
{
- songContext = context;
+ songContext = context;
activatedRecord = songsRepository->getRecord(context.filePath);
}
@@ 175,4 175,4 @@ namespace app::music_player
songsRepository->updateRepository(filePath);
}
-} // namespace app::music_player
+} // namespace app::music
M module-apps/application-music-player/models/SongsModel.hpp => module-apps/application-music-player/models/SongsModel.hpp +5 -5
@@ 5,13 5,13 @@
#include "module-apps/application-music-player/data/MusicPlayerStyle.hpp"
-#include "SongContext.hpp"
-#include "SongsRepository.hpp"
-#include "SongsModelInterface.hpp"
+#include <apps-common/models/SongsRepository.hpp>
+#include <apps-common/models/SongsModelInterface.hpp>
+#include <apps-common/models/SongContext.hpp>
#include <Audio/decoder/Decoder.hpp>
-namespace app::music_player
+namespace app::music
{
class SongsModel : public SongsModelInterface
{
@@ 61,4 61,4 @@ namespace app::music_player
std::shared_ptr<AbstractSongsRepository> songsRepository;
};
-} // namespace app::music_player
+} // namespace app::music
M module-apps/application-music-player/presenters/SongsPresenter.cpp => module-apps/application-music-player/presenters/SongsPresenter.cpp +16 -15
@@ 10,7 10,7 @@
namespace app::music_player
{
SongsPresenter::SongsPresenter(app::ApplicationCommon *app,
- std::shared_ptr<app::music_player::SongsModelInterface> songsModelInterface,
+ std::shared_ptr<app::music::SongsModelInterface> songsModelInterface,
std::unique_ptr<AbstractAudioOperations> &&audioOperations)
: songsModelInterface{std::move(songsModelInterface)}, audioOperations{std::move(audioOperations)}
{
@@ 19,7 19,7 @@ namespace app::music_player
app, "MP Song Progres", tick, [this]([[maybe_unused]] sys::Timer &) { handleTrackProgressTick(); });
}
- std::shared_ptr<app::music_player::SongsModelInterface> SongsPresenter::getMusicPlayerModelInterface() const
+ std::shared_ptr<app::music::SongsModelInterface> SongsPresenter::getMusicPlayerModelInterface() const
{
return songsModelInterface;
}
@@ 46,11 46,12 @@ namespace app::music_player
return;
}
- SongContext songContext{SongState::Playing, token, filePath, SongContext::StartPos};
+ app::music::SongContext songContext{
+ app::music::SongState::Playing, token, filePath, app::music::SongContext::StartPos};
songsModelInterface->setCurrentSongContext(songContext);
if (changePlayingStateCallback != nullptr) {
- changePlayingStateCallback(SongState::Playing);
+ changePlayingStateCallback(app::music::SongState::Playing);
}
updateViewSongState();
songsModelInterface->updateRepository(filePath);
@@ 76,9 77,9 @@ namespace app::music_player
LOG_ERROR("Pause audio operation failed, wrong token");
return;
}
- songsModelInterface->setCurrentSongState(SongState::NotPlaying);
+ songsModelInterface->setCurrentSongState(app::music::SongState::NotPlaying);
if (changePlayingStateCallback != nullptr) {
- changePlayingStateCallback(SongState::NotPlaying);
+ changePlayingStateCallback(app::music::SongState::NotPlaying);
}
updateViewSongState();
songProgressTimer.stop();
@@ 106,9 107,9 @@ namespace app::music_player
LOG_ERROR("Resume audio operation failed, wrong token");
return;
}
- songsModelInterface->setCurrentSongState(SongState::Playing);
+ songsModelInterface->setCurrentSongState(app::music::SongState::Playing);
if (changePlayingStateCallback != nullptr) {
- changePlayingStateCallback(SongState::Playing);
+ changePlayingStateCallback(app::music::SongState::Playing);
}
updateViewSongState();
songProgressTimestamp = std::chrono::system_clock::now();
@@ 161,7 162,7 @@ namespace app::music_player
updateViewSongState();
}
- void SongsPresenter::setPlayingStateCallback(std::function<void(SongState)> cb)
+ void SongsPresenter::setPlayingStateCallback(std::function<void(app::music::SongState)> cb)
{
changePlayingStateCallback = std::move(cb);
}
@@ 171,7 172,7 @@ namespace app::music_player
if (token == songsModelInterface->getCurrentFileToken()) {
songsModelInterface->clearCurrentSongContext();
if (changePlayingStateCallback != nullptr) {
- changePlayingStateCallback(SongState::NotPlaying);
+ changePlayingStateCallback(app::music::SongState::NotPlaying);
}
if (!waitingToPlay) {
updateViewSongState();
@@ 189,7 190,7 @@ namespace app::music_player
if (token == currentSongContext.currentFileToken) {
songsModelInterface->clearCurrentSongContext();
if (changePlayingStateCallback != nullptr) {
- changePlayingStateCallback(SongState::NotPlaying);
+ changePlayingStateCallback(app::music::SongState::NotPlaying);
}
auto nextSongToPlay = songsModelInterface->getNextFilePath(currentSongContext.filePath);
if (!nextSongToPlay.empty()) {
@@ 207,9 208,9 @@ namespace app::music_player
bool SongsPresenter::handleAudioPausedNotification(audio::Token token)
{
if (token == songsModelInterface->getCurrentFileToken()) {
- songsModelInterface->setCurrentSongState(SongState::NotPlaying);
+ songsModelInterface->setCurrentSongState(app::music::SongState::NotPlaying);
if (changePlayingStateCallback != nullptr) {
- changePlayingStateCallback(SongState::NotPlaying);
+ changePlayingStateCallback(app::music::SongState::NotPlaying);
}
updateViewSongState();
return true;
@@ 220,9 221,9 @@ namespace app::music_player
bool SongsPresenter::handleAudioResumedNotification(audio::Token token)
{
if (token == songsModelInterface->getCurrentFileToken()) {
- songsModelInterface->setCurrentSongState(SongState::Playing);
+ songsModelInterface->setCurrentSongState(app::music::SongState::Playing);
if (changePlayingStateCallback != nullptr) {
- changePlayingStateCallback(SongState::Playing);
+ changePlayingStateCallback(app::music::SongState::Playing);
}
updateViewSongState();
return true;
M module-apps/application-music-player/presenters/SongsPresenter.hpp => module-apps/application-music-player/presenters/SongsPresenter.hpp +15 -15
@@ 6,7 6,7 @@
#include <apps-common/AudioOperations.hpp>
#include <apps-common/BasePresenter.hpp>
-#include <module-apps/application-music-player/models/SongsModelInterface.hpp>
+#include <apps-common/models/SongsModelInterface.hpp>
namespace app::music_player
{
@@ 23,24 23,24 @@ namespace app::music_player
Stopped
};
- virtual ~View() noexcept = default;
+ virtual ~View() noexcept = default;
virtual void updateSongsState(std::optional<db::multimedia_files::MultimediaFilesRecord> record,
- RecordState state) = 0;
- virtual void updateSongProgress(float progress) = 0;
- virtual void refreshWindow() = 0;
- virtual void setNavBarTemporaryMode(const std::string &text) = 0;
- virtual void restoreFromNavBarTemporaryMode() = 0;
+ RecordState state) = 0;
+ virtual void updateSongProgress(float progress) = 0;
+ virtual void refreshWindow() = 0;
+ virtual void setNavBarTemporaryMode(const std::string &text) = 0;
+ virtual void restoreFromNavBarTemporaryMode() = 0;
};
class Presenter : public BasePresenter<SongsContract::View>
{
public:
- using OnPlayingStateChangeCallback = std::function<void(SongState)>;
+ using OnPlayingStateChangeCallback = std::function<void(app::music::SongState)>;
virtual ~Presenter() noexcept = default;
- virtual std::shared_ptr<SongsModelInterface> getMusicPlayerModelInterface() const = 0;
- virtual void createData() = 0;
+ virtual std::shared_ptr<app::music::SongsModelInterface> getMusicPlayerModelInterface() const = 0;
+ virtual void createData() = 0;
virtual bool play(const std::string &filePath) = 0;
virtual bool pause() = 0;
@@ 63,10 63,10 @@ namespace app::music_player
{
public:
explicit SongsPresenter(app::ApplicationCommon *app,
- std::shared_ptr<SongsModelInterface> songsListItemProvider,
+ std::shared_ptr<app::music::SongsModelInterface> songsListItemProvider,
std::unique_ptr<AbstractAudioOperations> &&audioOperations);
- std::shared_ptr<SongsModelInterface> getMusicPlayerModelInterface() const override;
+ std::shared_ptr<app::music::SongsModelInterface> getMusicPlayerModelInterface() const override;
void createData() override;
@@ 78,7 78,7 @@ namespace app::music_player
bool playPrevious() override;
void songsStateRequest() override;
- void setPlayingStateCallback(std::function<void(SongState)> cb) override;
+ void setPlayingStateCallback(std::function<void(app::music::SongState)> cb) override;
bool handleAudioStopNotifiaction(audio::Token token) override;
bool handleAudioEofNotification(audio::Token token) override;
bool handleAudioPausedNotification(audio::Token token) override;
@@ 100,9 100,9 @@ namespace app::music_player
bool requestAudioOperation(const std::string &filePath = "");
void setViewNavBarTemporaryMode(const std::string &text);
void restoreViewNavBarFromTemporaryMode();
- std::shared_ptr<SongsModelInterface> songsModelInterface;
+ std::shared_ptr<app::music::SongsModelInterface> songsModelInterface;
std::unique_ptr<AbstractAudioOperations> audioOperations;
- std::function<void(SongState)> changePlayingStateCallback = nullptr;
+ std::function<void(app::music::SongState)> changePlayingStateCallback = nullptr;
sys::TimerHandle songProgressTimer;
std::chrono::time_point<std::chrono::system_clock> songProgressTimestamp;
M module-apps/application-music-player/tests/MockSongsRepository.hpp => module-apps/application-music-player/tests/MockSongsRepository.hpp +3 -3
@@ 12,9 12,9 @@
#include <string>
#include <vector>
-namespace testing::app::music_player
+namespace testing::app::music
{
- class MockSongsRepository : public ::app::music_player::AbstractSongsRepository
+ class MockSongsRepository : public ::app::music::AbstractSongsRepository
{
public:
MOCK_METHOD(void,
@@ 31,4 31,4 @@ namespace testing::app::music_player
(const override));
MOCK_METHOD(void, updateRepository, (const std::string &filePath), (override));
};
-}; // namespace testing::app::music_player
+}; // namespace testing::app::music
M module-apps/application-music-player/tests/MockTagsFetcher.hpp => module-apps/application-music-player/tests/MockTagsFetcher.hpp +3 -3
@@ 10,11 10,11 @@
#include <optional>
-namespace testing::app::music_player
+namespace testing::app::music
{
- class MockTagsFetcher : public ::app::music_player::AbstractTagsFetcher
+ class MockTagsFetcher : public ::app::music::AbstractTagsFetcher
{
public:
MOCK_METHOD(std::optional<tags::fetcher::Tags>, getFileTags, (const std::string &filePath), (const override));
};
-}; // namespace testing::app::music_player
+}; // namespace testing::app::music
M module-apps/application-music-player/tests/unittest_songsmodel.cpp => module-apps/application-music-player/tests/unittest_songsmodel.cpp +3 -3
@@ 10,9 10,9 @@
#include <memory>
#include <optional>
-using ::app::music_player::SongsModel;
+using ::app::music::SongsModel;
using ::testing::Return;
-using ::testing::app::music_player::MockSongsRepository;
+using ::testing::app::music::MockSongsRepository;
TEST(SongsModel, Init)
{
@@ 31,5 31,5 @@ TEST(SongsModel, EmptyContext)
EXPECT_EQ(ctx.currentFileToken, std::nullopt);
EXPECT_TRUE(ctx.filePath.empty());
- EXPECT_EQ(ctx.currentSongState, app::music_player::SongState::NotPlaying);
+ EXPECT_EQ(ctx.currentSongState, app::music::SongState::NotPlaying);
}
M module-apps/apps-common/CMakeLists.txt => module-apps/apps-common/CMakeLists.txt +6 -0
@@ 15,6 15,8 @@ target_sources(apps-common
StatusBarManager.cpp
WindowsFactory.cpp
audio/SoundsPlayer.cpp
+ models/SongContext.cpp
+ models/SongsRepository.cpp
notifications/NotificationData.cpp
notifications/NotificationListItem.cpp
notifications/NotificationProvider.cpp
@@ 62,6 64,10 @@ target_sources(apps-common
actions/AlarmRingingData.hpp
actions/AlarmTriggeredAction.hpp
+ models/SongContext.hpp
+ models/SongsRepository.hpp
+ models/SongsModelInterface.hpp
+
widgets/spinners/GenericSpinner.hpp
widgets/spinners/SpinnerPolicies.hpp
widgets/spinners/Spinners.hpp
R module-apps/application-music-player/models/SongContext.cpp => module-apps/apps-common/models/SongContext.cpp +2 -2
@@ 4,7 4,7 @@
#include "SongContext.hpp"
#include <optional>
-namespace app::music_player
+namespace app::music
{
void SongContext::clear()
{
@@ 28,4 28,4 @@ namespace app::music_player
{
return isValid() && currentSongState == SongState::NotPlaying;
}
-} // namespace app::music_player
+} // namespace app::music
R module-apps/application-music-player/models/SongContext.hpp => module-apps/apps-common/models/SongContext.hpp +3 -3
@@ 4,7 4,7 @@
#include <Audio/decoder/Decoder.hpp>
-namespace app::music_player
+namespace app::music
{
enum class SongState
@@ 16,7 16,7 @@ namespace app::music_player
struct SongContext
{
static constexpr uint32_t StartPos = 0;
- SongState currentSongState = SongState::NotPlaying;
+ SongState currentSongState = SongState::NotPlaying;
std::optional<audio::Token> currentFileToken;
std::string filePath;
uint32_t currentPos = StartPos;
@@ 28,4 28,4 @@ namespace app::music_player
bool isValid() const;
};
-} // namespace app::music_player
+} // namespace app::music
R module-apps/application-music-player/models/SongsModelInterface.hpp => module-apps/apps-common/models/SongsModelInterface.hpp +17 -18
@@ 5,30 5,29 @@
#include "SongContext.hpp"
#include <string>
-#include <widgets/SongItem.hpp>
#include <ListItemProvider.hpp>
#include <apps-common/ApplicationCommon.hpp>
#include <apps-common/DatabaseModel.hpp>
#include <module-db/Interface/MultimediaFilesRecord.hpp>
-namespace app::music_player
+namespace app::music
{
class SongsListItemProvider : public app::DatabaseModel<db::multimedia_files::MultimediaFilesRecord>,
public gui::ListItemProvider
{
public:
- using OnShortReleaseCallback = std::function<bool(const std::string &fileName)>;
- using OnLongPressCallback = std::function<void()>;
- using OnSetNavBarTemporaryCallback = std::function<void(const UTF8 &)>;
- using OnRestoreNavBarTemporaryCallback = std::function<void()>;
+ using OnShortReleaseCallback = std::function<bool(const std::string &fileName)>;
+ using OnLongPressCallback = std::function<void()>;
+ using OnSetNavBarTemporaryCallback = std::function<void(const UTF8 &)>;
+ using OnRestoreNavBarTemporaryCallback = std::function<void()>;
explicit SongsListItemProvider(app::ApplicationCommon *app);
virtual ~SongsListItemProvider() noexcept = default;
virtual void createData(OnShortReleaseCallback shortReleaseCallback,
OnLongPressCallback longPressCallback,
OnSetNavBarTemporaryCallback navBarTemporaryMode,
- OnRestoreNavBarTemporaryCallback navBarRestoreFromTemporaryMode) = 0;
- virtual void clearData() = 0;
+ OnRestoreNavBarTemporaryCallback navBarRestoreFromTemporaryMode) = 0;
+ virtual void clearData() = 0;
};
class SongsModelInterface : public SongsListItemProvider
@@ 37,15 36,15 @@ namespace app::music_player
explicit SongsModelInterface(app::ApplicationCommon *app);
virtual ~SongsModelInterface() noexcept = default;
- virtual bool isSongPlaying() const noexcept = 0;
- virtual void setCurrentSongState(SongState songState) noexcept = 0;
- virtual std::optional<audio::Token> getCurrentFileToken() const noexcept = 0;
+ virtual bool isSongPlaying() const noexcept = 0;
+ virtual void setCurrentSongState(SongState songState) noexcept = 0;
+ virtual std::optional<audio::Token> getCurrentFileToken() const noexcept = 0;
virtual std::optional<db::multimedia_files::MultimediaFilesRecord> getActivatedRecord() const noexcept = 0;
- virtual SongContext getCurrentSongContext() const noexcept = 0;
- virtual void setCurrentSongContext(SongContext context) = 0;
- virtual void clearCurrentSongContext() = 0;
- virtual std::string getNextFilePath(const std::string &filePath) const = 0;
- virtual std::string getPreviousFilePath(const std::string &filePath) const = 0;
- virtual void updateRepository(const std::string &filePath) = 0;
+ virtual SongContext getCurrentSongContext() const noexcept = 0;
+ virtual void setCurrentSongContext(SongContext context) = 0;
+ virtual void clearCurrentSongContext() = 0;
+ virtual std::string getNextFilePath(const std::string &filePath) const = 0;
+ virtual std::string getPreviousFilePath(const std::string &filePath) const = 0;
+ virtual void updateRepository(const std::string &filePath) = 0;
};
-} // namespace app::music_player
+} // namespace app::music
R module-apps/application-music-player/models/SongsRepository.cpp => module-apps/apps-common/models/SongsRepository.cpp +9 -5
@@ 10,6 10,7 @@
#include <time/ScopedTime.hpp>
#include <service-audio/AudioMessage.hpp>
#include <module-db/queries/multimedia_files/QueryMultimediaFilesGetLimited.hpp>
+#include <module-db/queries/multimedia_files/QueryMultimediaFilesGet.hpp>
#include <filesystem>
@@ 19,7 20,7 @@ namespace constants
inline constexpr auto cacheThreshold{10};
} // namespace constants
-namespace app::music_player
+namespace app::music
{
ServiceAudioTagsFetcher::ServiceAudioTagsFetcher(ApplicationCommon *application) : application(application)
{}
@@ 29,8 30,11 @@ namespace app::music_player
return tags::fetcher::fetchTags(filePath);
}
- SongsRepository::SongsRepository(ApplicationCommon *application, std::unique_ptr<AbstractTagsFetcher> tagsFetcher)
- : app::AsyncCallbackReceiver{application}, application{application}, tagsFetcher(std::move(tagsFetcher))
+ SongsRepository::SongsRepository(ApplicationCommon *application,
+ std::unique_ptr<AbstractTagsFetcher> tagsFetcher,
+ std::string pathPrefix)
+ : app::AsyncCallbackReceiver{application}, application{application},
+ tagsFetcher(std::move(tagsFetcher)), pathPrefix{pathPrefix}
{}
void SongsRepository::initCache()
@@ 55,7 59,7 @@ namespace app::music_player
std::uint32_t limit,
const OnGetMusicFilesListCallback &callback)
{
- auto query = std::make_unique<db::multimedia_files::query::GetLimited>(offset, limit);
+ auto query = std::make_unique<db::multimedia_files::query::GetLimitedByPath>(pathPrefix, offset, limit);
auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::MultimediaFiles);
task->setCallback([this, callback, offset](auto response) {
@@ 252,4 256,4 @@ namespace app::music_player
return musicFilesModelCache.records[index];
}
-} // namespace app::music_player
+} // namespace app::music
R module-apps/application-music-player/models/SongsRepository.hpp => module-apps/apps-common/models/SongsRepository.hpp +12 -10
@@ 14,7 14,7 @@
#include <cstddef>
-namespace app::music_player
+namespace app::music
{
struct FilesCache
{
@@ 54,22 54,22 @@ namespace app::music_player
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 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;
+ const std::string &filePath) const = 0;
+ virtual void updateRepository(const std::string &filePath) = 0;
};
class SongsRepository : public AbstractSongsRepository, public app::AsyncCallbackReceiver
{
public:
- explicit SongsRepository(ApplicationCommon *application, std::unique_ptr<AbstractTagsFetcher> tagsFetcher);
+ explicit SongsRepository(ApplicationCommon *application,
+ std::unique_ptr<AbstractTagsFetcher> tagsFetcher,
+ std::string pathPrefix);
void initCache();
- void getMusicFilesList(std::uint32_t offset,
- std::uint32_t limit,
- const OnGetMusicFilesListCallback &callback) override;
+ void getMusicFilesList(std::uint32_t offset, std::uint32_t limit, const OnGetMusicFilesListCallback &callback);
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(
@@ 88,6 88,8 @@ namespace app::music_player
std::unique_ptr<AbstractTagsFetcher> tagsFetcher;
+ std::string pathPrefix;
+
/// collection of music files displayed in the list view
FilesCache musicFilesViewCache;
/// collection of music files currently playing
@@ 119,4 121,4 @@ namespace app::music_player
unsigned int repoRecordsCount,
std::uint32_t offset);
};
-} // namespace app::music_player
+} // namespace app::music
M module-db/Interface/MultimediaFilesRecord.cpp => module-db/Interface/MultimediaFilesRecord.cpp +13 -1
@@ 36,6 36,9 @@ namespace db::multimedia_files
if (typeid(*query) == typeid(query::GetLimited)) {
return runQueryImplGetLimited(std::static_pointer_cast<query::GetLimited>(query));
}
+ if (typeid(*query) == typeid(query::GetLimitedByPath)) {
+ return runQueryImplGetLimited(std::static_pointer_cast<query::GetLimitedByPath>(query));
+ }
if (typeid(*query) == typeid(query::Remove)) {
return runQueryImplRemove(std::static_pointer_cast<query::Remove>(query));
}
@@ 78,7 81,6 @@ namespace db::multimedia_files
if (typeid(*query) == typeid(query::GetByPath)) {
return runQueryImplGetByPath(std::static_pointer_cast<query::GetByPath>(query));
}
-
return nullptr;
}
@@ 249,6 251,16 @@ namespace db::multimedia_files
return response;
}
+ std::unique_ptr<db::multimedia_files::query::GetLimitedResult> MultimediaFilesRecordInterface::
+ runQueryImplGetLimited(const std::shared_ptr<db::multimedia_files::query::GetLimitedByPath> &query)
+ {
+ const auto records = database->files.getLimitOffsetByPath(query->path, query->offset, query->limit);
+ auto response = std::make_unique<query::GetLimitedResult>(records, database->files.count());
+ response->setRequestQuery(query);
+
+ return response;
+ }
+
std::unique_ptr<db::multimedia_files::query::GetCountResult> MultimediaFilesRecordInterface::runQueryImplGetCount(
const std::shared_ptr<db::multimedia_files::query::GetCountForAlbum> &query)
{
M module-db/Interface/MultimediaFilesRecord.hpp => module-db/Interface/MultimediaFilesRecord.hpp +3 -0
@@ 34,6 34,7 @@ namespace db::multimedia_files::query
class GetCountForArtist;
class GetCountResult;
class GetLimited;
+ class GetLimitedByPath;
class GetLimitedForAlbum;
class GetLimitedForArtist;
class GetLimitedResult;
@@ 70,6 71,8 @@ namespace db::multimedia_files
const std::shared_ptr<db::multimedia_files::query::Get> &query);
std::unique_ptr<db::multimedia_files::query::GetLimitedResult> runQueryImplGetLimited(
const std::shared_ptr<db::multimedia_files::query::GetLimited> &query);
+ std::unique_ptr<db::multimedia_files::query::GetLimitedResult> runQueryImplGetLimited(
+ const std::shared_ptr<db::multimedia_files::query::GetLimitedByPath> &query);
std::unique_ptr<db::multimedia_files::query::RemoveResult> runQueryImplRemove(
const std::shared_ptr<db::multimedia_files::query::Remove> &query);
std::unique_ptr<db::multimedia_files::query::RemoveResult> runQueryImplRemoveAll(
M module-db/Tables/MultimediaFilesTable.cpp => module-db/Tables/MultimediaFilesTable.cpp +9 -0
@@ 330,4 330,13 @@ namespace db::multimedia_files
return (*queryRet)[0].getUInt32();
}
+
+ auto MultimediaFilesTable::getLimitOffsetByPath(const std::string &path, uint32_t offset, uint32_t limit)
+ -> std::vector<TableRow>
+ {
+ std::string query = "SELECT * FROM files WHERE path LIKE '" + path + "%%' ORDER BY title ASC LIMIT " +
+ std::to_string(limit) + " OFFSET " + std::to_string(offset) + ";";
+ std::unique_ptr<QueryResult> retQuery = db->query(query.c_str());
+ return retQueryUnpack(std::move(retQuery));
+ }
} // namespace db::multimedia_files
M module-db/Tables/MultimediaFilesTable.hpp => module-db/Tables/MultimediaFilesTable.hpp +1 -0
@@ 101,6 101,7 @@ namespace db::multimedia_files
auto getLimitOffset(const Album &album, uint32_t offset, uint32_t limit) -> std::vector<TableRow>;
auto count(const Album &album) -> uint32_t;
+ auto getLimitOffsetByPath(const std::string &path, uint32_t offset, uint32_t limit) -> std::vector<TableRow>;
TableRow getByPath(std::string path);
/// @note entry.ID is skipped
M module-db/queries/multimedia_files/QueryMultimediaFilesGetLimited.cpp => module-db/queries/multimedia_files/QueryMultimediaFilesGetLimited.cpp +9 -0
@@ 105,4 105,13 @@ namespace db::multimedia_files::query
{
return std::string{"GetAlbumsLimitedResult"};
}
+
+ GetLimitedByPath::GetLimitedByPath(std::string path, uint32_t offset, uint32_t limit)
+ : Query(Query::Type::Read), path{path}, offset(offset), limit(limit)
+ {}
+
+ auto GetLimitedByPath::debugInfo() const -> std::string
+ {
+ return std::string{"GetLimitedByPath"};
+ }
} // namespace db::multimedia_files::query
M module-db/queries/multimedia_files/QueryMultimediaFilesGetLimited.hpp => module-db/queries/multimedia_files/QueryMultimediaFilesGetLimited.hpp +11 -0
@@ 100,4 100,15 @@ namespace db::multimedia_files::query
[[nodiscard]] auto getCount() const noexcept -> unsigned int;
[[nodiscard]] auto debugInfo() const -> std::string override;
};
+
+ class GetLimitedByPath : public Query
+ {
+ public:
+ GetLimitedByPath(std::string path, uint32_t offset, uint32_t limit);
+ [[nodiscard]] auto debugInfo() const -> std::string override;
+
+ const std::string path;
+ const uint32_t offset = 0;
+ const uint32_t limit = 0;
+ };
} // namespace db::multimedia_files::query
M module-db/tests/MultimediaFilesTable_tests.cpp => module-db/tests/MultimediaFilesTable_tests.cpp +24 -0
@@ 345,6 345,15 @@ TEST_CASE("Multimedia DB tests")
return record;
};
+ auto getLimitedByPathQuery = [&](const std::string &pathPrefix, const uint32_t offset, const uint32_t limit) {
+ auto query = std::make_shared<db::multimedia_files::query::GetLimitedByPath>(pathPrefix, offset, limit);
+ auto ret = multimediaFilesRecordInterface.runQuery(query);
+ auto result = dynamic_cast<db::multimedia_files::query::GetLimitedResult *>(ret.get());
+ REQUIRE(result != nullptr);
+ auto record = result->getResult();
+ return record;
+ };
+
auto updateQuery = [&](const MultimediaFilesRecord &record) {
const auto query = std::make_shared<db::multimedia_files::query::Edit>(record);
const auto ret = multimediaFilesRecordInterface.runQuery(query);
@@ 564,6 573,21 @@ TEST_CASE("Multimedia DB tests")
REQUIRE(getLimitedQuery(size - 3, size).size() == 3);
}
+ SECTION("getLimitOffsetByPath")
+ {
+ auto rootPrefix = "user/";
+ auto musicPrefix = "user/music/";
+ auto falsePrefix1 = "user/music1/";
+ auto flasePrefix2 = "user/music2";
+ auto falsePrefix3 = "abc/";
+ auto size = records.size();
+ REQUIRE(getLimitedByPathQuery(rootPrefix, 0, size).size() == size);
+ REQUIRE(getLimitedByPathQuery(musicPrefix, 0, size).size() == (size - 3));
+ REQUIRE(getLimitedByPathQuery(falsePrefix1, 0, size).size() == 0);
+ REQUIRE(getLimitedByPathQuery(flasePrefix2, 0, size).size() == 0);
+ REQUIRE(getLimitedByPathQuery(falsePrefix3, 0, size).size() == 0);
+ }
+
SECTION("Artists")
{
REQUIRE(getCountArtistsQuery() == artists.size());
M module-services/CMakeLists.txt => module-services/CMakeLists.txt +1 -0
@@ 14,6 14,7 @@ add_subdirectory( service-db )
add_subdirectory( service-desktop )
add_subdirectory( service-eink )
add_subdirectory( service-evtmgr )
+add_subdirectory( service-fileindexer )
add_subdirectory( service-gui )
add_subdirectory( service-time )
R products/PurePhone/services/service-fileindexer/CMakeLists.txt => module-services/service-fileindexer/CMakeLists.txt +0 -0
R products/PurePhone/services/service-fileindexer/Common.hpp => module-services/service-fileindexer/Common.hpp +0 -0
R products/PurePhone/services/service-fileindexer/InotifyHandler.cpp => module-services/service-fileindexer/InotifyHandler.cpp +0 -0
R products/PurePhone/services/service-fileindexer/ServiceFileIndexer.cpp => module-services/service-fileindexer/ServiceFileIndexer.cpp +3 -2
@@ 19,9 19,10 @@ namespace
namespace service
{
- ServiceFileIndexer::ServiceFileIndexer(const std::string_view name) : sys::Service(std::string(name))
+ ServiceFileIndexer::ServiceFileIndexer(const std::vector<std::string> &paths)
+ : sys::Service{service::name::file_indexer}, mStartupIndexer{paths}
{
- LOG_DEBUG("[%s] Initializing", std::string(name).c_str());
+ LOG_DEBUG("[%s] Initializing", service::name::file_indexer);
}
sys::MessagePointer ServiceFileIndexer::DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp)
R products/PurePhone/services/service-fileindexer/StartupIndexer.cpp => module-services/service-fileindexer/StartupIndexer.cpp +3 -3
@@ 18,9 18,6 @@ namespace service::detail
namespace
{
using namespace std::string_literals;
-
- // List of initial dirs for scan
- const std::vector<std::string> start_dirs{purefs::dir::getUserDiskPath() / "music"};
// Lock file name
const auto lock_file_name = purefs::dir::getUserDiskPath() / ".directory_is_indexed";
// Time for indexing first unit
@@ 29,6 26,9 @@ namespace service::detail
constexpr auto timer_run_delay = 10000;
} // namespace
+ StartupIndexer::StartupIndexer(const std::vector<std::string> &paths) : start_dirs{paths}
+ {}
+
// Process single entry
auto StartupIndexer::processEntry(std::shared_ptr<sys::Service> svc,
const std::filesystem::recursive_directory_iterator::value_type &entry) -> void
R products/PurePhone/services/service-fileindexer/include/service-fileindexer/Constants.hpp => module-services/service-fileindexer/include/service-fileindexer/Constants.hpp +0 -0
R products/PurePhone/services/service-fileindexer/include/service-fileindexer/InotifyHandler.hpp => module-services/service-fileindexer/include/service-fileindexer/InotifyHandler.hpp +0 -0
R products/PurePhone/services/service-fileindexer/include/service-fileindexer/ServiceFileIndexer.hpp => module-services/service-fileindexer/include/service-fileindexer/ServiceFileIndexer.hpp +1 -1
@@ 15,7 15,7 @@ namespace service
class ServiceFileIndexer final : public sys::Service
{
public:
- ServiceFileIndexer(const std::string_view name = service::name::file_indexer);
+ ServiceFileIndexer(const std::vector<std::string> &paths);
virtual ~ServiceFileIndexer() = default;
ServiceFileIndexer(const ServiceFileIndexer &) = delete;
ServiceFileIndexer &operator=(const ServiceFileIndexer &) = delete;
R products/PurePhone/services/service-fileindexer/include/service-fileindexer/StartupIndexer.hpp => module-services/service-fileindexer/include/service-fileindexer/StartupIndexer.hpp +4 -1
@@ 13,7 13,7 @@ namespace service::detail
{
public:
- StartupIndexer() = default;
+ explicit StartupIndexer(const std::vector<std::string> &paths);
~StartupIndexer() = default;
StartupIndexer(const StartupIndexer &) = delete;
StartupIndexer &operator=(StartupIndexer) = delete;
@@ 41,5 41,8 @@ namespace service::detail
sys::TimerHandle mIdxTimer;
bool mStarted{};
bool mForceStop{};
+
+ // List of initial dirs for scan
+ const std::vector<std::string> start_dirs;
};
} // namespace service::detail
M products/BellHybrid/BellHybridMain.cpp => products/BellHybrid/BellHybridMain.cpp +7 -0
@@ 15,7 15,9 @@
// modules
#include <module-db/Databases/EventsDB.hpp>
+#include <module-db/Databases/MultimediaFilesDB.hpp>
#include <module-db/Interface/AlarmEventRecord.hpp>
+#include <module-db/Interface/MultimediaFilesRecord.hpp>
// services
#include <appmgr/ApplicationManager.hpp>
@@ 28,6 30,7 @@
#include <service-eink/ServiceEink.hpp>
#include <service-gui/ServiceGUI.hpp>
#include <service-time/ServiceTime.hpp>
+#include <service-fileindexer/ServiceFileIndexer.hpp>
#include <Application.hpp>
#include <ApplicationLauncher.hpp>
@@ 47,6 50,9 @@ int main()
{
constexpr auto ApplicationName = "BellHybrid";
+ const std::vector<std::string> fileIndexerAudioPaths = {
+ {purefs::dir::getCurrentOSPath() / "assets/audio/bell/bg_sounds"}};
+
#if SYSTEM_VIEW_ENABLED
SEGGER_SYSVIEW_Conf();
SEGGER_SYSVIEW_DisableEvents(SYSVIEW_EVTMASK_ISR_ENTER);
@@ 68,6 74,7 @@ int main()
std::vector<std::unique_ptr<sys::BaseServiceCreator>> systemServices;
systemServices.emplace_back(sys::CreatorFor<EventManager>([]() { return dumpLogs(); }));
+ systemServices.emplace_back(sys::CreatorFor<service::ServiceFileIndexer>(std::move(fileIndexerAudioPaths)));
systemServices.emplace_back(sys::CreatorFor<ServiceDB>());
systemServices.emplace_back(sys::CreatorFor<service::Audio>());
systemServices.emplace_back(sys::CreatorFor<ServiceDesktop>());
M products/BellHybrid/CMakeLists.txt => products/BellHybrid/CMakeLists.txt +1 -0
@@ 58,6 58,7 @@ target_link_libraries(BellHybrid
module-vfs
service-desktop
service-time
+ service-fileindexer
sys
bell::time
platform
M products/BellHybrid/apps/application-bell-background-sounds/ApplicationBellBackgroundSounds.cpp => products/BellHybrid/apps/application-bell-background-sounds/ApplicationBellBackgroundSounds.cpp +11 -3
@@ 2,7 2,6 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "ApplicationBellBackgroundSounds.hpp"
-#include "models/BGSoundsRepository.hpp"
#include "presenter/BGSoundsMainWindowPresenter.hpp"
#include "presenter/BGSoundsTimerSelectPresenter.hpp"
#include "presenter/BGSoundsProgressPresenter.hpp"
@@ 14,11 13,19 @@
#include "windows/BGSoundsVolumeWindow.hpp"
#include "widgets/BGSoundsPlayer.hpp"
#include <apps-common/messages/AppMessage.hpp>
+#include <apps-common/models/SongsRepository.hpp>
#include <common/models/TimeModel.hpp>
#include <common/models/AudioModel.hpp>
#include <audio/AudioMessage.hpp>
#include <log/log.hpp>
+
+namespace
+{
+ const auto backgroundSoundsFilesPath =
+ purefs::createPath(purefs::dir::getCurrentOSPath(), "assets/audio/bell/bg_sounds").string();
+}
+
namespace app
{
ApplicationBellBackgroundSounds::ApplicationBellBackgroundSounds(std::string name,
@@ 48,8 55,9 @@ namespace app
void ApplicationBellBackgroundSounds::createUserInterface()
{
windowsFactory.attach(gui::name::window::main_window, [this](ApplicationCommon *app, const std::string &name) {
- auto tagsFetcher = std::make_unique<bgSounds::BGSoundsTagsFetcher>(app);
- auto soundsRepository = std::make_shared<bgSounds::BGSoundsRepository>(std::move(tagsFetcher));
+ auto tagsFetcher = std::make_unique<app::music::ServiceAudioTagsFetcher>(app);
+ auto soundsRepository =
+ std::make_unique<app::music::SongsRepository>(app, std::move(tagsFetcher), backgroundSoundsFilesPath);
auto presenter = std::make_unique<bgSounds::BGSoundsMainWindowPresenter>(std::move(soundsRepository));
return std::make_unique<gui::BGSoundsMainWindow>(app, std::move(presenter));
});
M products/BellHybrid/apps/application-bell-background-sounds/CMakeLists.txt => products/BellHybrid/apps/application-bell-background-sounds/CMakeLists.txt +0 -2
@@ 13,7 13,6 @@ target_include_directories(application-bell-background-sounds
target_sources(application-bell-background-sounds
PRIVATE
ApplicationBellBackgroundSounds.cpp
- models/BGSoundsRepository.cpp
presenter/BGSoundsMainWindowPresenter.cpp
presenter/BGSoundsProgressPresenter.cpp
presenter/BGSoundsTimerSelectPresenter.cpp
@@ 28,7 27,6 @@ target_sources(application-bell-background-sounds
data/BGSoundsCommon.hpp
data/BGSoundsStyle.hpp
data/BGSoundsAudioData.hpp
- models/BGSoundsRepository.hpp
widgets/BGSoundsPlayer.hpp
windows/BGSoundsMainWindow.hpp
presenter/BGSoundsMainWindowPresenter.hpp
M products/BellHybrid/apps/application-bell-background-sounds/data/BGSoundsAudioData.hpp => products/BellHybrid/apps/application-bell-background-sounds/data/BGSoundsAudioData.hpp +5 -4
@@ 3,6 3,7 @@
#pragma once
#include <SwitchData.hpp>
+#include <module-db/Interface/MultimediaFilesRecord.hpp>
#include <tags_fetcher/TagsFetcher.hpp>
#include <chrono>
@@ 13,14 14,14 @@ namespace gui
{
class BGSoundsAudioContext
{
- tags::fetcher::Tags tags;
+ db::multimedia_files::MultimediaFilesRecord sound;
public:
- explicit BGSoundsAudioContext(const tags::fetcher::Tags &tags) : tags{tags}
+ explicit BGSoundsAudioContext(const db::multimedia_files::MultimediaFilesRecord &sound) : sound{sound}
{}
- [[nodiscard]] const tags::fetcher::Tags &getTags() const noexcept
+ [[nodiscard]] const db::multimedia_files::MultimediaFilesRecord &getSound() const noexcept
{
- return tags;
+ return sound;
}
};
M products/BellHybrid/apps/application-bell-background-sounds/include/application-bell-background-sounds/ApplicationBellBackgroundSounds.hpp => products/BellHybrid/apps/application-bell-background-sounds/include/application-bell-background-sounds/ApplicationBellBackgroundSounds.hpp +1 -0
@@ 5,6 5,7 @@
#include <Application.hpp>
#include <common/models/AbstractAudioModel.hpp>
+#include <purefs/filesystem_paths.hpp>
namespace gui::window::name
{
M products/BellHybrid/apps/application-bell-background-sounds/models/BGSoundsRepository.cpp => products/BellHybrid/apps/application-bell-background-sounds/models/BGSoundsRepository.cpp +30 -32
@@ 1,12 1,12 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-#include "BGSoundsRepository.hpp"
-
#include <algorithm>
#include <log/log.hpp>
#include <time/ScopedTime.hpp>
#include <tags_fetcher/TagsFetcher.hpp>
+#include <apps-common/models/SongsRepository.hpp>
+#include <module-db/queries/multimedia_files/QueryMultimediaFilesGetLimited.hpp>
#include <filesystem>
@@ 20,41 20,39 @@ namespace app::bgSounds
return tags::fetcher::fetchTags(filePath);
}
- BGSoundsRepository::BGSoundsRepository(std::unique_ptr<AbstractTagsFetcher> tagsFetcher,
+ BGSoundsRepository::BGSoundsRepository(ApplicationCommon *application,
+ std::unique_ptr<AbstractTagsFetcher> tagsFetcher,
std::string musicFolderName)
- : tagsFetcher(std::move(tagsFetcher)), musicFolderName(std::move(musicFolderName))
+ : app::AsyncCallbackReceiver{application}, application{application}, tagsFetcher(std::move(tagsFetcher)),
+ musicFolderName(std::move(musicFolderName))
{}
- void BGSoundsRepository::scanMusicFilesList()
+ void BGSoundsRepository::getMusicFilesList(std::uint32_t offset,
+ std::uint32_t limit,
+ const OnGetMusicFilesListCallback &callback)
{
- musicFiles.clear();
-
- LOG_INFO("Scanning music folder: %s", musicFolderName.c_str());
- {
- auto time = utils::time::Scoped("fetch tags time");
- for (const auto &entry : std::filesystem::directory_iterator(musicFolderName)) {
- if (!std::filesystem::is_directory(entry)) {
- const auto &filePath = entry.path();
- const auto fileTags = tagsFetcher->getFileTags(filePath);
- if (fileTags) {
- musicFiles.push_back(*fileTags);
- }
- else {
- LOG_ERROR("Scanned not an audio file, skipped");
- }
- }
+ auto query = std::make_unique<db::multimedia_files::query::GetLimited>(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;
}
- std::sort(
- musicFiles.begin(), musicFiles.end(), [](const tags::fetcher::Tags &t1, const tags::fetcher::Tags &t2) {
- return t1.filePath < t2.filePath;
- });
- }
- LOG_INFO("Total number of music files found: %u", static_cast<unsigned int>(musicFiles.size()));
- }
- std::vector<tags::fetcher::Tags> BGSoundsRepository::getMusicFilesList() const
- {
- return musicFiles;
- }
+ 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;
+ });
+ task->execute(application, this);
+ }
} // namespace app::bgSounds
M products/BellHybrid/apps/application-bell-background-sounds/models/BGSoundsRepository.hpp => products/BellHybrid/apps/application-bell-background-sounds/models/BGSoundsRepository.hpp +17 -7
@@ 16,6 16,13 @@
namespace app::bgSounds
{
+ struct FilesCache
+ {
+ std::vector<db::multimedia_files::MultimediaFilesRecord> records{};
+ std::uint32_t recordsOffset{0};
+ std::uint32_t recordsCount{0};
+ };
+
class AbstractTagsFetcher
{
public:
@@ 40,25 47,28 @@ namespace app::bgSounds
public:
virtual ~AbstractSoundsRepository() noexcept = default;
- virtual void scanMusicFilesList() = 0;
virtual std::vector<tags::fetcher::Tags> getMusicFilesList() const = 0;
};
- class BGSoundsRepository : public AbstractSoundsRepository
+ class BGSoundsRepository : public AbstractSoundsRepository, public app::AsyncCallbackReceiver
{
static constexpr auto bgsoundsSubfolderPath = "assets/audio/bell/bg_sounds";
public:
- explicit BGSoundsRepository(std::unique_ptr<AbstractTagsFetcher> tagsFetcher,
- std::string musicFolderName = purefs::dir::getCurrentOSPath() /
- bgsoundsSubfolderPath);
+ using OnGetMusicFilesListCallback =
+ std::function<bool(const std::vector<db::multimedia_files::MultimediaFilesRecord> &, unsigned int)>;
- void scanMusicFilesList() override;
- std::vector<tags::fetcher::Tags> getMusicFilesList() const override;
+ BGSoundsRepository(ApplicationCommon *application,
+ std::unique_ptr<AbstractTagsFetcher> tagsFetcher,
+ std::string musicFolderName = purefs::dir::getCurrentOSPath() / bgsoundsSubfolderPath);
+
+ void getMusicFilesList(std::uint32_t offset, std::uint32_t limit, const OnGetMusicFilesListCallback &callback);
private:
+ ApplicationCommon *application = nullptr;
std::unique_ptr<AbstractTagsFetcher> tagsFetcher;
std::string musicFolderName;
+ FilesCache musicFilesViewCache;
std::vector<tags::fetcher::Tags> musicFiles;
};
} // namespace app::bgSounds
M products/BellHybrid/apps/application-bell-background-sounds/presenter/BGSoundsMainWindowPresenter.cpp => products/BellHybrid/apps/application-bell-background-sounds/presenter/BGSoundsMainWindowPresenter.cpp +21 -7
@@ 2,18 2,32 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "BGSoundsMainWindowPresenter.hpp"
-#include "models/BGSoundsRepository.hpp"
-#include <application-music-player/models/SongsRepository.hpp>
+#include <apps-common/models/SongsRepository.hpp>
+#include <purefs/filesystem_paths.hpp>
+
+namespace
+{
+ constexpr auto soundsRepoOffset = 0;
+ constexpr auto soundsRepoLimit = 100;
+} // namespace
namespace app::bgSounds
{
- BGSoundsMainWindowPresenter::BGSoundsMainWindowPresenter(std::shared_ptr<AbstractSoundsRepository> soundsRepository)
+ auto bgSoundsPath = purefs::dir::getCurrentOSPath() / "assets" / "audio" / "bell" / "bg_sounds";
+
+ BGSoundsMainWindowPresenter::BGSoundsMainWindowPresenter(
+ std::unique_ptr<app::music::AbstractSongsRepository> soundsRepository)
: soundsRepository{std::move(soundsRepository)}
- {
- this->soundsRepository->scanMusicFilesList();
- }
+ {}
void BGSoundsMainWindowPresenter::loadAudioRecords()
{
- getView()->setSoundsList(soundsRepository->getMusicFilesList());
+ soundsRepository->getMusicFilesList(
+ soundsRepoOffset,
+ soundsRepoLimit,
+ [this](const std::vector<db::multimedia_files::MultimediaFilesRecord> &records,
+ unsigned int repoRecordsCount) {
+ getView()->setSoundsList(records);
+ return true;
+ });
}
} // namespace app::bgSounds
M products/BellHybrid/apps/application-bell-background-sounds/presenter/BGSoundsMainWindowPresenter.hpp => products/BellHybrid/apps/application-bell-background-sounds/presenter/BGSoundsMainWindowPresenter.hpp +8 -4
@@ 4,11 4,16 @@
#pragma once
#include <apps-common/BasePresenter.hpp>
+#include <module-db/Interface/MultimediaFilesRecord.hpp>
#include <tags_fetcher/TagsFetcher.hpp>
#include <memory>
#include <string>
#include <vector>
+namespace app::music
+{
+ class AbstractSongsRepository;
+}
namespace app::bgSounds
{
class BGSoundsMainWindowContract
@@ 19,7 24,7 @@ namespace app::bgSounds
public:
virtual ~View() = default;
- virtual void setSoundsList(std::vector<tags::fetcher::Tags> soundsTags) = 0;
+ virtual void setSoundsList(std::vector<db::multimedia_files::MultimediaFilesRecord> songs) = 0;
};
class Presenter : public BasePresenter<BGSoundsMainWindowContract::View>
@@ 29,14 34,13 @@ namespace app::bgSounds
};
};
- class AbstractSoundsRepository;
class BGSoundsMainWindowPresenter : public BGSoundsMainWindowContract::Presenter
{
- std::shared_ptr<AbstractSoundsRepository> soundsRepository;
+ std::unique_ptr<app::music::AbstractSongsRepository> soundsRepository;
void loadAudioRecords() override;
public:
- explicit BGSoundsMainWindowPresenter(std::shared_ptr<AbstractSoundsRepository> soundsRepository);
+ explicit BGSoundsMainWindowPresenter(std::unique_ptr<app::music::AbstractSongsRepository> soundsRepository);
};
} // namespace app::bgSounds
M products/BellHybrid/apps/application-bell-background-sounds/presenter/BGSoundsProgressPresenter.cpp => products/BellHybrid/apps/application-bell-background-sounds/presenter/BGSoundsProgressPresenter.cpp +3 -3
@@ 27,7 27,7 @@ namespace app::bgSounds
timer->registerOnFinishedCallback([this]() { onFinished(); });
}
- void BGSoundsProgressPresenter::activate(const tags::fetcher::Tags &tags)
+ void BGSoundsProgressPresenter::activate(const db::multimedia_files::MultimediaFilesRecord &song)
{
Expects(timer != nullptr);
AbstractBGSoundsPlayer::PlaybackMode mode;
@@ 37,7 37,7 @@ namespace app::bgSounds
mode = AbstractBGSoundsPlayer::PlaybackMode::Looped;
}
else {
- timer->reset(std::chrono::seconds{tags.total_duration_s});
+ timer->reset(std::chrono::seconds{song.audioProperties.songLength});
mode = AbstractBGSoundsPlayer::PlaybackMode::SingleShot;
}
auto onStartCallback = [this](audio::RetCode retCode) {
@@ 45,7 45,7 @@ namespace app::bgSounds
timer->start();
}
};
- player.start(tags.filePath, mode, std::move(onStartCallback));
+ player.start(song.fileInfo.path, mode, std::move(onStartCallback));
}
void BGSoundsProgressPresenter::stop()
{
M products/BellHybrid/apps/application-bell-background-sounds/presenter/BGSoundsProgressPresenter.hpp => products/BellHybrid/apps/application-bell-background-sounds/presenter/BGSoundsProgressPresenter.hpp +10 -9
@@ 5,6 5,7 @@
#include <apps-common/BasePresenter.hpp>
#include <apps-common/widgets/TimerWithCallbacks.hpp>
+#include <module-db/Interface/MultimediaFilesRecord.hpp>
#include <tags_fetcher/TagsFetcher.hpp>
#include <time/time_locale.hpp>
#include <memory>
@@ 40,14 41,14 @@ namespace app::bgSounds
class Presenter : public BasePresenter<BGSoundsProgressContract::View>
{
public:
- virtual void activate(const tags::fetcher::Tags &tags) = 0;
- virtual void stop() = 0;
- virtual void pause() = 0;
- virtual void resume() = 0;
- virtual void setTimer(std::unique_ptr<app::TimerWithCallbacks> &&timer) = 0;
- virtual void handleUpdateTimeEvent() = 0;
- virtual bool isPaused() = 0;
- virtual void onBeforeShow() = 0;
+ virtual void activate(const db::multimedia_files::MultimediaFilesRecord &tags) = 0;
+ virtual void stop() = 0;
+ virtual void pause() = 0;
+ virtual void resume() = 0;
+ virtual void setTimer(std::unique_ptr<app::TimerWithCallbacks> &&timer) = 0;
+ virtual void handleUpdateTimeEvent() = 0;
+ virtual bool isPaused() = 0;
+ virtual void onBeforeShow() = 0;
};
};
@@ 60,7 61,7 @@ namespace app::bgSounds
std::unique_ptr<app::TimerWithCallbacks> timer;
std::unique_ptr<AbstractTimeModel> timeModel;
- void activate(const tags::fetcher::Tags &tags) override;
+ void activate(const db::multimedia_files::MultimediaFilesRecord &tags) override;
void stop() override;
void pause() override;
void resume() override;
M products/BellHybrid/apps/application-bell-background-sounds/windows/BGSoundsMainWindow.cpp => products/BellHybrid/apps/application-bell-background-sounds/windows/BGSoundsMainWindow.cpp +8 -8
@@ 19,21 19,21 @@ namespace gui
buildInterface();
setListTitle(utils::translate("app_bellmain_background_sounds"));
}
- void BGSoundsMainWindow::setSoundsList(std::vector<tags::fetcher::Tags> soundsTags)
+ void BGSoundsMainWindow::setSoundsList(std::vector<db::multimedia_files::MultimediaFilesRecord> sounds)
{
std::list<gui::Option> menuOptionList;
- auto addRecord = [&](const tags::fetcher::Tags &soundTags) {
+ auto addRecord = [&](const db::multimedia_files::MultimediaFilesRecord &sound) {
menuOptionList.emplace_back(std::make_unique<gui::option::OptionBellMenu>(
- soundTags.title,
+ sound.tags.title,
[=](gui::Item &item) {
- onActivated(soundTags);
+ onActivated(sound);
return true;
},
[=](gui::Item &item) { return true; },
this));
};
- for (const auto &tag : soundsTags) {
- addRecord(tag);
+ for (const auto &sound : sounds) {
+ addRecord(sound);
}
addOptions(std::move(menuOptionList));
@@ 44,9 44,9 @@ namespace gui
presenter->loadAudioRecords();
}
- void BGSoundsMainWindow::onActivated(const tags::fetcher::Tags &selectedSoundTags)
+ void BGSoundsMainWindow::onActivated(const db::multimedia_files::MultimediaFilesRecord &selectedSound)
{
- auto audioContext = std::make_unique<BGSoundsAudioContext>(selectedSoundTags);
+ auto audioContext = std::make_unique<BGSoundsAudioContext>(selectedSound);
auto switchData = std::make_unique<BGSoundsSwitchData>(std::move(audioContext));
application->switchWindow(gui::window::name::bgSoundsTimerSelect, std::move(switchData));
}
M products/BellHybrid/apps/application-bell-background-sounds/windows/BGSoundsMainWindow.hpp => products/BellHybrid/apps/application-bell-background-sounds/windows/BGSoundsMainWindow.hpp +2 -2
@@ 11,10 11,10 @@ namespace gui
{
std::unique_ptr<app::bgSounds::BGSoundsMainWindowContract::Presenter> presenter;
- void setSoundsList(std::vector<tags::fetcher::Tags> soundsTags);
+ void setSoundsList(std::vector<db::multimedia_files::MultimediaFilesRecord> soundsTags);
void buildInterface() override;
- void onActivated(const tags::fetcher::Tags &selectedSoundTags);
+ void onActivated(const db::multimedia_files::MultimediaFilesRecord &selectedSound);
public:
BGSoundsMainWindow(app::ApplicationCommon *app,
M products/BellHybrid/apps/application-bell-background-sounds/windows/BGSoundsProgressWindow.cpp => products/BellHybrid/apps/application-bell-background-sounds/windows/BGSoundsProgressWindow.cpp +2 -2
@@ 86,8 86,8 @@ namespace gui
if (data && typeid(*data) == typeid(BGSoundsSwitchData)) {
auto *audioSwitchData = static_cast<BGSoundsSwitchData *>(data);
audioContext = audioSwitchData->getAudioContext();
- title->setText(audioContext->getTags().title);
- presenter->activate(audioContext->getTags());
+ title->setText(audioContext->getSound().tags.title);
+ presenter->activate(audioContext->getSound());
}
}
M products/BellHybrid/services/db/ServiceDB.cpp => products/BellHybrid/services/db/ServiceDB.cpp +10 -1
@@ 4,7 4,10 @@
#include <db/ServiceDB.hpp>
#include <module-db/Databases/EventsDB.hpp>
+#include <module-db/Databases/MultimediaFilesDB.hpp>
+
#include <module-db/Interface/AlarmEventRecord.hpp>
+#include <module-db/Interface/MultimediaFilesRecord.hpp>
#include <service-db/DBServiceMessage.hpp>
#include <service-db/agents/settings/SettingsAgent.hpp>
@@ 25,6 28,8 @@ db::Interface *ServiceDB::getInterface(db::Interface::Name interface)
switch (interface) {
case db::Interface::Name::AlarmEvents:
return alarmEventRecordInterface.get();
+ case db::Interface::Name::MultimediaFiles:
+ return multimediaFilesRecordInterface.get();
default:
LOG_INFO("Not supported interface");
}
@@ 67,10 72,14 @@ sys::ReturnCodes ServiceDB::InitHandler()
}
// Create databases
- eventsDB = std::make_unique<EventsDB>((purefs::dir::getUserDiskPath() / "events.db").c_str());
+ eventsDB = std::make_unique<EventsDB>((purefs::dir::getUserDiskPath() / "events.db").c_str());
+ multimediaFilesDB = std::make_unique<db::multimedia_files::MultimediaFilesDB>(
+ (purefs::dir::getUserDiskPath() / "multimedia.db").c_str());
// Create record interfaces
alarmEventRecordInterface = std::make_unique<AlarmEventRecordInterface>(eventsDB.get());
+ multimediaFilesRecordInterface =
+ std::make_unique<db::multimedia_files::MultimediaFilesRecordInterface>(multimediaFilesDB.get());
databaseAgents.emplace(std::make_unique<SettingsAgent>(this, "settings_bell.db"));
M products/BellHybrid/services/db/include/db/ServiceDB.hpp => products/BellHybrid/services/db/include/db/ServiceDB.hpp +8 -0
@@ 10,6 10,11 @@ class AlarmEventRecordInterface;
class EventsDB;
class ThreadRecordInterface;
+namespace db::multimedia_files
+{
+ class MultimediaFilesDB;
+ class MultimediaFilesRecordInterface;
+} // namespace db::multimedia_files
class ServiceDB : public ServiceDBCommon
{
@@ 20,7 25,10 @@ class ServiceDB : public ServiceDBCommon
private:
std::unique_ptr<EventsDB> eventsDB;
+ std::unique_ptr<db::multimedia_files::MultimediaFilesDB> multimediaFilesDB;
+
std::unique_ptr<AlarmEventRecordInterface> alarmEventRecordInterface;
+ std::unique_ptr<db::multimedia_files::MultimediaFilesRecordInterface> multimediaFilesRecordInterface;
db::Interface *getInterface(db::Interface::Name interface) override;
sys::MessagePointer DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp) override;
M products/PurePhone/PurePhoneMain.cpp => products/PurePhone/PurePhoneMain.cpp +3 -1
@@ 75,6 75,8 @@ int main()
{
constexpr auto ApplicationName = "PurePhone";
+ const std::vector<std::string> fileIndexerAudioPaths = {{purefs::dir::getUserDiskPath() / "music"}};
+
#if SYSTEM_VIEW_ENABLED
SEGGER_SYSVIEW_Conf();
SEGGER_SYSVIEW_DisableEvents(SYSVIEW_EVTMASK_ISR_ENTER);
@@ 96,7 98,7 @@ int main()
std::vector<std::unique_ptr<sys::BaseServiceCreator>> systemServices;
systemServices.emplace_back(sys::CreatorFor<EventManager>([]() { return dumpLogs(); }));
- systemServices.emplace_back(sys::CreatorFor<service::ServiceFileIndexer>());
+ systemServices.emplace_back(sys::CreatorFor<service::ServiceFileIndexer>(std::move(fileIndexerAudioPaths)));
systemServices.emplace_back(sys::CreatorFor<ServiceDB>());
#if ENABLE_GSM == 0
// For now disable permanently Service cellular when there is no GSM configured
M products/PurePhone/services/CMakeLists.txt => products/PurePhone/services/CMakeLists.txt +0 -1
@@ 2,5 2,4 @@ add_subdirectory(appmgr)
add_subdirectory(evtmgr)
add_subdirectory(db)
add_subdirectory(desktop)
-add_subdirectory(service-fileindexer)
add_subdirectory(time)