chore: tidy code and hello 2025 :)
This commit is contained in:
		| @ -678,7 +678,7 @@ void MainWindow::on_actionHelp_triggered() | ||||
|         "\n" | ||||
|         "[Source Code](https://github.com/BLumia/pineapple-music)\n" | ||||
|         "\n" | ||||
|         "Copyright © 2024 [BLumia](https://github.com/BLumia/)" | ||||
|         "Copyright © 2025 [BLumia](https://github.com/BLumia/)" | ||||
|         ); | ||||
|     infoBox.setTextFormat(Qt::MarkdownText); | ||||
|     infoBox.exec(); | ||||
|  | ||||
| @ -1,255 +1,253 @@ | ||||
| // SPDX-FileCopyrightText: 2024 Gary Wang <git@blumia.net> | ||||
| // | ||||
| // SPDX-License-Identifier: MIT | ||||
|  | ||||
| #include "playlistmanager.h" | ||||
|  | ||||
| #include <QCollator> | ||||
| #include <QDir> | ||||
| #include <QFileInfo> | ||||
| #include <QUrl> | ||||
|  | ||||
| PlaylistModel::PlaylistModel(QObject *parent) | ||||
|     : QAbstractListModel(parent) | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| PlaylistModel::~PlaylistModel() | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| void PlaylistModel::setPlaylist(const QList<QUrl> &urls) | ||||
| { | ||||
|     beginResetModel(); | ||||
|     m_playlist = urls; | ||||
|     endResetModel(); | ||||
| } | ||||
|  | ||||
| QModelIndex PlaylistModel::loadPlaylist(const QList<QUrl> & urls) | ||||
| { | ||||
|     if (urls.isEmpty()) return QModelIndex(); | ||||
|     if (urls.count() == 1) { | ||||
|         return loadPlaylist(urls.constFirst()); | ||||
|     } else { | ||||
|         setPlaylist(urls); | ||||
|         return index(0); | ||||
|     } | ||||
| } | ||||
|  | ||||
| QModelIndex PlaylistModel::loadPlaylist(const QUrl &url) | ||||
| { | ||||
|     QFileInfo info(url.toLocalFile()); | ||||
|     QDir dir(info.path()); | ||||
|     QString && currentFileName = info.fileName(); | ||||
|  | ||||
|     if (dir.path() == m_currentDir) { | ||||
|         int idx = indexOf(url); | ||||
|         return idx == -1 ? appendToPlaylist(url) : index(idx); | ||||
|     } | ||||
|  | ||||
|     QStringList entryList = dir.entryList( | ||||
|         m_autoLoadSuffixes, | ||||
|         QDir::Files | QDir::NoSymLinks, QDir::NoSort); | ||||
|  | ||||
|     QCollator collator; | ||||
|     collator.setNumericMode(true); | ||||
|  | ||||
|     std::sort(entryList.begin(), entryList.end(), collator); | ||||
|  | ||||
|     QList<QUrl> playlist; | ||||
|  | ||||
|     int idx = -1; | ||||
|     for (int i = 0; i < entryList.count(); i++) { | ||||
|         const QString & fileName = entryList.at(i); | ||||
|         const QString & oneEntry = dir.absoluteFilePath(fileName); | ||||
|         const QUrl & url = QUrl::fromLocalFile(oneEntry); | ||||
|         playlist.append(url); | ||||
|         if (fileName == currentFileName) { | ||||
|             idx = i; | ||||
|         } | ||||
|     } | ||||
|     if (idx == -1) { | ||||
|         idx = playlist.count(); | ||||
|         playlist.append(url); | ||||
|     } | ||||
|     m_currentDir = dir.path(); | ||||
|  | ||||
|     setPlaylist(playlist); | ||||
|  | ||||
|     return index(idx); | ||||
| } | ||||
|  | ||||
| QModelIndex PlaylistModel::appendToPlaylist(const QUrl &url) | ||||
| { | ||||
|     const int lastIndex = rowCount(); | ||||
|     beginInsertRows(QModelIndex(), lastIndex, lastIndex); | ||||
|     m_playlist.append(url); | ||||
|     endInsertRows(); | ||||
|     return index(lastIndex); | ||||
| } | ||||
|  | ||||
| bool PlaylistModel::removeAt(int index) | ||||
| { | ||||
|     if (index < 0 || index >= rowCount()) return false; | ||||
|     beginRemoveRows(QModelIndex(), index, index); | ||||
|     m_playlist.removeAt(index); | ||||
|     endRemoveRows(); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| int PlaylistModel::indexOf(const QUrl &url) const | ||||
| { | ||||
|     return m_playlist.indexOf(url); | ||||
| } | ||||
|  | ||||
| QUrl PlaylistModel::urlByIndex(int index) const | ||||
| { | ||||
|     return m_playlist.value(index); | ||||
| } | ||||
|  | ||||
| QStringList PlaylistModel::autoLoadFilterSuffixes() const | ||||
| { | ||||
|     return m_autoLoadSuffixes; | ||||
| } | ||||
|  | ||||
| QHash<int, QByteArray> PlaylistModel::roleNames() const | ||||
| { | ||||
|     QHash<int, QByteArray> result = QAbstractListModel::roleNames(); | ||||
|     result.insert(UrlRole, "url"); | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| int PlaylistModel::rowCount(const QModelIndex &parent) const | ||||
| { | ||||
|     return m_playlist.count(); | ||||
| } | ||||
|  | ||||
| QVariant PlaylistModel::data(const QModelIndex &index, int role) const | ||||
| { | ||||
|     if (!index.isValid()) return QVariant(); | ||||
|  | ||||
|     switch (role) { | ||||
|     case Qt::DisplayRole: | ||||
|         return m_playlist.at(index.row()).fileName(); | ||||
|     case UrlRole: | ||||
|         return m_playlist.at(index.row()); | ||||
|     } | ||||
|  | ||||
|     return QVariant(); | ||||
| } | ||||
|  | ||||
| PlaylistManager::PlaylistManager(QObject *parent) | ||||
|     : QObject(parent) | ||||
| { | ||||
|     connect(&m_model, &PlaylistModel::rowsRemoved, this, | ||||
|             [this](const QModelIndex &, int, int) { | ||||
|                 if (m_model.rowCount() <= m_currentIndex) { | ||||
|                     setProperty("currentIndex", m_currentIndex - 1); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|     auto onRowCountChanged = [this](){ | ||||
|         emit totalCountChanged(m_model.rowCount()); | ||||
|     }; | ||||
|  | ||||
|     connect(&m_model, &PlaylistModel::rowsInserted, this, onRowCountChanged); | ||||
|     connect(&m_model, &PlaylistModel::rowsRemoved, this, onRowCountChanged); | ||||
|     connect(&m_model, &PlaylistModel::modelReset, this, onRowCountChanged); | ||||
| } | ||||
|  | ||||
| PlaylistManager::~PlaylistManager() | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| PlaylistModel *PlaylistManager::model() | ||||
| { | ||||
|     return &m_model; | ||||
| } | ||||
|  | ||||
| void PlaylistManager::setPlaylist(const QList<QUrl> &urls) | ||||
| { | ||||
|     m_model.setPlaylist(urls); | ||||
| } | ||||
|  | ||||
| QModelIndex PlaylistManager::loadPlaylist(const QList<QUrl> &urls) | ||||
| { | ||||
|     QModelIndex idx = m_model.loadPlaylist(urls); | ||||
|     setProperty("currentIndex", idx.row()); | ||||
|     return idx; | ||||
| } | ||||
|  | ||||
| QModelIndex PlaylistManager::loadPlaylist(const QUrl &url) | ||||
| { | ||||
|     QModelIndex idx = m_model.loadPlaylist(url); | ||||
|     setProperty("currentIndex", idx.row()); | ||||
|     return idx; | ||||
| } | ||||
|  | ||||
| int PlaylistManager::totalCount() const | ||||
| { | ||||
|     return m_model.rowCount(); | ||||
| } | ||||
|  | ||||
| QModelIndex PlaylistManager::previousIndex() const | ||||
| { | ||||
|     int count = totalCount(); | ||||
|     if (count == 0) return QModelIndex(); | ||||
|  | ||||
|     return m_model.index(m_currentIndex - 1 < 0 ? count - 1 : m_currentIndex - 1); | ||||
| } | ||||
|  | ||||
| QModelIndex PlaylistManager::nextIndex() const | ||||
| { | ||||
|     int count = totalCount(); | ||||
|     if (count == 0) return QModelIndex(); | ||||
|  | ||||
|     return m_model.index(m_currentIndex + 1 == count ? 0 : m_currentIndex + 1); | ||||
| } | ||||
|  | ||||
| QModelIndex PlaylistManager::curIndex() const | ||||
| { | ||||
|     return m_model.index(m_currentIndex); | ||||
| } | ||||
|  | ||||
| void PlaylistManager::setCurrentIndex(const QModelIndex &index) | ||||
| { | ||||
|     if (index.isValid() && index.row() >= 0 && index.row() < totalCount()) { | ||||
|         setProperty("currentIndex", index.row()); | ||||
|     } | ||||
| } | ||||
|  | ||||
| QUrl PlaylistManager::urlByIndex(const QModelIndex &index) | ||||
| { | ||||
|     return m_model.urlByIndex(index.row()); | ||||
| } | ||||
|  | ||||
| QString PlaylistManager::localFileByIndex(const QModelIndex &index) | ||||
| { | ||||
|     return urlByIndex(index).toLocalFile(); | ||||
| } | ||||
|  | ||||
| bool PlaylistManager::removeAt(const QModelIndex &index) | ||||
| { | ||||
|     return m_model.removeAt(index.row()); | ||||
| } | ||||
|  | ||||
| void PlaylistManager::setAutoLoadFilterSuffixes(const QStringList &nameFilters) | ||||
| { | ||||
|     m_model.setProperty("autoLoadFilterSuffixes", nameFilters); | ||||
| } | ||||
|  | ||||
| QList<QUrl> PlaylistManager::convertToUrlList(const QStringList &files) | ||||
| { | ||||
|     QList<QUrl> urlList; | ||||
|     for (const QString & str : std::as_const(files)) { | ||||
|         QUrl url = QUrl::fromLocalFile(str); | ||||
|         if (url.isValid()) { | ||||
|             urlList.append(url); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return urlList; | ||||
| } | ||||
| // SPDX-FileCopyrightText: 2025 Gary Wang <git@blumia.net> | ||||
| // | ||||
| // SPDX-License-Identifier: MIT | ||||
|  | ||||
| #include "playlistmanager.h" | ||||
|  | ||||
| #include <QCollator> | ||||
| #include <QDir> | ||||
| #include <QFileInfo> | ||||
| #include <QUrl> | ||||
|  | ||||
| PlaylistModel::PlaylistModel(QObject *parent) | ||||
|     : QAbstractListModel(parent) | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| PlaylistModel::~PlaylistModel() | ||||
| = default; | ||||
|  | ||||
| void PlaylistModel::setPlaylist(const QList<QUrl> &urls) | ||||
| { | ||||
|     beginResetModel(); | ||||
|     m_playlist = urls; | ||||
|     endResetModel(); | ||||
| } | ||||
|  | ||||
| QModelIndex PlaylistModel::loadPlaylist(const QList<QUrl> & urls) | ||||
| { | ||||
|     if (urls.isEmpty()) return {}; | ||||
|     if (urls.count() == 1) { | ||||
|         return loadPlaylist(urls.constFirst()); | ||||
|     } else { | ||||
|         setPlaylist(urls); | ||||
|         return index(0); | ||||
|     } | ||||
| } | ||||
|  | ||||
| QModelIndex PlaylistModel::loadPlaylist(const QUrl &url) | ||||
| { | ||||
|     QFileInfo info(url.toLocalFile()); | ||||
|     QDir dir(info.path()); | ||||
|     QString && currentFileName = info.fileName(); | ||||
|  | ||||
|     if (dir.path() == m_currentDir) { | ||||
|         int idx = indexOf(url); | ||||
|         return idx == -1 ? appendToPlaylist(url) : index(idx); | ||||
|     } | ||||
|  | ||||
|     QStringList entryList = dir.entryList( | ||||
|         m_autoLoadSuffixes, | ||||
|         QDir::Files | QDir::NoSymLinks, QDir::NoSort); | ||||
|  | ||||
|     QCollator collator; | ||||
|     collator.setNumericMode(true); | ||||
|  | ||||
|     std::sort(entryList.begin(), entryList.end(), collator); | ||||
|  | ||||
|     QList<QUrl> playlist; | ||||
|  | ||||
|     int idx = -1; | ||||
|     for (int i = 0; i < entryList.count(); i++) { | ||||
|         const QString & fileName = entryList.at(i); | ||||
|         const QString & oneEntry = dir.absoluteFilePath(fileName); | ||||
|         const QUrl & url = QUrl::fromLocalFile(oneEntry); | ||||
|         playlist.append(url); | ||||
|         if (fileName == currentFileName) { | ||||
|             idx = i; | ||||
|         } | ||||
|     } | ||||
|     if (idx == -1) { | ||||
|         idx = playlist.count(); | ||||
|         playlist.append(url); | ||||
|     } | ||||
|     m_currentDir = dir.path(); | ||||
|  | ||||
|     setPlaylist(playlist); | ||||
|  | ||||
|     return index(idx); | ||||
| } | ||||
|  | ||||
| QModelIndex PlaylistModel::appendToPlaylist(const QUrl &url) | ||||
| { | ||||
|     const int lastIndex = rowCount(); | ||||
|     beginInsertRows(QModelIndex(), lastIndex, lastIndex); | ||||
|     m_playlist.append(url); | ||||
|     endInsertRows(); | ||||
|     return index(lastIndex); | ||||
| } | ||||
|  | ||||
| bool PlaylistModel::removeAt(int index) | ||||
| { | ||||
|     if (index < 0 || index >= rowCount()) return false; | ||||
|     beginRemoveRows(QModelIndex(), index, index); | ||||
|     m_playlist.removeAt(index); | ||||
|     endRemoveRows(); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| int PlaylistModel::indexOf(const QUrl &url) const | ||||
| { | ||||
|     return m_playlist.indexOf(url); | ||||
| } | ||||
|  | ||||
| QUrl PlaylistModel::urlByIndex(int index) const | ||||
| { | ||||
|     return m_playlist.value(index); | ||||
| } | ||||
|  | ||||
| QStringList PlaylistModel::autoLoadFilterSuffixes() const | ||||
| { | ||||
|     return m_autoLoadSuffixes; | ||||
| } | ||||
|  | ||||
| QHash<int, QByteArray> PlaylistModel::roleNames() const | ||||
| { | ||||
|     QHash<int, QByteArray> result = QAbstractListModel::roleNames(); | ||||
|     result.insert(UrlRole, "url"); | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| int PlaylistModel::rowCount(const QModelIndex &parent) const | ||||
| { | ||||
|     return m_playlist.count(); | ||||
| } | ||||
|  | ||||
| QVariant PlaylistModel::data(const QModelIndex &index, int role) const | ||||
| { | ||||
|     if (!index.isValid()) return {}; | ||||
|  | ||||
|     switch (role) { | ||||
|     case Qt::DisplayRole: | ||||
|         return m_playlist.at(index.row()).fileName(); | ||||
|     case UrlRole: | ||||
|         return m_playlist.at(index.row()); | ||||
|     } | ||||
|  | ||||
|     return {}; | ||||
| } | ||||
|  | ||||
| PlaylistManager::PlaylistManager(QObject *parent) | ||||
|     : QObject(parent) | ||||
| { | ||||
|     connect(&m_model, &PlaylistModel::rowsRemoved, this, | ||||
|             [this](const QModelIndex &, int, int) { | ||||
|                 if (m_model.rowCount() <= m_currentIndex) { | ||||
|                     setProperty("currentIndex", m_currentIndex - 1); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|     auto onRowCountChanged = [this](){ | ||||
|         emit totalCountChanged(m_model.rowCount()); | ||||
|     }; | ||||
|  | ||||
|     connect(&m_model, &PlaylistModel::rowsInserted, this, onRowCountChanged); | ||||
|     connect(&m_model, &PlaylistModel::rowsRemoved, this, onRowCountChanged); | ||||
|     connect(&m_model, &PlaylistModel::modelReset, this, onRowCountChanged); | ||||
| } | ||||
|  | ||||
| PlaylistManager::~PlaylistManager() | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| PlaylistModel *PlaylistManager::model() | ||||
| { | ||||
|     return &m_model; | ||||
| } | ||||
|  | ||||
| void PlaylistManager::setPlaylist(const QList<QUrl> &urls) | ||||
| { | ||||
|     m_model.setPlaylist(urls); | ||||
| } | ||||
|  | ||||
| QModelIndex PlaylistManager::loadPlaylist(const QList<QUrl> &urls) | ||||
| { | ||||
|     QModelIndex idx = m_model.loadPlaylist(urls); | ||||
|     setProperty("currentIndex", idx.row()); | ||||
|     return idx; | ||||
| } | ||||
|  | ||||
| QModelIndex PlaylistManager::loadPlaylist(const QUrl &url) | ||||
| { | ||||
|     QModelIndex idx = m_model.loadPlaylist(url); | ||||
|     setProperty("currentIndex", idx.row()); | ||||
|     return idx; | ||||
| } | ||||
|  | ||||
| int PlaylistManager::totalCount() const | ||||
| { | ||||
|     return m_model.rowCount(); | ||||
| } | ||||
|  | ||||
| QModelIndex PlaylistManager::previousIndex() const | ||||
| { | ||||
|     int count = totalCount(); | ||||
|     if (count == 0) return {}; | ||||
|  | ||||
|     return m_model.index(m_currentIndex - 1 < 0 ? count - 1 : m_currentIndex - 1); | ||||
| } | ||||
|  | ||||
| QModelIndex PlaylistManager::nextIndex() const | ||||
| { | ||||
|     int count = totalCount(); | ||||
|     if (count == 0) return {}; | ||||
|  | ||||
|     return m_model.index(m_currentIndex + 1 == count ? 0 : m_currentIndex + 1); | ||||
| } | ||||
|  | ||||
| QModelIndex PlaylistManager::curIndex() const | ||||
| { | ||||
|     return m_model.index(m_currentIndex); | ||||
| } | ||||
|  | ||||
| void PlaylistManager::setCurrentIndex(const QModelIndex &index) | ||||
| { | ||||
|     if (index.isValid() && index.row() >= 0 && index.row() < totalCount()) { | ||||
|         setProperty("currentIndex", index.row()); | ||||
|     } | ||||
| } | ||||
|  | ||||
| QUrl PlaylistManager::urlByIndex(const QModelIndex &index) | ||||
| { | ||||
|     return m_model.urlByIndex(index.row()); | ||||
| } | ||||
|  | ||||
| QString PlaylistManager::localFileByIndex(const QModelIndex &index) | ||||
| { | ||||
|     return urlByIndex(index).toLocalFile(); | ||||
| } | ||||
|  | ||||
| bool PlaylistManager::removeAt(const QModelIndex &index) | ||||
| { | ||||
|     return m_model.removeAt(index.row()); | ||||
| } | ||||
|  | ||||
| void PlaylistManager::setAutoLoadFilterSuffixes(const QStringList &nameFilters) | ||||
| { | ||||
|     m_model.setProperty("autoLoadFilterSuffixes", nameFilters); | ||||
| } | ||||
|  | ||||
| QList<QUrl> PlaylistManager::convertToUrlList(const QStringList &files) | ||||
| { | ||||
|     QList<QUrl> urlList; | ||||
|     for (const QString & str : std::as_const(files)) { | ||||
|         QUrl url = QUrl::fromLocalFile(str); | ||||
|         if (url.isValid()) { | ||||
|             urlList.append(url); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return urlList; | ||||
| } | ||||
|  | ||||
| @ -1,85 +1,85 @@ | ||||
| // SPDX-FileCopyrightText: 2024 Gary Wang <git@blumia.net> | ||||
| // | ||||
| // SPDX-License-Identifier: MIT | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <QUrl> | ||||
| #include <QAbstractListModel> | ||||
|  | ||||
| class PlaylistModel : public QAbstractListModel | ||||
| { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     enum PlaylistRole { | ||||
|         UrlRole = Qt::UserRole | ||||
|     }; | ||||
|     Q_ENUM(PlaylistRole) | ||||
|     Q_PROPERTY(QStringList autoLoadFilterSuffixes MEMBER m_autoLoadSuffixes NOTIFY autoLoadFilterSuffixesChanged) | ||||
|  | ||||
|     explicit PlaylistModel(QObject *parent = nullptr); | ||||
|     ~PlaylistModel(); | ||||
|  | ||||
|     void setPlaylist(const QList<QUrl> & urls); | ||||
|     QModelIndex loadPlaylist(const QList<QUrl> & urls); | ||||
|     QModelIndex loadPlaylist(const QUrl & url); | ||||
|     QModelIndex appendToPlaylist(const QUrl & url); | ||||
|     bool removeAt(int index); | ||||
|     int indexOf(const QUrl & url) const; | ||||
|     QUrl urlByIndex(int index) const; | ||||
|     QStringList autoLoadFilterSuffixes() const; | ||||
|  | ||||
|     QHash<int, QByteArray> roleNames() const override; | ||||
|     int rowCount(const QModelIndex &parent = QModelIndex()) const override; | ||||
|     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; | ||||
|  | ||||
| signals: | ||||
|     void autoLoadFilterSuffixesChanged(QStringList suffixes); | ||||
|  | ||||
| private: | ||||
|     // model data | ||||
|     QList<QUrl> m_playlist; | ||||
|     // properties | ||||
|     QStringList m_autoLoadSuffixes = {}; | ||||
|     // internal | ||||
|     QString m_currentDir; | ||||
| }; | ||||
|  | ||||
| class PlaylistManager : public QObject | ||||
| { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     Q_PROPERTY(int currentIndex MEMBER m_currentIndex NOTIFY currentIndexChanged) | ||||
|     Q_PROPERTY(QStringList autoLoadFilterSuffixes WRITE setAutoLoadFilterSuffixes) | ||||
|     Q_PROPERTY(PlaylistModel * model READ model CONSTANT) | ||||
|  | ||||
|     explicit PlaylistManager(QObject *parent = nullptr); | ||||
|     ~PlaylistManager(); | ||||
|  | ||||
|     PlaylistModel * model(); | ||||
|  | ||||
|     void setPlaylist(const QList<QUrl> & url); | ||||
|     Q_INVOKABLE QModelIndex loadPlaylist(const QList<QUrl> & urls); | ||||
|     Q_INVOKABLE QModelIndex loadPlaylist(const QUrl & url); | ||||
|  | ||||
|     int totalCount() const; | ||||
|     QModelIndex previousIndex() const; | ||||
|     QModelIndex nextIndex() const; | ||||
|     QModelIndex curIndex() const; | ||||
|     void setCurrentIndex(const QModelIndex & index); | ||||
|     QUrl urlByIndex(const QModelIndex & index); | ||||
|     QString localFileByIndex(const QModelIndex & index); | ||||
|     bool removeAt(const QModelIndex & index); | ||||
|  | ||||
|     void setAutoLoadFilterSuffixes(const QStringList &nameFilters); | ||||
|  | ||||
|     static QList<QUrl> convertToUrlList(const QStringList & files); | ||||
|  | ||||
| signals: | ||||
|     void currentIndexChanged(int index); | ||||
|     void totalCountChanged(int count); | ||||
|  | ||||
| private: | ||||
|     int m_currentIndex = -1; | ||||
|     PlaylistModel m_model; | ||||
| }; | ||||
| // SPDX-FileCopyrightText: 2025 Gary Wang <git@blumia.net> | ||||
| // | ||||
| // SPDX-License-Identifier: MIT | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <QUrl> | ||||
| #include <QAbstractListModel> | ||||
|  | ||||
| class PlaylistModel : public QAbstractListModel | ||||
| { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     enum PlaylistRole { | ||||
|         UrlRole = Qt::UserRole | ||||
|     }; | ||||
|     Q_ENUM(PlaylistRole) | ||||
|     Q_PROPERTY(QStringList autoLoadFilterSuffixes MEMBER m_autoLoadSuffixes NOTIFY autoLoadFilterSuffixesChanged) | ||||
|  | ||||
|     explicit PlaylistModel(QObject *parent = nullptr); | ||||
|     ~PlaylistModel() override; | ||||
|  | ||||
|     void setPlaylist(const QList<QUrl> & urls); | ||||
|     QModelIndex loadPlaylist(const QList<QUrl> & urls); | ||||
|     QModelIndex loadPlaylist(const QUrl & url); | ||||
|     QModelIndex appendToPlaylist(const QUrl & url); | ||||
|     bool removeAt(int index); | ||||
|     int indexOf(const QUrl & url) const; | ||||
|     QUrl urlByIndex(int index) const; | ||||
|     QStringList autoLoadFilterSuffixes() const; | ||||
|  | ||||
|     QHash<int, QByteArray> roleNames() const override; | ||||
|     int rowCount(const QModelIndex &parent = QModelIndex()) const override; | ||||
|     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; | ||||
|  | ||||
| signals: | ||||
|     void autoLoadFilterSuffixesChanged(QStringList suffixes); | ||||
|  | ||||
| private: | ||||
|     // model data | ||||
|     QList<QUrl> m_playlist; | ||||
|     // properties | ||||
|     QStringList m_autoLoadSuffixes = {}; | ||||
|     // internal | ||||
|     QString m_currentDir; | ||||
| }; | ||||
|  | ||||
| class PlaylistManager : public QObject | ||||
| { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     Q_PROPERTY(int currentIndex MEMBER m_currentIndex NOTIFY currentIndexChanged) | ||||
|     Q_PROPERTY(QStringList autoLoadFilterSuffixes WRITE setAutoLoadFilterSuffixes) | ||||
|     Q_PROPERTY(PlaylistModel * model READ model CONSTANT) | ||||
|  | ||||
|     explicit PlaylistManager(QObject *parent = nullptr); | ||||
|     ~PlaylistManager(); | ||||
|  | ||||
|     PlaylistModel * model(); | ||||
|  | ||||
|     void setPlaylist(const QList<QUrl> & url); | ||||
|     Q_INVOKABLE QModelIndex loadPlaylist(const QList<QUrl> & urls); | ||||
|     Q_INVOKABLE QModelIndex loadPlaylist(const QUrl & url); | ||||
|  | ||||
|     int totalCount() const; | ||||
|     QModelIndex previousIndex() const; | ||||
|     QModelIndex nextIndex() const; | ||||
|     QModelIndex curIndex() const; | ||||
|     void setCurrentIndex(const QModelIndex & index); | ||||
|     QUrl urlByIndex(const QModelIndex & index); | ||||
|     QString localFileByIndex(const QModelIndex & index); | ||||
|     bool removeAt(const QModelIndex & index); | ||||
|  | ||||
|     void setAutoLoadFilterSuffixes(const QStringList &nameFilters); | ||||
|  | ||||
|     static QList<QUrl> convertToUrlList(const QStringList & files); | ||||
|  | ||||
| signals: | ||||
|     void currentIndexChanged(int index); | ||||
|     void totalCountChanged(int count); | ||||
|  | ||||
| private: | ||||
|     int m_currentIndex = -1; | ||||
|     PlaylistModel m_model; | ||||
| }; | ||||
|  | ||||
| @ -1,24 +1,24 @@ | ||||
| // SPDX-FileCopyrightText: 2024 Gary Wang <git@blumia.net> | ||||
| // | ||||
| // SPDX-License-Identifier: MIT | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <QSlider> | ||||
| #include <QMouseEvent> | ||||
|  | ||||
| class SeekableSlider : public QSlider | ||||
| { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     explicit SeekableSlider(QWidget *parent = nullptr); | ||||
|     ~SeekableSlider() = default; | ||||
|  | ||||
| signals: | ||||
|  | ||||
| public slots: | ||||
|  | ||||
| protected: | ||||
|     void mouseReleaseEvent(QMouseEvent *event) override; | ||||
| }; | ||||
|  | ||||
| // SPDX-FileCopyrightText: 2025 Gary Wang <git@blumia.net> | ||||
| // | ||||
| // SPDX-License-Identifier: MIT | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <QSlider> | ||||
| #include <QMouseEvent> | ||||
|  | ||||
| class SeekableSlider : public QSlider | ||||
| { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     explicit SeekableSlider(QWidget *parent = nullptr); | ||||
|     ~SeekableSlider() override = default; | ||||
|  | ||||
| signals: | ||||
|  | ||||
| public slots: | ||||
|  | ||||
| protected: | ||||
|     void mouseReleaseEvent(QMouseEvent *event) override; | ||||
| }; | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user