start implementing model for koto artist

This commit is contained in:
Joshua Strobl 2024-10-27 19:16:30 +02:00
parent e3a00ab8ac
commit ddfd17c67c
12 changed files with 267 additions and 34 deletions

View file

@ -1,5 +1,5 @@
find_package(Qt6 6.4 REQUIRED COMPONENTS Quick QuickControls2 Sql) find_package(Qt6 6.4 REQUIRED COMPONENTS Quick QuickControls2 Sql)
find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE) find_package(ECM REQUIRED NO_MODULE)
find_package(KF6Baloo) find_package(KF6Baloo)
find_package(KF6FileMetaData) find_package(KF6FileMetaData)
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
@ -19,10 +19,15 @@ qt_add_executable(com.github.joshstrobl.koto
datalake/cartographer.cpp datalake/cartographer.cpp
datalake/database.cpp datalake/database.cpp
datalake/indexer.cpp datalake/indexer.cpp
datalake/models.cpp
datalake/track.cpp datalake/track.cpp
datalake/cartographer.hpp
datalake/structs.hpp
main.cpp main.cpp
datalake/models.cpp
) )
target_include_directories(com.github.joshstrobl.koto PUBLIC datalake includes)
ecm_add_qml_module(com.github.joshstrobl.koto URI "com.github.joshstrobl.koto" GENERATE_PLUGIN_SOURCE) ecm_add_qml_module(com.github.joshstrobl.koto URI "com.github.joshstrobl.koto" GENERATE_PLUGIN_SOURCE)
ecm_target_qml_sources(com.github.joshstrobl.koto ecm_target_qml_sources(com.github.joshstrobl.koto

View file

@ -82,6 +82,10 @@ std::optional<int> KotoAlbum::getYear() {
return this->year; return this->year;
} }
int KotoAlbum::getYearQml() {
return this->year.value_or(0);
}
void KotoAlbum::removeTrack(KotoTrack* track) { void KotoAlbum::removeTrack(KotoTrack* track) {
this->tracks.removeOne(track); this->tracks.removeOne(track);
} }

View file

@ -62,10 +62,18 @@ QString KotoArtist::getName() {
return QString {this->name}; return QString {this->name};
} }
QString KotoArtist::getPath() {
return QString {this->path};
}
QList<KotoTrack*> KotoArtist::getTracks() { QList<KotoTrack*> KotoArtist::getTracks() {
return QList {this->tracks}; return QList {this->tracks};
} }
QUuid KotoArtist::getUuid() {
return this->uuid;
}
void KotoArtist::removeAlbum(KotoAlbum* album) { void KotoArtist::removeAlbum(KotoAlbum* album) {
this->albums.removeOne(album); this->albums.removeOne(album);
} }

View file

