diff --git a/build/CMakeLists.txt b/CMakeLists.txt similarity index 86% rename from build/CMakeLists.txt rename to CMakeLists.txt index da048ae..03a3086 100755 --- a/build/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,9 +28,9 @@ pkg_check_modules(LIBAV REQUIRED IMPORTED_TARGET ) PKG_SEARCH_MODULE(SDL2 REQUIRED sdl2) -file(GLOB_RECURSE PROJECT_SOURCES ../src/*.cpp) -file(GLOB_RECURSE PROJECT_HEADERS ../src/*.h) -file(GLOB_RECURSE PROJECT_RESOURCES ../assets/resources.qrc) +file(GLOB_RECURSE PROJECT_SOURCES src/*.cpp) +file(GLOB_RECURSE PROJECT_HEADERS src/*.h) +file(GLOB_RECURSE PROJECT_RESOURCES assets/resources.qrc) add_executable(CryliaPlayer ${PROJECT_SOURCES} @@ -61,4 +61,4 @@ set(DESKTOP_FILE ${CMAKE_CURRENT_BINARY_DIR}/CryliaPlayer.desktop) configure_file(${DESKTOP_FILE_IN} ${DESKTOP_FILE} @ONLY) install(FILES ${DESKTOP_FILE} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications) -install(FILES ../assets/aqua.jpg DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons) +install(FILES assets/aqua.jpg DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons) diff --git a/build/CryliaPlayer.desktop.in b/CryliaPlayer.desktop.in similarity index 100% rename from build/CryliaPlayer.desktop.in rename to CryliaPlayer.desktop.in diff --git a/assets/icons/songControl/arrow-expand.svg b/assets/icons/arrow-expand.svg similarity index 100% rename from assets/icons/songControl/arrow-expand.svg rename to assets/icons/arrow-expand.svg diff --git a/assets/icons/folder-outline.svg b/assets/icons/folder-outline.svg new file mode 100644 index 0000000..d61f392 --- /dev/null +++ b/assets/icons/folder-outline.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/home-outline.svg b/assets/icons/home-outline.svg new file mode 100644 index 0000000..f3b66bb --- /dev/null +++ b/assets/icons/home-outline.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/songControl/magnify.svg b/assets/icons/magnify.svg similarity index 100% rename from assets/icons/songControl/magnify.svg rename to assets/icons/magnify.svg diff --git a/assets/icons/songControl/nextSong.svg b/assets/icons/nextSong.svg similarity index 100% rename from assets/icons/songControl/nextSong.svg rename to assets/icons/nextSong.svg diff --git a/assets/icons/songControl/pause.svg b/assets/icons/pause.svg similarity index 100% rename from assets/icons/songControl/pause.svg rename to assets/icons/pause.svg diff --git a/assets/icons/songControl/play.svg b/assets/icons/play.svg similarity index 100% rename from assets/icons/songControl/play.svg rename to assets/icons/play.svg diff --git a/assets/icons/playlist-edit.svg b/assets/icons/playlist-edit.svg new file mode 100644 index 0000000..93a81fe --- /dev/null +++ b/assets/icons/playlist-edit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/playlist-music-outline.svg b/assets/icons/playlist-music-outline.svg new file mode 100644 index 0000000..77c3776 --- /dev/null +++ b/assets/icons/playlist-music-outline.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/playlist-plus.svg b/assets/icons/playlist-plus.svg new file mode 100644 index 0000000..c6c3476 --- /dev/null +++ b/assets/icons/playlist-plus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/songControl/prevSong.svg b/assets/icons/prevSong.svg similarity index 100% rename from assets/icons/songControl/prevSong.svg rename to assets/icons/prevSong.svg diff --git a/assets/icons/songControl/repeat-once.svg b/assets/icons/repeat-once.svg similarity index 100% rename from assets/icons/songControl/repeat-once.svg rename to assets/icons/repeat-once.svg diff --git a/assets/icons/songControl/shuffle.svg b/assets/icons/shuffle.svg similarity index 100% rename from assets/icons/songControl/shuffle.svg rename to assets/icons/shuffle.svg diff --git a/assets/icons/songControl/songRepeat.svg b/assets/icons/songRepeat.svg similarity index 100% rename from assets/icons/songControl/songRepeat.svg rename to assets/icons/songRepeat.svg diff --git a/assets/icons/songControl/volume-high.svg b/assets/icons/volume-high.svg similarity index 100% rename from assets/icons/songControl/volume-high.svg rename to assets/icons/volume-high.svg diff --git a/assets/icons/songControl/volume-low.svg b/assets/icons/volume-low.svg similarity index 100% rename from assets/icons/songControl/volume-low.svg rename to assets/icons/volume-low.svg diff --git a/assets/icons/songControl/volume-medium.svg b/assets/icons/volume-medium.svg similarity index 100% rename from assets/icons/songControl/volume-medium.svg rename to assets/icons/volume-medium.svg diff --git a/assets/icons/songControl/volume-mute.svg b/assets/icons/volume-mute.svg similarity index 100% rename from assets/icons/songControl/volume-mute.svg rename to assets/icons/volume-mute.svg diff --git a/assets/icons/songControl/volume-off.svg b/assets/icons/volume-off.svg similarity index 100% rename from assets/icons/songControl/volume-off.svg rename to assets/icons/volume-off.svg diff --git a/assets/resources.qrc b/assets/resources.qrc index 1c9cbad..94dec68 100755 --- a/assets/resources.qrc +++ b/assets/resources.qrc @@ -1,20 +1,6 @@ aqua.jpg - icons/songControl/shuffle.svg - icons/songControl/prevSong.svg - icons/songControl/nextSong.svg - icons/songControl/play.svg - icons/songControl/pause.svg - icons/songControl/songRepeat.svg - icons/songControl/repeat-once.svg - icons/songControl/volume-high.svg - icons/songControl/volume-low.svg - icons/songControl/volume-mute.svg - icons/songControl/volume-off.svg - icons/songControl/volume-medium.svg - icons/songControl/arrow-expand.svg - icons/home.svg - icons/songControl/magnify.svg + icons/ diff --git a/src/Controller/MusicPlayer/MusicPlayer.cpp b/src/Controller/MusicPlayer/MusicPlayer.cpp new file mode 100644 index 0000000..80e0508 --- /dev/null +++ b/src/Controller/MusicPlayer/MusicPlayer.cpp @@ -0,0 +1,79 @@ +#include "MusicPlayer.h" + +MusicPlayer::~MusicPlayer( ) { } + +void MusicPlayer::PlaySong(Song* song) { + songHistory->push(songQueue->Top( )); + songQueue->SetTop(song); + + audio.PlaySong(songQueue->Top( )->GetPath( )); +} + +void MusicPlayer::NextSong( ) { + if (songQueue->IsEmpty( )) { + audio.StopMusic( ); + return; + } + + songHistory->push(songQueue->Top( )); + songQueue->Next( ); + + audio.PlaySong(songQueue->Top( )->GetPath( )); +} + +void MusicPlayer::NextSong(Song* song, bool isPrioQueue) { + if (songQueue->IsEmpty( )) { + audio.StopMusic( ); + return; + } + + songHistory->push(songQueue->Top( )); + songQueue->JumpToSong(song, isPrioQueue); + + audio.PlaySong(songQueue->Top( )->GetPath( )); +} + +void MusicPlayer::PreviousSong( ) { + if (songHistory->isEmpty( )) + return; + + songQueue->SetTop(songHistory->top( )); + songHistory->pop( ); + + audio.PlaySong(songQueue->Top( )->GetPath( )); +} + +void MusicPlayer::SkipToTimestamp(unsigned const int& skipTo) { + if (audio.IsMusicPlaying( ) == 0) return; + + audio.SetMusicPos(skipTo); +} + +int MusicPlayer::GetSongProgression( ) { + return audio.IsMusicPlaying( ) == 1 ? audio.GetMusicPos( ) : 0; +} + +Song* MusicPlayer::GetCurrentlyPlaying( ) { + return songQueue->Top( ); +} + +//For the PriorityQueue +void MusicPlayer::AddSongToQueue(Song* song) { + songQueue->AddToPriorityQueue(song); +} + +void MusicPlayer::RemoveSongFromQueue(Song* song) { + songQueue->RemoveSongFromPriorityQueue(song); +} + +void MusicPlayer::MoveSongInQueue(Song* songToMove, Song* otherSong, bool beforeElseAfter) { + songQueue->MoveSongInPriorityQueue(songToMove, otherSong, beforeElseAfter); +} + +void MusicPlayer::shuffleQueue( ) { + shuffle ? songQueue->ShufflePlaylist( ) : songQueue->RestorePlaylist( ); +} + +void MusicPlayer::setQueueLoop( ) { + loop == All ? songQueue->LinkQueue(true) : songQueue->LinkQueue(false); +} diff --git a/src/Controller/MusicPlayer/MusicPlayer.h b/src/Controller/MusicPlayer/MusicPlayer.h new file mode 100644 index 0000000..5a099d9 --- /dev/null +++ b/src/Controller/MusicPlayer/MusicPlayer.h @@ -0,0 +1,104 @@ +#pragma once + +#include "../../core/audio/audio.h" +#include "../../core/SongHistory/SongHistory.hpp" +#include "../../core/SongQueue/SongQueue.h" +#include "../../core/song/song.h" + +enum Loop { + None, + Once, + All +}; + +class MusicPlayer { +public: + static MusicPlayer& getInstance( ) { + static MusicPlayer instance; + return instance; + } + +private: + MusicPlayer( ); + + // 0 no shuffle, 1 shuffling + int shuffle = 0; + // None, Once, All + Loop loop = None; + // 0 stopped, 1 playing + bool playing = 0; + + // Song queue, will be filled with the entire playlist by default + SongQueue* songQueue; + + // Contain all played songs + SongHistory* songHistory; + + Audio& audio = Audio::getInstance( ); + + void shuffleQueue( ); + void setQueueLoop( ); + +public: + ~MusicPlayer( ); + + MusicPlayer(MusicPlayer const&) = delete; + void operator=(MusicPlayer const&) = delete; + + /** + * @brief Will start playing the given song and put itself at the queue top. + * + * @param song Song that will start playing + */ + void PlaySong(Song* song); + + /** + * @brief Skip the current song and play the next in queue, + * if nothing is in queue it will stop playing anything. + * + */ + void NextSong( ); + + /** + * @brief Jumps the queue to the given song keeping the non altered queue intact + * + * @param song + * @param isPrioQueue If the song is in the prio queue or normal queue + */ + void NextSong(Song* song, bool isPrioQueue); + + /** + * @brief Rewind the currently playing song to the beginning if playtime >= 5 seconds. + * Otherwise play the top song in the history stack + * + */ + void PreviousSong( ); + + /** + * @brief Skip the song to the given timestamp + * + * @param skipTo time as positive integer + */ + void SkipToTimestamp(unsigned const int& skipTo); + + /** + * @brief Get the current Song progression as an positive integer + * + * @return int current timestamp + */ + int GetSongProgression( ); + + /** + * @brief Get the Currently Playing Song + * + * @return Song& Song thats currently playing + */ + Song* GetCurrentlyPlaying( ); + + void SetShuffle(bool shuffle) { this->shuffle = shuffle; } + void SetLoop(Loop loop) { this->loop = loop; } + + void AddSongToQueue(Song* song); + void RemoveSongFromQueue(Song* song); + void MoveSongInQueue(Song* songToMove, Song* otherSong, bool beforeElseAfter); +}; diff --git a/src/Controller/Pages/PageController.hpp b/src/Controller/Pages/PageController.hpp new file mode 100644 index 0000000..e69de29 diff --git a/src/Public/MainWindow.cpp b/src/Public/MainWindow.cpp deleted file mode 100755 index 593fb22..0000000 --- a/src/Public/MainWindow.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "MainWindow.h" - -void MainWindow::setupMainWindow( ) { - this->setWindowTitle("Crylia Player"); - this->setWindowIcon(QIcon(":aqua.jpg")); - - QWidget* mw = new QWidget(this); - mw->setContentsMargins(10, 10, 10, 10); - - QOverlayout* ol = new QOverlayout(mw); - mw->setLayout(ol); - - Pages* p = new Pages(mw); - PlaylistPage* pp = new PlaylistPage(mw); - PlaylistWidget* pw = new PlaylistWidget(mw); - FloatingControls* fc = new FloatingControls(mw, this->path); - - QVBoxLayout* vbox = new QVBoxLayout( ); - vbox->addWidget(fc, 0, Qt::AlignBottom); - - QHBoxLayout* hbox = new QHBoxLayout( ); - QVBoxLayout* vbox2 = new QVBoxLayout( ); - vbox2->addWidget(p); - vbox2->addWidget(pw); - hbox->addLayout(vbox2); - hbox->addWidget(pp); - - hbox->setSpacing(10); - vbox2->setSpacing(10); - - ol->addItem(vbox); - ol->addItem(hbox); - - this->setCentralWidget(mw); -} - -MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) { - setupMainWindow( ); -} - -MainWindow::MainWindow(std::filesystem::path path, QWidget* parent) - : QMainWindow(parent), path(path) { - setupMainWindow( ); -} - -MainWindow::~MainWindow( ) { } diff --git a/src/Public/Modules/PageNavigator/pages.cpp b/src/Public/Modules/PageNavigator/pages.cpp deleted file mode 100755 index a916f65..0000000 --- a/src/Public/Modules/PageNavigator/pages.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "pages.h" - -#include -#include - -Pages::Pages(QWidget* parent) :QFrame(parent) { - - this->setStyleSheet(R"( - background-color: #282828; - border-radius: 12px; - )"); - - this->setFixedSize(300, 180); - - QVBoxLayout* layout = new QVBoxLayout(this); - - PageNavigator* home = new PageNavigator("Home", ":icons/home.svg"); - PageNavigator* localFiles = new PageNavigator("Local Files", ":icons/home.svg"); - PageNavigator* playlist = new PageNavigator("Playlist", ":icons/songControl/magnify.svg"); - - - layout->addWidget(home); - layout->addWidget(localFiles); - layout->addWidget(playlist); -} - -Pages::~Pages( ) { } diff --git a/src/Public/Modules/PageNavigator/pages.h b/src/Public/Modules/PageNavigator/pages.h deleted file mode 100755 index e9a98c0..0000000 --- a/src/Public/Modules/PageNavigator/pages.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include -#include -#include "../../Widgets/PageNavigator/PageNavigator.h" - -class Pages : public QFrame { - - Q_OBJECT - -private: - //Page[3] pages; - -public: - Pages(QWidget* parent = nullptr); - ~Pages( ); -}; diff --git a/src/Public/Pages/Playlist/PlaylistPage.cpp b/src/Public/Pages/Playlist/PlaylistPage.cpp deleted file mode 100755 index 037de2d..0000000 --- a/src/Public/Pages/Playlist/PlaylistPage.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "PlaylistPage.h" - -#include -#include -#include -#include -#include -#include - -PlaylistPage::PlaylistPage(QWidget* parent) : QFrame(parent) { - - this->setStyleSheet(R"( - background-color: #282828; - border-radius: 12px; - )"); -} - -PlaylistPage::~PlaylistPage( ) { } diff --git a/src/Public/Tools/SvgToPixmap.hpp b/src/Public/Tools/SvgToPixmap.hpp deleted file mode 100644 index 417bd5c..0000000 --- a/src/Public/Tools/SvgToPixmap.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -static QPixmap RenderSvg(QString path, int w, int h) { - QSvgRenderer renderer(path); - QPixmap pixmap(w, h); - pixmap.fill(Qt::transparent); - QPainter painter(&pixmap); - renderer.render(&painter); - - return pixmap; -} diff --git a/src/Public/Widgets/PageNavigator/PageNavigator.cpp b/src/Public/Widgets/PageNavigator/PageNavigator.cpp deleted file mode 100644 index 0d96fc8..0000000 --- a/src/Public/Widgets/PageNavigator/PageNavigator.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "PageNavigator.h" -#include "SelectHandler.hpp" - -PageNavigator::PageNavigator(QString text, QString icon, QWidget* parent) - :m_text(new QLabel(text)), m_icon(new QLabel( )) { - - m_icon->setPixmap(icon); - - setObjectName("PageNavigator"); - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - setStyleSheet(R"( - #PageNavigator{ - border: 4px solid #414141; - border-radius: 8px; - color: #E0E0E0; - } - )"); - - QFont font = m_text->font( ); - font.setPointSize(16); - font.setWeight(QFont::Bold); - m_text->setFont(font); - - QHBoxLayout* layout = new QHBoxLayout(this); - layout->addWidget(m_icon, 0, Qt::AlignLeft); - layout->addWidget(m_text, 1, Qt::AlignLeft); - - connect(this, &QPushButton::clicked, [this]( ) { - SelectHandler* sh = SelectHandler::GetInstance( ); - - sh->setSelected(this); - }); - -} - -void PageNavigator::unselect( ) { - setStyleSheet(R"( - #PageNavigator{ - border: 4px solid #414141; - border-radius: 6px; - color: #E0E0E0; - } - )"); -} - -void PageNavigator::select( ) { - setStyleSheet(R"( - #PageNavigator{ - border: 4px solid #81D4FA; - border-radius: 6px; - color: #E0E0E0; - } - )"); -} diff --git a/src/Public/Layouts/QOverlayout.cpp b/src/View/Layouts/QOverlayout.cpp similarity index 100% rename from src/Public/Layouts/QOverlayout.cpp rename to src/View/Layouts/QOverlayout.cpp diff --git a/src/Public/Layouts/QOverlayout.h b/src/View/Layouts/QOverlayout.h similarity index 100% rename from src/Public/Layouts/QOverlayout.h rename to src/View/Layouts/QOverlayout.h diff --git a/src/View/MainWidget.cpp b/src/View/MainWidget.cpp new file mode 100644 index 0000000..18b91ce --- /dev/null +++ b/src/View/MainWidget.cpp @@ -0,0 +1,68 @@ +#include "MainWidget.h" + +void MainWidget::setupMainWidget( ) { + setContentsMargins(10, 10, 10, 10); + + QOverlayout* ol = new QOverlayout(this); + setLayout(ol); + + QVBoxLayout* vbox = new QVBoxLayout( ); + vbox->addWidget(floatingControlls, 0, Qt::AlignBottom); + + QHBoxLayout* hbox = new QHBoxLayout( ); + QVBoxLayout* vbox2 = new QVBoxLayout( ); + vbox2->addWidget(pageNav); + vbox2->addWidget(playlistNav); + hbox->addLayout(vbox2); + QHBoxLayout* stackedLayout = new QHBoxLayout( ); + + stackedLayout->addWidget(homePage); + stackedLayout->addWidget(playlistPage); + + playlistPage->setVisible(false); + + hbox->addLayout(stackedLayout, 0); + + hbox->setSpacing(10); + vbox2->setSpacing(10); + + ol->addItem(hbox); + ol->addItem(vbox); + + connect(pageNav, &PageNavModule::SelectChanged, [this, stackedLayout](PageNavigator* pn) { + if (pn->GetText( ).toStdString( ) == "Home") { + //stackedLayout->setCurrentIndex(0); + stackedLayout->itemAt(0)->widget( )->setVisible(true); + stackedLayout->itemAt(1)->widget( )->setVisible(false); + } + else if (pn->GetText( ).toStdString( ) == "Playlist") { + //stackedLayout->setCurrentIndex(1); + stackedLayout->itemAt(0)->widget( )->setVisible(false); + stackedLayout->itemAt(1)->widget( )->setVisible(true); + } + }); +} + +void MainWidget::PageChangedAction( ) { } + +MainWidget::MainWidget(QWidget* parent) + : QWidget(parent), + pageNav(new PageNavModule(this)), + playlistNav(new PlaylistNavModule(this)), + playlistPage(new PlaylistPage(this)), + homePage(new HomePage(this)), + floatingControlls(new FloatingControls(this)) { + setupMainWidget( ); +} + +MainWidget::MainWidget(std::filesystem::path path, QWidget* parent) + : QWidget(parent), + pageNav(new PageNavModule(this)), + playlistNav(new PlaylistNavModule(this)), + playlistPage(new PlaylistPage(this)), + homePage(new HomePage(this)), + floatingControlls(new FloatingControls(this, path)) { + setupMainWidget( ); +} + +MainWidget::~MainWidget( ) { } diff --git a/src/View/MainWidget.h b/src/View/MainWidget.h new file mode 100644 index 0000000..de7d766 --- /dev/null +++ b/src/View/MainWidget.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include +#include + +#include "Layouts/QOverlayout.h" +#include "Modules/FloatingControls/FloatingControls.h" +#include "Modules/PageNavModule/PageNavModule.h" +#include "Modules/PlaylistNavModule/PlaylistNavModule.h" +#include "Pages/Playlist/PlaylistPage.h" +#include "Pages/Home/HomePage.h" + +class MainWidget : public QWidget { + Q_OBJECT +private: + + PageNavModule* pageNav; + PlaylistNavModule* playlistNav; + + PlaylistPage* playlistPage; + HomePage* homePage; + + FloatingControls* floatingControlls; + + void setupMainWidget( ); + +public: + MainWidget(QWidget* parent = nullptr); + MainWidget(std::filesystem::path path, QWidget* parent = nullptr); + ~MainWidget( ); + +private slots: + void PageChangedAction( ); + + +}; diff --git a/src/View/MainWindow.cpp b/src/View/MainWindow.cpp new file mode 100755 index 0000000..1b957b4 --- /dev/null +++ b/src/View/MainWindow.cpp @@ -0,0 +1,27 @@ +#include "MainWindow.h" + +void MainWindow::setupMainWindow( ) { + this->setWindowTitle("Crylia Player"); + this->setWindowIcon(QIcon(":aqua.jpg")); + + setObjectName("MainWindow"); + setStyleSheet(R"( + #MainWindow{ + background-color: #121212; + } + )"); + + this->setCentralWidget(mainWidget); +} + +MainWindow::MainWindow(QWidget* parent) + : QMainWindow(parent), mainWidget(new MainWidget(this)) { + setupMainWindow( ); +} + +MainWindow::MainWindow(std::filesystem::path path, QWidget* parent) + : QMainWindow(parent), mainWidget(new MainWidget(path, this)) { + setupMainWindow( ); +} + +MainWindow::~MainWindow( ) { } diff --git a/src/Public/MainWindow.h b/src/View/MainWindow.h similarity index 54% rename from src/Public/MainWindow.h rename to src/View/MainWindow.h index 71d247e..40e89e9 100755 --- a/src/Public/MainWindow.h +++ b/src/View/MainWindow.h @@ -7,23 +7,17 @@ #include #include -#include "Modules/FloatingControls/FloatingControls.h" -#include "Layouts/QOverlayout.h" -#include "Modules/PageNavigator/pages.h" -#include "Pages/Playlist/PlaylistPage.h" -#include "Modules/PlaylistNavigator/PlaylistWidget.h" +#include "MainWidget.h" class MainWindow : public QMainWindow { Q_OBJECT - public: MainWindow(QWidget* parent = nullptr); MainWindow(std::filesystem::path path, QWidget* parent = nullptr); ~MainWindow( ); private: - // In case the program gets started with a song as an argument - std::filesystem::path path; + MainWidget* mainWidget; void setupMainWindow( ); }; diff --git a/src/Public/Modules/FloatingControls/FloatingControls.cpp b/src/View/Modules/FloatingControls/FloatingControls.cpp similarity index 88% rename from src/Public/Modules/FloatingControls/FloatingControls.cpp rename to src/View/Modules/FloatingControls/FloatingControls.cpp index 2b9c257..f4b38c6 100755 --- a/src/Public/Modules/FloatingControls/FloatingControls.cpp +++ b/src/View/Modules/FloatingControls/FloatingControls.cpp @@ -20,27 +20,6 @@ enum Repeat : short { NONE }; -template -static void applyShadow(T obj, int blurRadius = 20, int xOffset = 10, int yOffset = 10, QString color = "#000000", int offset = 2) { - QGraphicsDropShadowEffect* dropShadow = new QGraphicsDropShadowEffect( ); - dropShadow->setBlurRadius(blurRadius); - dropShadow->setXOffset(xOffset); - dropShadow->setYOffset(yOffset); - dropShadow->setColor(color); - dropShadow->setOffset(offset); - obj->setGraphicsEffect(dropShadow); -} - -static QPixmap RenderSvg(QString path) { - QSvgRenderer renderer(path); - QPixmap pixmap(36, 36); - pixmap.fill(Qt::transparent); - QPainter painter(&pixmap); - renderer.render(&painter); - - return pixmap; -} - static QPushButton* makeSongControlButton(QString name, QSize size = QSize(36, 36), QString color = "#D7D7D7") { QPushButton* button = new QPushButton( ); button->setObjectName(name); @@ -50,7 +29,7 @@ static QPushButton* makeSongControlButton(QString name, QSize size = QSize(36, 3 border: 0; } )"); - button->setIcon(RenderSvg(":/icons/songControl/" + name + ".svg")); + button->setIcon(RenderSvg(":/icons/" + name + ".svg", 36, 36)); button->setIconSize(size); button->setCursor(Qt::PointingHandCursor); QGraphicsColorizeEffect* colorize = new QGraphicsColorizeEffect( ); @@ -70,7 +49,7 @@ FloatingControls::FloatingControls(QWidget* parent, std::filesystem::path path) songRepeat(NONE), artist("Artist"), songName("Song"), - song(Audio::getInstance(path)) { + song(Audio::getInstance( )) { this->setFixedHeight(100); this->setObjectName("main"); this->setStyleSheet(R"( @@ -145,7 +124,7 @@ FloatingControls::FloatingControls(QWidget* parent, std::filesystem::path path) QHBoxLayout* songControlsLayout = new QHBoxLayout( ); songControlsLayout->setAlignment(Qt::AlignCenter | Qt::AlignBottom); - QString buttonNames[5] = { "songRepeat", "prevSong", "play", "nextSong", "shuffle" }; + QString buttonNames[5] = { "shuffle", "prevSong", "play", "nextSong", "songRepeat" }; QString col = "#D7D7D7"; for (int i = 0; i < 5; i++) { if (buttonNames[i] == "shuffle" || buttonNames[i] == "songRepeat") @@ -158,16 +137,16 @@ FloatingControls::FloatingControls(QWidget* parent, std::filesystem::path path) QObject::connect(pb, &QPushButton::clicked, [pb, this]( ) { if (!song.IsMusicPlaying( )) { song.StartMusic( ); - pb->setIcon(RenderSvg(":/icons/songControl/pause.svg")); + pb->setIcon(RenderSvg(":/icons/pause.svg", 36, 36)); return; } if (GetPlayPause( )) { song.ResumeMusic( ); - pb->setIcon(RenderSvg(":/icons/songControl/pause.svg")); + pb->setIcon(RenderSvg(":/icons/pause.svg", 36, 36)); } else { song.PauseMusic( ); - pb->setIcon(RenderSvg(":/icons/songControl/play.svg")); + pb->setIcon(RenderSvg(":/icons/play.svg", 36, 36)); } togglePlayPause( ); }); @@ -279,7 +258,7 @@ FloatingControls::FloatingControls(QWidget* parent, std::filesystem::path path) QLabel* volumeIcon = new QLabel( ); volumeIcon->setAlignment(Qt::AlignRight | Qt::AlignVCenter); volumeIcon->setObjectName("volumeIcon"); - volumeIcon->setPixmap(RenderSvg(":icons/songControl//volume-high.svg").scaled(QSize(24, 24), Qt::IgnoreAspectRatio)); + volumeIcon->setPixmap(RenderSvg(":icons/volume-high.svg", 36, 36).scaled(QSize(24, 24), Qt::IgnoreAspectRatio)); QGraphicsColorizeEffect* colorize = new QGraphicsColorizeEffect( ); colorize->setColor(QColor("#78AB70")); colorize->setStrength(1); @@ -344,7 +323,7 @@ FloatingControls::FloatingControls(QWidget* parent, std::filesystem::path path) QLabel* FullscreenLabel = new QLabel( ); FullscreenLabel->setFixedSize(36, 24); FullscreenLabel->setObjectName("fullscreenLabel"); - FullscreenLabel->setPixmap(QPixmap(":icons/songControl//arrow-expand.svg").scaled(QSize(24, 24), Qt::IgnoreAspectRatio)); + FullscreenLabel->setPixmap(QPixmap(":icons/arrow-expand.svg").scaled(QSize(24, 24), Qt::IgnoreAspectRatio)); QVBoxLayout* FullscreenLayout = new QVBoxLayout( ); FullscreenLayout->setAlignment(Qt::AlignCenter); diff --git a/src/Public/Modules/FloatingControls/FloatingControls.h b/src/View/Modules/FloatingControls/FloatingControls.h similarity index 96% rename from src/Public/Modules/FloatingControls/FloatingControls.h rename to src/View/Modules/FloatingControls/FloatingControls.h index 9ff0201..29271b2 100755 --- a/src/Public/Modules/FloatingControls/FloatingControls.h +++ b/src/View/Modules/FloatingControls/FloatingControls.h @@ -1,12 +1,14 @@ #pragma once #include "../../../core/audio/audio.h" +#include "../../Tools/SvgToPixmap.hpp" #include #include #include #include #include +#include enum Repeat : short; diff --git a/src/View/Modules/PageNavModule/PageNavModule.cpp b/src/View/Modules/PageNavModule/PageNavModule.cpp new file mode 100755 index 0000000..405f678 --- /dev/null +++ b/src/View/Modules/PageNavModule/PageNavModule.cpp @@ -0,0 +1,32 @@ +#include "PageNavModule.h" + +#include +#include + +PageNavModule::PageNavModule(QWidget* parent) :QFrame(parent) { + + this->setStyleSheet(R"( + background-color: #282828; + border-radius: 12px; + )"); + + applyShadow(this); + + this->setFixedSize(300, 180); + + QVBoxLayout* layout = new QVBoxLayout(this); + + PageNavigator* home = new PageNavigator("Home", ":icons/home-outline.svg", "#81D4FA"); + PageNavigator* localFiles = new PageNavigator("Local Files", ":icons/folder-outline.svg", "#FFE082"); + PageNavigator* playlist = new PageNavigator("Playlist", ":icons/magnify.svg", "#CE93D8"); + + layout->addWidget(home); + layout->addWidget(localFiles); + layout->addWidget(playlist); + + connect(home, &PageNavigator::SelectedChanged, this, &PageNavModule::SelectChanged); + connect(localFiles, &PageNavigator::SelectedChanged, this, &PageNavModule::SelectChanged); + connect(playlist, &PageNavigator::SelectedChanged, this, &PageNavModule::SelectChanged); +} + +PageNavModule::~PageNavModule( ) { } diff --git a/src/View/Modules/PageNavModule/PageNavModule.h b/src/View/Modules/PageNavModule/PageNavModule.h new file mode 100755 index 0000000..2ca68f8 --- /dev/null +++ b/src/View/Modules/PageNavModule/PageNavModule.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include +#include +#include "../../Widgets/PageNavigator/PageNavigator.h" +#include "../../Tools/SvgToPixmap.hpp" + +class PageNavModule : public QFrame { + Q_OBJECT +private: + QVector pages; + +public: + PageNavModule(QWidget* parent = nullptr); + ~PageNavModule( ); + +signals: + void SelectChanged(PageNavigator* pn); +}; diff --git a/src/Public/Modules/PlaylistNavigator/PlaylistWidget.cpp b/src/View/Modules/PlaylistNavModule/PlaylistNavModule.cpp similarity index 58% rename from src/Public/Modules/PlaylistNavigator/PlaylistWidget.cpp rename to src/View/Modules/PlaylistNavModule/PlaylistNavModule.cpp index 18d0d57..2b95474 100755 --- a/src/Public/Modules/PlaylistNavigator/PlaylistWidget.cpp +++ b/src/View/Modules/PlaylistNavModule/PlaylistNavModule.cpp @@ -1,6 +1,6 @@ -#include "PlaylistWidget.h" +#include "PlaylistNavModule.h" -PlaylistWidget::PlaylistWidget(QWidget* parent) : QFrame(parent) { +PlaylistNavModule::PlaylistNavModule(QWidget* parent) : QFrame(parent) { this->setStyleSheet(R"( background-color: #282828; @@ -14,4 +14,4 @@ PlaylistWidget::PlaylistWidget(QWidget* parent) : QFrame(parent) { } -PlaylistWidget::~PlaylistWidget( ) { } +PlaylistNavModule::~PlaylistNavModule( ) { } diff --git a/src/Public/Modules/PlaylistNavigator/PlaylistWidget.h b/src/View/Modules/PlaylistNavModule/PlaylistNavModule.h similarity index 50% rename from src/Public/Modules/PlaylistNavigator/PlaylistWidget.h rename to src/View/Modules/PlaylistNavModule/PlaylistNavModule.h index e90efe7..7ccd4ca 100755 --- a/src/Public/Modules/PlaylistNavigator/PlaylistWidget.h +++ b/src/View/Modules/PlaylistNavModule/PlaylistNavModule.h @@ -4,13 +4,13 @@ #include #include -class PlaylistWidget : public QFrame { +class PlaylistNavModule : public QFrame { Q_OBJECT private: public: - PlaylistWidget(QWidget* parent); - ~PlaylistWidget( ); + PlaylistNavModule(QWidget* parent); + ~PlaylistNavModule( ); }; diff --git a/src/View/Pages/Home/HomePage.cpp b/src/View/Pages/Home/HomePage.cpp new file mode 100644 index 0000000..09e3926 --- /dev/null +++ b/src/View/Pages/Home/HomePage.cpp @@ -0,0 +1,14 @@ +#include "HomePage.h" + +HomePage::HomePage(QWidget* parent) + : QFrame(parent) { + + setStyleSheet(R"( + background-color: #28FF28; + border-radius: 12px; + )"); + + applyShadow(this); +} + +HomePage::~HomePage( ) { } diff --git a/src/View/Pages/Home/HomePage.h b/src/View/Pages/Home/HomePage.h new file mode 100644 index 0000000..c29b873 --- /dev/null +++ b/src/View/Pages/Home/HomePage.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include +#include "../../Tools/SvgToPixmap.hpp" + + +class HomePage : public QFrame { + Q_OBJECT +private: + /* data */ +public: + HomePage(QWidget* parent = nullptr); + ~HomePage( ); +}; diff --git a/src/View/Pages/Playlist/PlaylistPage.cpp b/src/View/Pages/Playlist/PlaylistPage.cpp new file mode 100755 index 0000000..8992b70 --- /dev/null +++ b/src/View/Pages/Playlist/PlaylistPage.cpp @@ -0,0 +1,14 @@ +#include "PlaylistPage.h" + +PlaylistPage::PlaylistPage(QWidget* parent) + : QFrame(parent) { + + setStyleSheet(R"( + background-color: #2828ff; + border-radius: 12px; + )"); + + applyShadow(this); +} + +PlaylistPage::~PlaylistPage( ) { } diff --git a/src/Public/Pages/Playlist/PlaylistPage.h b/src/View/Pages/Playlist/PlaylistPage.h similarity index 63% rename from src/Public/Pages/Playlist/PlaylistPage.h rename to src/View/Pages/Playlist/PlaylistPage.h index 445d6d2..17b07d4 100755 --- a/src/Public/Pages/Playlist/PlaylistPage.h +++ b/src/View/Pages/Playlist/PlaylistPage.h @@ -2,13 +2,12 @@ #include #include +#include "../../Tools/SvgToPixmap.hpp" class PlaylistPage : public QFrame { - Q_OBJECT - private: public: - PlaylistPage(QWidget* parent); + PlaylistPage(QWidget* parent = nullptr); ~PlaylistPage( ); }; diff --git a/src/View/Tools/SvgToPixmap.hpp b/src/View/Tools/SvgToPixmap.hpp new file mode 100644 index 0000000..f166091 --- /dev/null +++ b/src/View/Tools/SvgToPixmap.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +static QPixmap RenderSvg(QString path, int w, int h) { + QSvgRenderer renderer(path); + QPixmap pixmap(w, h); + pixmap.fill(Qt::transparent); + QPainter painter(&pixmap); + renderer.render(&painter); + + return pixmap; +} + +template +static void applyShadow(T obj, int blurRadius = 20, int xOffset = 10, int yOffset = 10, QString color = "#000000", int offset = 2) { + QGraphicsDropShadowEffect* dropShadow = new QGraphicsDropShadowEffect( ); + dropShadow->setBlurRadius(blurRadius); + dropShadow->setXOffset(xOffset); + dropShadow->setYOffset(yOffset); + dropShadow->setColor(color); + dropShadow->setOffset(offset); + obj->setGraphicsEffect(dropShadow); +} diff --git a/src/View/Widgets/NavigationButton/NavigationButton.cpp b/src/View/Widgets/NavigationButton/NavigationButton.cpp new file mode 100644 index 0000000..e5bf25b --- /dev/null +++ b/src/View/Widgets/NavigationButton/NavigationButton.cpp @@ -0,0 +1,11 @@ +#include "NavigationButton.h" + +NavigationButton::NavigationButton( ) { } + +NavigationButton::~NavigationButton( ) { } + +void setSelected(NavigationButton* newSelected); +NavigationButton getSelected( ) { } + +void NavigationButton::select( ) { } +void NavigationButton::unselect( ) { } diff --git a/src/View/Widgets/NavigationButton/NavigationButton.h b/src/View/Widgets/NavigationButton/NavigationButton.h new file mode 100644 index 0000000..2772088 --- /dev/null +++ b/src/View/Widgets/NavigationButton/NavigationButton.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include + +class NavigationButton : public QPushButton { + Q_OBJECT +private: + QLabel* m_icon; + QLabel* m_name; + QString* m_colorHex; + + static NavigationButton* m_selected; + +public: + static void setSelected(NavigationButton* newSelected); + static NavigationButton* getSelected( ); + + NavigationButton( ); + ~NavigationButton( ); + +signals: + void unselected( ); + void selected( ); + +private slots: + void select( ); + void unselect( ); + +}; diff --git a/src/View/Widgets/NavigationButton/PagesButton/PagesButton.cpp b/src/View/Widgets/NavigationButton/PagesButton/PagesButton.cpp new file mode 100644 index 0000000..a7689d5 --- /dev/null +++ b/src/View/Widgets/NavigationButton/PagesButton/PagesButton.cpp @@ -0,0 +1,4 @@ +#include "PagesButton.h" + +PagesButton::PagesButton( ) { } +PagesButton::~PagesButton( ) { } diff --git a/src/View/Widgets/NavigationButton/PagesButton/PagesButton.h b/src/View/Widgets/NavigationButton/PagesButton/PagesButton.h new file mode 100644 index 0000000..6f72cd1 --- /dev/null +++ b/src/View/Widgets/NavigationButton/PagesButton/PagesButton.h @@ -0,0 +1,11 @@ +#pragma once + +#include "../NavigationButton.h" + +class PagesButton : NavigationButton { +private: + +public: + PagesButton( ); + ~PagesButton( ); +}; diff --git a/src/View/Widgets/NavigationButton/PlaylistButton/PlaylistButton.cpp b/src/View/Widgets/NavigationButton/PlaylistButton/PlaylistButton.cpp new file mode 100644 index 0000000..6016e2d --- /dev/null +++ b/src/View/Widgets/NavigationButton/PlaylistButton/PlaylistButton.cpp @@ -0,0 +1,4 @@ +#include "PlaylistButton.h" + +PlaylistButton::PlaylistButton( ) { } +PlaylistButton::~PlaylistButton( ) { } diff --git a/src/View/Widgets/NavigationButton/PlaylistButton/PlaylistButton.h b/src/View/Widgets/NavigationButton/PlaylistButton/PlaylistButton.h new file mode 100644 index 0000000..43c2584 --- /dev/null +++ b/src/View/Widgets/NavigationButton/PlaylistButton/PlaylistButton.h @@ -0,0 +1,11 @@ +#pragma once + +#include "../NavigationButton.h" + +class PlaylistButton : NavigationButton { +private: + +public: + PlaylistButton( ); + ~PlaylistButton( ); +}; diff --git a/src/View/Widgets/PageNavigator/PageNavigator.cpp b/src/View/Widgets/PageNavigator/PageNavigator.cpp new file mode 100644 index 0000000..110aa5b --- /dev/null +++ b/src/View/Widgets/PageNavigator/PageNavigator.cpp @@ -0,0 +1,88 @@ +#include "PageNavigator.h" +#include "SelectHandler.hpp" +#include "../../Tools/SvgToPixmap.hpp" + +class SquareIcon : public QLabel { +public: + QSize sizeHint( ) const override { + QSize hint = QLabel::sizeHint( ); + int side = qMin(hint.width( ), hint.height( )); + return QSize(side, side); + } +}; + +PageNavigator::PageNavigator(QString text, QString icon, QString color, QWidget* parent) + :m_text(new QLabel(text)), m_icon(new SquareIcon( )), m_color(color), m_iconPath(icon) { + + + QSvgRenderer renderer(icon); + + QPixmap pixmap(32, 32); + pixmap.fill(Qt::transparent); + QPainter painter(&pixmap); + renderer.render(&painter, pixmap.rect( )); + + painter.setCompositionMode(QPainter::CompositionMode_SourceIn); + painter.fillRect(pixmap.rect( ), color); + painter.end( ); + + m_icon->setPixmap(pixmap); + + m_icon->setObjectName("icon"); + + setObjectName("PageNavigator"); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + setStyleSheet(R"( + #PageNavigator{ + border: 4px solid #414141; + border-radius: 6px; + color: #E0E0E0; + } + )"); + + QFont font = m_text->font( ); + font.setPointSize(16); + font.setWeight(QFont::Bold); + m_text->setFont(font); + + QHBoxLayout* layout = new QHBoxLayout(this); + layout->addWidget(m_icon, 0, Qt::AlignLeft); + layout->addWidget(m_text, 1, Qt::AlignLeft); + + connect(this, &QPushButton::clicked, [this, parent]( ) { + SelectHandler* sh = SelectHandler::GetInstance( ); + + sh->setSelected(this); + emit SelectedChanged(this); + }); + + // Little hacky but thats how home is the default + if (text == "Home") { + SelectHandler* sh = SelectHandler::GetInstance( ); + + sh->setSelected(this); + emit SelectedChanged(this); + } +} + +void PageNavigator::unselect( ) { + setStyleSheet(R"( + #PageNavigator{ + border: 4px solid #414141; + border-radius: 6px; + } + )"); +} + +void PageNavigator::select( ) { + setStyleSheet(R"( + #PageNavigator{ + border: 4px solid )" + m_color + R"(; + border-radius: 6px; + } + )"); +} + +QString PageNavigator::GetText( ) { + return m_text->text( ); +} diff --git a/src/Public/Widgets/PageNavigator/PageNavigator.h b/src/View/Widgets/PageNavigator/PageNavigator.h similarity index 50% rename from src/Public/Widgets/PageNavigator/PageNavigator.h rename to src/View/Widgets/PageNavigator/PageNavigator.h index d19d869..63474fc 100644 --- a/src/Public/Widgets/PageNavigator/PageNavigator.h +++ b/src/View/Widgets/PageNavigator/PageNavigator.h @@ -5,16 +5,25 @@ #include #include #include +#include +#include class PageNavigator :public QPushButton { Q_OBJECT private: QLabel* m_text; QLabel* m_icon; + QString m_iconPath; + QString m_color; public: - PageNavigator(QString text, QString icon, QWidget* parent = nullptr); + PageNavigator(QString text, QString icon, QString color, QWidget* parent = nullptr); void unselect( ); void select( ); + + QString GetText( ); + +signals: + void SelectedChanged(PageNavigator* pn); }; diff --git a/src/Public/Widgets/PageNavigator/SelectHandler.hpp b/src/View/Widgets/PageNavigator/SelectHandler.hpp similarity index 95% rename from src/Public/Widgets/PageNavigator/SelectHandler.hpp rename to src/View/Widgets/PageNavigator/SelectHandler.hpp index 3c0a33a..a3933d1 100644 --- a/src/Public/Widgets/PageNavigator/SelectHandler.hpp +++ b/src/View/Widgets/PageNavigator/SelectHandler.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include "PageNavigator.h" /* @@ -40,7 +39,7 @@ void SelectHandler::setSelected(PageNavigator* newSelected) { if (this->selected == nullptr) { this->selected = newSelected; - newSelected->select( ); + selected->select( ); return; } diff --git a/src/core/SongHistory/SongHistory.hpp b/src/core/SongHistory/SongHistory.hpp new file mode 100644 index 0000000..faaa459 --- /dev/null +++ b/src/core/SongHistory/SongHistory.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include + +template +class SongHistory { +private: + struct Node { + T data; + Node* next; + }; + + Node* topNode = nullptr; + +public: + SongHistory( ) { } + ~SongHistory( ) { + while (!isEmpty( )) + pop( ); + } + + void push(const T& value) { + Node* newNode = new Node; + newNode->data = value; + newNode->next = topNode; + topNode = newNode; + } + + void pop( ) { + if (!isEmpty( )) { + Node* tmp = topNode; + topNode = topNode->next; + delete tmp; + } + else + std::cerr << "Stack empty, cannot pop" << std::endl; + } + + T top( ) { + if (!isEmpty( )) + return topNode->data; + else + return nullptr; + } + + bool isEmpty( ) const { return topNode == nullptr; } +}; diff --git a/src/core/SongQueue/ConditionalCircularLinkedList/ConditionalCircularLinkedList.cpp b/src/core/SongQueue/ConditionalCircularLinkedList/ConditionalCircularLinkedList.cpp new file mode 100644 index 0000000..61ecffb --- /dev/null +++ b/src/core/SongQueue/ConditionalCircularLinkedList/ConditionalCircularLinkedList.cpp @@ -0,0 +1,186 @@ +#include "ConditionalCircularLinkedList.h" + +ConditionalCircularLinkedList::ConditionalCircularLinkedList( ) { } + +void ConditionalCircularLinkedList::Append(Song* song) { + Node* newNode = new Node(song); + if (head == nullptr) { + head = newNode; + + // Only link back when its supposed to + if (isLinked) + head->next = head; + + current = head; + } + else { + Node* tmp = head; + + while (tmp->next != head) + tmp = tmp->next; + + tmp->next = newNode; + + // Again make sure to only link when supposed to + if (isLinked) + newNode->next = head; + } +} + +void ConditionalCircularLinkedList::SetListMode(bool isLooping) { + if (head == nullptr) { + std::cout << "WARN: List is empty, cannot set mode" << std::endl; + return; + } + + Node* tmp = head; + while (tmp->next != head) + tmp = tmp->next; + + if (!isLooping) + tmp->next = nullptr; + else + tmp->next = head; +} + +void ConditionalCircularLinkedList::Clear( ) { + while (head != nullptr) { + Node* tmp = head; + head = head->next; + delete tmp; + delete current; + } +} + +void ConditionalCircularLinkedList::Advance( ) { + if (current != nullptr) + current = current->next; +} + +Song* ConditionalCircularLinkedList::GetNext( ) { + if (current != nullptr) + return current->data; +} + +void ConditionalCircularLinkedList::AddSongBefore(Song* newSong, Song* addSongBefore) { + if (head == nullptr) return; + + Node* newNode = new Node(newSong); + + Node* current = head; + Node* prev = nullptr; + + do { + if (current->data == addSongBefore) { + if (prev == nullptr) { + newNode->next = head; + head = newNode; + + Node* lastNode = head; + while (lastNode->next != head) + lastNode = lastNode->next; + + if (isLinked) + lastNode->next = head; + } + else { + prev->next = newNode; + newNode->next = current; + } + return; + } + prev = current; + current = current->next; + + } while (current != head); +} + +void ConditionalCircularLinkedList::AddSongAfter(Song* newSong, Song* addSongAfter) { + if (head == nullptr) return; + + Node* newNode = new Node(newSong); + + Node* current = head; + + do { + if (current->data == addSongAfter) { + newNode->next = current->next; + current->next = newNode; + return; + } + current = current->next; + } while (current != head); + +} + +Song* ConditionalCircularLinkedList::RemoveSong(Song* removeSong) { + if (head == nullptr) return nullptr; + + Node* current = head; + Node* prev = nullptr; + + do { + if (current->data == removeSong) { + if (prev == nullptr) { + head = current->next; + Node* lastNode = head; + while (lastNode->next != current) + lastNode = lastNode->next; + + if (isLinked) + lastNode->next = head; + + Song* deletedSong = current->data; + delete current; + return deletedSong; + } + else { + prev->next = current->next; + + Song* deletedSong = current->data; + delete current; + return deletedSong; + } + } + prev = current; + current = current->next; + } while (current != head); +} + +bool ConditionalCircularLinkedList::IsEmpty( ) { + return current == nullptr; +} + +void ConditionalCircularLinkedList::Shuffle( ) { + int cnt = 0; + Node* tmp = head; + + while (tmp != nullptr) { + cnt++; + tmp = tmp->next; + } + + Node** nodes = new Node * [cnt]; + + tmp = head; + for (int i = 0; i < cnt; i++) { + nodes[i] = tmp; + tmp = tmp->next; + } + + for (int i = cnt; i > 0; i--) { + int j = rand( ) % (i + 1); + + Node* tmp = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = tmp; + } + + head = nodes[0]; + for (int i = 0; i < cnt - 1; i++) + nodes[i]->next = nodes[i + 1]; + + nodes[cnt - 1]->next = nullptr; + + delete[] nodes; +} diff --git a/src/core/SongQueue/ConditionalCircularLinkedList/ConditionalCircularLinkedList.h b/src/core/SongQueue/ConditionalCircularLinkedList/ConditionalCircularLinkedList.h new file mode 100644 index 0000000..98ba4d4 --- /dev/null +++ b/src/core/SongQueue/ConditionalCircularLinkedList/ConditionalCircularLinkedList.h @@ -0,0 +1,72 @@ +#pragma once + +#include + +#include "../../song/song.h" + +class ConditionalCircularLinkedList { +private: + + struct Node { + Node* next; + Song* data; + + Node(Song* song) : data(song), next(nullptr) { } + }; + + Node* head; + + // Variable to keep the current position that we seek + Node* current; + + // Variable to either link or unlink the list + bool isLinked; +public: + ConditionalCircularLinkedList( ); + ConditionalCircularLinkedList(bool isLinked) : head(nullptr), isLinked(isLinked) { } + + /** + * @brief Append a new song to the queue + * + * @param song + */ + void Append(Song* song); + + /** + * @brief Clear the entire list so its brand spanking new. + * + */ + void Clear( ); + + /** + * @brief Depending on if the queue is supposed to be looping, this will link + * up the end of the list, with its beginning to its a circular list. + * If its not supposed to loop then we break the link and it will be a normal list. + * @param isLooping Will set the list to circular or normal mode + */ + void SetListMode(bool isLooping); + + /** + * @brief Advance the circular list by one, this means setting the "current" pointer + * to the next element + * + */ + void Advance( ); + + /** + * @brief Get the "current" pointer's data + * + * @return Song* + */ + Song* GetNext( ); + + void AddSongBefore(Song* newSong, Song* addSongBefore); + + void AddSongAfter(Song* newSong, Song* addSongAfter); + + Song* RemoveSong(Song* removeSong); + + bool IsEmpty( ); + + void Shuffle( ); +}; diff --git a/src/core/SongQueue/SongQueue.cpp b/src/core/SongQueue/SongQueue.cpp new file mode 100644 index 0000000..1f0a0e9 --- /dev/null +++ b/src/core/SongQueue/SongQueue.cpp @@ -0,0 +1,94 @@ +#include "SongQueue.h" + +SongQueue::SongQueue( ) { + queue = new ConditionalCircularLinkedList( ); + + // Its never going to be linked, I'm just too lazy to make a new implementation thats almost the same + priorityQueue = new ConditionalCircularLinkedList(false); +} + +SongQueue::~SongQueue( ) { } + +void SongQueue::PopulateQueue(const std::list& songList) { + for (Song* song : songList) { + queue->Append(song); + } +} + +void SongQueue::Next( ) { + if (priorityQueue->IsEmpty( )) { + topSong = queue->GetNext( ); + queue->Advance( ); + + return; + } + + topSong = priorityQueue->GetNext( ); + priorityQueue->Advance( ); +} + +void SongQueue::JumpToSong(Song* song, bool fromPrioQueue) { + if (fromPrioQueue) { + if (priorityQueue->IsEmpty( )) + return; + + while (priorityQueue->GetNext( ) != song) { + priorityQueue->Advance( ); + topSong = song; + } + } + + if (queue->IsEmpty( )) + return; + + while (queue->GetNext( ) != song) { + queue->Advance( ); + topSong = song; + } +} + +void SongQueue::AddToPriorityQueue(Song* song) { + priorityQueue->Append(song); +} + +bool SongQueue::IsEmpty( ) { + return queue->IsEmpty( ) && priorityQueue->IsEmpty( ); +} + +Song* SongQueue::Top( ) { return topSong; } + +void SongQueue::SetTop(Song* song) { topSong = song; } + +void SongQueue::RemoveSongFromPriorityQueue(Song* song) { + if (priorityQueue->IsEmpty( )) + return; + + priorityQueue->RemoveSong(song); +} + +void SongQueue::MoveSongInPriorityQueue(Song* songToMove, Song* otherSong, bool beforeElseAfter) { + if (priorityQueue->IsEmpty( )) + return; + + if (beforeElseAfter) + priorityQueue->AddSongBefore(songToMove, otherSong); + else + priorityQueue->AddSongAfter(songToMove, otherSong); +} + +void SongQueue::ShufflePlaylist( ) { + //First backup the original list state + queue_original = new ConditionalCircularLinkedList(queue); + + queue->Shuffle( ); +} + +void SongQueue::RestorePlaylist( ) { + if (queue_original == nullptr) return; + + queue = new ConditionalCircularLinkedList(queue_original); +} + +void SongQueue::LinkQueue(bool link) { + queue->SetListMode(link); +} diff --git a/src/core/SongQueue/SongQueue.h b/src/core/SongQueue/SongQueue.h new file mode 100644 index 0000000..9522d51 --- /dev/null +++ b/src/core/SongQueue/SongQueue.h @@ -0,0 +1,61 @@ +#pragma once + +#include +#include + +#include "../song/song.h" +#include "ConditionalCircularLinkedList/ConditionalCircularLinkedList.h" + +class SongQueue { +private: + + // The currently playing song + Song* topSong; + + //Regular song queue, can be unlinked for non looping playlists + ConditionalCircularLinkedList* queue; + //Copy of queue to faster restore when unshuffling + ConditionalCircularLinkedList* queue_original; + + //The name is confusing, but its because the queue itself has priority over the normal one + ConditionalCircularLinkedList* priorityQueue; + + void setQueue( ); +public: + SongQueue( ); + ~SongQueue( ); + + void PopulateQueue(const std::list& songlist); + + /** + * @brief Will put the next song from the correct sublist as the topSong. + * This will also remove the song from the queue as its not needed anymore. + * + */ + void Next( ); + + /** + * @brief Will put the given song from the priority or normal queue as the top song and remove it + * from the list + * + * @param song + */ + void JumpToSong(Song* song, bool fromPrioQueue); + + void AddToPriorityQueue(Song* song); + + bool IsEmpty( ); + + Song* Top( ); + + void SetTop(Song* song); + + void RemoveSongFromPriorityQueue(Song* song); + + void MoveSongInPriorityQueue(Song* songToMove, Song* otherSong, bool beforeElseAfter); + + void ShufflePlaylist( ); + void RestorePlaylist( ); + + void LinkQueue(bool link); +}; diff --git a/src/core/audio/audio.cpp b/src/core/audio/audio.cpp index 8daf5cf..d95646c 100644 --- a/src/core/audio/audio.cpp +++ b/src/core/audio/audio.cpp @@ -1,6 +1,6 @@ #include "audio.h" -Audio::Audio(const std::string path) :path(path) { +Audio::Audio( ) { if (SDL_Init(SDL_INIT_AUDIO) < 0) { std::cerr << "SDL initialization failed: " << SDL_GetError( ) << std::endl; return; @@ -11,14 +11,6 @@ Audio::Audio(const std::string path) :path(path) { SDL_Quit( ); return; } - - music = Mix_LoadMUS(path.c_str( )); - if (!music) { - std::cerr << "Failed to load MP3 file: " << Mix_GetError( ) << std::endl; - Mix_CloseAudio( ); - SDL_Quit( ); - return; - } }; Audio::~Audio( ) { @@ -34,6 +26,22 @@ void Audio::StartMusic( ) { } } +void Audio::StopMusic( ) { + Mix_HaltMusic( ); +} + +void Audio::PlaySong(const std::string path) { + this->path = path; + + music = Mix_LoadMUS(path.c_str( )); + if (!music) { + std::cerr << "Failed to load MP3 file: " << Mix_GetError( ) << std::endl; + Mix_CloseAudio( ); + SDL_Quit( ); + return; + } +} + void Audio::PauseMusic( ) { if (Mix_PlayingMusic( ) == 1) { Mix_PauseMusic( ); diff --git a/src/core/audio/audio.h b/src/core/audio/audio.h index ff78741..d203c96 100644 --- a/src/core/audio/audio.h +++ b/src/core/audio/audio.h @@ -14,16 +14,16 @@ extern "C" { class Audio { public: - static Audio& getInstance(const std::string path) { - static Audio instance(path); + static Audio& getInstance( ) { + static Audio instance; return instance; } private: - Audio(const std::string path); + Audio( ); - const std::string path; - const std::string artist; - const std::string album; + std::string path; + std::string artist; + std::string album; Mix_Music* music; @@ -43,6 +43,9 @@ public: QPixmap GetAlbumCover( ); + void PlaySong(const std::string path); + + void StopMusic( ); void StartMusic( ); void PauseMusic( ); void ResumeMusic( ); diff --git a/src/core/song/song.cpp b/src/core/song/song.cpp new file mode 100644 index 0000000..2718dd6 --- /dev/null +++ b/src/core/song/song.cpp @@ -0,0 +1,36 @@ +#include "song.h" + +Song::Song( + std::string title, + std::string album, + std::string artist, + std::string codec, + std::string comment, + std::string copyright, + std::string publisher, + std::string genre, + std::string encoded_by, + std::string date, + std::string language, + std::string albumCoverPath, + std::string path, + int length, + std::string discoveredPath +) : title(title), +album(album), +artist(artist), +codec(codec), +comment(comment), +copyright(copyright), +publisher(publisher), +genre(genre), +encoded_by(encoded_by), +date(date), +language(language), +albumCoverPath(albumCoverPath), +path(path), +length(length) { + +} + +Song::~Song( ) { } diff --git a/src/core/song/song.h b/src/core/song/song.h new file mode 100644 index 0000000..f4d095e --- /dev/null +++ b/src/core/song/song.h @@ -0,0 +1,54 @@ +#pragma once + +#include + +class Song { +private: + // Song information + const std::string& title; + const std::string& album; + const std::string& artist; + const std::string& codec; + const std::string& comment; + const std::string& copyright; + const std::string& publisher; + const std::string& genre; + const std::string& encoded_by; + const std::string& date; + const std::string& language; + const std::string& albumCoverPath; + const std::string& path; + const int& length; + + // Our own Metadata + bool favorite = false; + int playCount = 0; + std::string discovered; + +public: + Song( + std::string title, + std::string album, + std::string artist, + std::string codec, + std::string comment, + std::string copyright, + std::string publisher, + std::string genre, + std::string encoded_by, + std::string date, + std::string language, + std::string albumCoverPath, + std::string path, + int length, + std::string discoveredPath + ); + ~Song( ); + + void SetFavorite(bool fav) { favorite = fav; } + + void IncrementPlayCount( ) { playCount++; } + + std::string GetPath( ) { return path; }; + +}; diff --git a/src/main.cpp b/src/main.cpp index cb8fb12..7bf1749 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,4 @@ -#include "Public/MainWindow.h" +#include "View/MainWindow.h" #include #include