@ -1,8 +1,11 @@
#include "cartographer.hpp" #include "cartographer.hpp"
Cartographer::Cartographer() #include <iostream>
: i_albums(QHash<QUuid, KotoAlbum*>()),
i_artists(QHash<QUuid, KotoArtist*>()), Cartographer::Cartographer(QObject* parent)
: QObject(parent),
i_albums(QHash<QUuid, KotoAlbum*>()),
i_artists_model(new KotoArtistModel(QList<KotoArtist*>())),
i_artists_by_name(QHash<QString, KotoArtist*>()), i_artists_by_name(QHash<QString, KotoArtist*>()),
i_tracks(QHash<QUuid, KotoTrack*>()) {} i_tracks(QHash<QUuid, KotoTrack*>()) {}
@ -16,7 +19,7 @@ void Cartographer::addAlbum(KotoAlbum* album) {
} }
void Cartographer::addArtist(KotoArtist* artist) { void Cartographer::addArtist(KotoArtist* artist) {
this->i_artists.insert(artist->uuid, artist); this->i_artists_model->addArtist(artist);
this->i_artists_by_name.insert(artist->getName(), artist); this->i_artists_by_name.insert(artist->getName(), artist);
} }
@ -29,17 +32,20 @@ std::optional<KotoAlbum*> Cartographer::getAlbum(QUuid uuid) {
return album ? std::optional {album} : std::nullopt; return album ? std::optional {album} : std::nullopt;
} }
QList<KotoAlbum*> Cartographer::getAlbums() {
return this->i_albums.values();
}
std::optional<KotoArtist*> Cartographer::getArtist(QUuid uuid) { std::optional<KotoArtist*> Cartographer::getArtist(QUuid uuid) {
auto artist = this->i_artists.value(uuid, nullptr); for (auto artist : this->i_artists_model->getArtists()) {
return artist ? std::optional {artist} : std::nullopt; if (artist->uuid == uuid) { return std::optional {artist}; }
}
return std::nullopt;
} }
QList<KotoArtist*> Cartographer::getArtists() { QList<KotoArtist*> Cartographer::getArtists() {
return this->i_artists.values(); return this->i_artists_model->getArtists();
}
KotoArtistModel* Cartographer::getArtistsModel() {
// if (this->i_artists_model == nullptr) { this->i_artists_model = new KotoArtistModel(this->i_artists); }
return this->i_artists_model;
} }
std::optional<KotoArtist*> Cartographer::getArtist(QString name) { std::optional<KotoArtist*> Cartographer::getArtist(QString name) {

View file

@ -1,21 +1,40 @@
#pragma once #pragma once
#include <QtQml/qqmlregistration.h>
#include <QHash> #include <QHash>
#include <QQmlEngine>
#include <QQmlListProperty>
#include <QString> #include <QString>
#include <QUuid> #include <QUuid>
#include <optional> #include <optional>
#include "structs.hpp" #include "structs.hpp"
class Cartographer { class Cartographer : public QObject {
public: Q_OBJECT
Cartographer(); QML_ELEMENT
static Cartographer& instance(); QML_SINGLETON
static Cartographer* create() { return &instance(); } // Q_PROPERTY(QQmlListProperty<KotoAlbum*> albums READ getAlbumsQml)
Q_PROPERTY(KotoArtistModel* artists READ getArtistsModel)
// Q_PROPERTY(QQmlListProperty<KotoTrack*> tracks READ getTracksQml)
public:
Cartographer(QObject* parent = nullptr);
static Cartographer& instance();
// static Cartographer* create(QQmlEngine* engine, QJSEngine*) {
// engine->setObjectOwnership(&instance(), QQmlEngine::CppOwnership);
// return &instance();
// }
void addAlbum(KotoAlbum* album);
void addArtist(KotoArtist* artist);
void addTrack(KotoTrack* track);
// QQmlListProperty<KotoAlbum*> getAlbumsQml();
KotoArtistModel* getArtistsModel();
// QQmlListProperty<KotoTrack*> getTracksQml();
void addAlbum(KotoAlbum* album);
void addArtist(KotoArtist* artist);
void addTrack(KotoTrack* track);
std::optional<KotoAlbum*> getAlbum(QUuid uuid); std::optional<KotoAlbum*> getAlbum(QUuid uuid);
QList<KotoAlbum*> getAlbums(); QList<KotoAlbum*> getAlbums();
std::optional<KotoArtist*> getArtist(QUuid uuid); std::optional<KotoArtist*> getArtist(QUuid uuid);
@ -26,7 +45,7 @@ class Cartographer {
private: private:
QHash<QUuid, KotoAlbum*> i_albums; QHash<QUuid, KotoAlbum*> i_albums;
QHash<QUuid, KotoArtist*> i_artists; KotoArtistModel* i_artists_model;
QHash<QString, KotoArtist*> i_artists_by_name; QHash<QString, KotoArtist*> i_artists_by_name;
QHash<QUuid, KotoTrack*> i_tracks; QHash<QUuid, KotoTrack*> i_tracks;
}; };

View file

@ -0,0 +1,45 @@
#include "structs.hpp"
KotoArtistModel::~KotoArtistModel() {
this->beginResetModel();
this->m_artists.clear();
this->endResetModel();
}
void KotoArtistModel::addArtist(KotoArtist* artist) {
this->beginInsertRows(QModelIndex(), this->m_artists.count(), this->m_artists.count());
this->m_artists.append(artist);
this->endInsertRows();
}
int KotoArtistModel::rowCount(const QModelIndex& parent) const {
return this->m_artists.count();
}
QVariant KotoArtistModel::data(const QModelIndex& index, int role) const {
if (!index.isValid()) { return {}; }
if (index.row() >= this->m_artists.size()) { return {}; }
if (role == KotoArtistRoles::NameRole) {
return this->m_artists.at(index.row())->getName();
} else if (role == KotoArtistRoles::PathRole) {
return this->m_artists.at(index.row())->getPath();
} else if (role == KotoArtistRoles::UuidRole) {
return this->m_artists.at(index.row())->uuid;
} else {
return {};
}
}
QList<KotoArtist*> KotoArtistModel::getArtists() {
return this->m_artists;
}
QHash<int, QByteArray> KotoArtistModel::roleNames() const {
QHash<int, QByteArray> roles;
roles[NameRole] = QByteArrayLiteral("name");
roles[PathRole] = QByteArrayLiteral("path");
roles[UuidRole] = QByteArrayLiteral("uuid");
return roles;
}

View file

@ -1,5 +1,8 @@
#pragma once #pragma once
#include <QtQml/qqmlregistration.h>
#include <KFileMetaData/SimpleExtractionResult> #include <KFileMetaData/SimpleExtractionResult>
#include <QAbstractListModel>
#include <QFileInfo> #include <QFileInfo>
#include <QList> #include <QList>
#include <QSqlQuery> #include <QSqlQuery>
@ -8,14 +11,25 @@
#include <QUuid> #include <QUuid>
class KotoArtist; class KotoArtist;
class KotoArtistModel;
class KotoAlbum; class KotoAlbum;
class KotoAlbumModel;
class KotoTrack; class KotoTrack;
class KotoTrackModel;
class KotoArtist : public QObject {
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(QString name READ getName WRITE setName NOTIFY nameChanged)
Q_PROPERTY(QString path READ getPath WRITE setPath NOTIFY pathChanged)
Q_PROPERTY(QList<KotoAlbum*> albums READ getAlbums NOTIFY albumsChanged)
Q_PROPERTY(QList<KotoTrack*> tracks READ getTracks NOTIFY tracksChanged)
Q_PROPERTY(QUuid uuid READ getUuid)
class KotoArtist {
public: public:
KotoArtist(); KotoArtist();
static KotoArtist* fromDb(const QSqlQuery& query, const QSqlRecord& record); static KotoArtist* fromDb(const QSqlQuery& query, const QSqlRecord& record);
~KotoArtist(); virtual ~KotoArtist();
QUuid uuid; QUuid uuid;
@ -27,11 +41,18 @@ class KotoArtist {
QString getName(); QString getName();
QString getPath(); QString getPath();
QList<KotoTrack*> getTracks(); QList<KotoTrack*> getTracks();
QUuid getUuid();
void removeAlbum(KotoAlbum* album); void removeAlbum(KotoAlbum* album);
void removeTrack(KotoTrack* track); void removeTrack(KotoTrack* track);
void setName(QString str); void setName(QString str);
void setPath(QString str); void setPath(QString str);
signals:
void albumsChanged();
void nameChanged();
void pathChanged();
void tracksChanged();
private: private:
QString path; QString path;
QString name; QString name;
@ -40,11 +61,46 @@ class KotoArtist {
QList<KotoTrack*> tracks; QList<KotoTrack*> tracks;
}; };
class KotoAlbum { class KotoArtistModel : public QAbstractListModel {
Q_OBJECT
public:
explicit KotoArtistModel(const QList<KotoArtist*>& artists, QObject* parent = nullptr) : QAbstractListModel(parent), m_artists(artists) {}
void addArtist(KotoArtist* artist);
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames() const override;
virtual ~KotoArtistModel();
QList<KotoArtist*> getArtists();
enum KotoArtistRoles {
NameRole = Qt::UserRole + 1,
PathRole,
UuidRole,
};
private:
QList<KotoArtist*> m_artists;
};
class KotoAlbum : public QObject {
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(QString albumArtPath READ getAlbumArtPath WRITE setAlbumArtPath NOTIFY albumArtChanged)
Q_PROPERTY(QString description READ getDescription WRITE setDescription NOTIFY descriptionChanged)
Q_PROPERTY(QList<QString> genres READ getGenres WRITE setGenres NOTIFY genresChanged)
Q_PROPERTY(QString narrator READ getNarrator WRITE setNarrator NOTIFY narratorChanged)
Q_PROPERTY(QString path READ getPath WRITE setPath NOTIFY pathChanged)
Q_PROPERTY(QString title READ getTitle WRITE setTitle NOTIFY titleChanged)
Q_PROPERTY(QList<KotoTrack*> tracks READ getTracks NOTIFY tracksChanged)
Q_PROPERTY(int year READ getYearQml WRITE setYear NOTIFY yearChanged)
public: public:
KotoAlbum(); KotoAlbum();
static KotoAlbum* fromDb(const QSqlQuery& query, const QSqlRecord& record); static KotoAlbum* fromDb(const QSqlQuery& query, const QSqlRecord& record);
~KotoAlbum(); virtual ~KotoAlbum();
QUuid uuid; QUuid uuid;
QUuid artist_uuid; QUuid artist_uuid;
@ -58,6 +114,7 @@ class KotoAlbum {
QString getTitle(); QString getTitle();
QList<KotoTrack*> getTracks(); QList<KotoTrack*> getTracks();
std::optional<int> getYear(); std::optional<int> getYear();
int getYearQml();
void addTrack(KotoTrack* track); void addTrack(KotoTrack* track);
void removeTrack(KotoTrack* track); void removeTrack(KotoTrack* track);
@ -69,6 +126,16 @@ class KotoAlbum {
void setTitle(QString str); void setTitle(QString str);
void setYear(int num); void setYear(int num);
signals:
void albumArtChanged();
void descriptionChanged();
void genresChanged();
void narratorChanged();
void pathChanged();
void titleChanged();
void tracksChanged();
void yearChanged();
private: private:
QString title; QString title;
QString description; QString description;
@ -82,18 +149,36 @@ class KotoAlbum {
QString album_art_path; QString album_art_path;
}; };
class KotoTrack { class KotoTrack : public QObject {
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(QString album_uuid READ getAlbumUuid NOTIFY albumChanged)
Q_PROPERTY(QUuid artist_uuid READ getArtistUuid NOTIFY artistChanged)
Q_PROPERTY(QUuid uuid READ getUuid)
Q_PROPERTY(int discNumber READ getDiscNumber WRITE setDiscNumber NOTIFY discNumberChanged)
Q_PROPERTY(int duration READ getDuration WRITE setDuration NOTIFY durationChanged)
Q_PROPERTY(QStringList genres READ getGenres WRITE setGenres NOTIFY genresChanged)
Q_PROPERTY(QString lyrics READ getLyrics WRITE setLyrics NOTIFY lyricsChanged)
Q_PROPERTY(QString narrator READ getNarrator WRITE setNarrator NOTIFY narratorChanged)
Q_PROPERTY(QString path READ getPath WRITE setPath NOTIFY pathChanged)
Q_PROPERTY(QString title READ getTitle WRITE setTitle NOTIFY titleChanged)
Q_PROPERTY(int trackNumber READ getTrackNumber WRITE setTrackNumber NOTIFY trackNumberChanged)
Q_PROPERTY(int year READ getYear WRITE setYear NOTIFY yearChanged)
public: public:
KotoTrack(); // No-op constructor KotoTrack(); // No-op constructor
static KotoTrack* fromDb(const QSqlQuery& query, const QSqlRecord& record); static KotoTrack* fromDb(const QSqlQuery& query, const QSqlRecord& record);
static KotoTrack* fromMetadata(const KFileMetaData::SimpleExtractionResult& metadata, const QFileInfo& info); static KotoTrack* fromMetadata(const KFileMetaData::SimpleExtractionResult& metadata, const QFileInfo& info);
~KotoTrack(); virtual ~KotoTrack();
std::optional<QUuid> album_uuid; std::optional<QUuid> album_uuid;
QUuid artist_uuid; QUuid artist_uuid;
QUuid uuid; QUuid uuid;
void commit(); void commit();
QString getAlbumUuid();
QUuid getArtistUuid();
int getDiscNumber();
int getDuration(); int getDuration();
QStringList getGenres(); QStringList getGenres();
QString getLyrics(); QString getLyrics();
@ -101,6 +186,7 @@ class KotoTrack {
QString getPath(); QString getPath();
QString getTitle(); QString getTitle();
int getTrackNumber(); int getTrackNumber();
QUuid getUuid();
int getYear(); int getYear();
void setAlbum(KotoAlbum* album); void setAlbum(KotoAlbum* album);
@ -115,6 +201,19 @@ class KotoTrack {
void setTrackNumber(int num); void setTrackNumber(int num);
void setYear(int num); void setYear(int num);
signals:
void albumChanged();
void artistChanged();
void discNumberChanged();
void durationChanged();
void genresChanged();
void lyricsChanged();
void narratorChanged();
void pathChanged();
void titleChanged();
void trackNumberChanged();
void yearChanged();
private: private:
int disc_number; int disc_number;
int duration; int duration;

View file

@ -102,6 +102,19 @@ void KotoTrack::commit() {
query.exec(); query.exec();
} }
QString KotoTrack::getAlbumUuid() {
if (!this->album_uuid.has_value()) return this->album_uuid.value().toString();
return {};
}
QUuid KotoTrack::getArtistUuid() {
return this->artist_uuid;
}
int KotoTrack::getDiscNumber() {
return this->disc_number;
}
int KotoTrack::getDuration() { int KotoTrack::getDuration() {
return this->duration; return this->duration;
} }
@ -130,6 +143,10 @@ int KotoTrack::getTrackNumber() {
return this->track_number; return this->track_number;
} }
QUuid KotoTrack::getUuid() {
return this->uuid;
}
int KotoTrack::getYear() { int KotoTrack::getYear() {
return this->year; return this->year;
} }

View file

@ -21,12 +21,14 @@ int main(int argc, char* argv[]) {
if (engine.rootObjects().isEmpty()) { return -1; } if (engine.rootObjects().isEmpty()) { return -1; }
std::thread([]() { std::thread([]() {
Cartographer::create(); // Cartographer::create();
KotoConfig::create(); KotoConfig::create();
KotoDatabase::create(); KotoDatabase::create();
KotoDatabase::instance().connect(); KotoDatabase::instance().connect();
std::cout << "???" << std::endl;
// If we needed to bootstrap, index all libraries, otherwise load the database // If we needed to bootstrap, index all libraries, otherwise load the database
if (KotoDatabase::instance().requiredBootstrap()) { if (KotoDatabase::instance().requiredBootstrap()) {
indexAllLibraries(); indexAllLibraries();

View file

@ -3,10 +3,35 @@ import QtQuick.Controls as Controls
import QtQuick.Layouts import QtQuick.Layouts
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
Kirigami.Page { Kirigami.ScrollablePage {
ColumnLayout { Component {
Controls.Label { id: listDelegate
text: qsTr("blah!")
Controls.ItemDelegate {
required property string name
text: name
width: ListView.view.width
} }
} }
// ListModel {
// id: blah
//
// ListElement {
// name: "blah1"
// }
// ListElement {
// name: "blah2"
// }
// ListElement {
// name: "blah3"
// }
// }
ListView {
Layout.fillHeight: true
Layout.fillWidth: true
delegate: listDelegate
//model: blah
model: Cartographer.artists
}
} }

View file

@ -20,7 +20,7 @@ Kirigami.GlobalDrawer {
drawerOpen: !isMobile() drawerOpen: !isMobile()
edge: Qt.LeftEdge edge: Qt.LeftEdge
height: parent.height height: parent.height
modal: isMobile() modal: false
actions: [ actions: [
Kirigami.Action { Kirigami.Action {

View file

@ -9,11 +9,14 @@ Kirigami.Page {
ColumnLayout { ColumnLayout {
id: rootLayout id: rootLayout
Layout.fillWidth: true anchors.fill: parent
Controls.StackView { Controls.StackView {
id: rootStack id: rootStack
Layout.fillHeight: true
Layout.fillWidth: true
initialItem: HomePage { initialItem: HomePage {
} }
} }