initial commit
This commit is contained in:
commit
fae3d30dbd
26 changed files with 18409 additions and 0 deletions
38
desktop/CMakeLists.txt
Normal file
38
desktop/CMakeLists.txt
Normal file
|
@ -0,0 +1,38 @@
|
|||
find_package(Qt6 6.4 REQUIRED COMPONENTS Quick QuickControls2)
|
||||
find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE)
|
||||
find_package(KF6Baloo)
|
||||
find_package(KF6FileMetaData)
|
||||
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
|
||||
|
||||
include(KDEInstallDirs)
|
||||
include(ECMFindQmlModule)
|
||||
include(ECMQmlModule)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(koto
|
||||
main.cpp
|
||||
config/config.cpp
|
||||
config/library.cpp
|
||||
config/ui_prefs.cpp
|
||||
datalake/indexer.cpp
|
||||
datalake/track.cpp
|
||||
)
|
||||
|
||||
ecm_add_qml_module(koto URI "com.github.joshstrobl.koto" GENERATE_PLUGIN_SOURCE)
|
||||
|
||||
ecm_target_qml_sources(koto
|
||||
SOURCES
|
||||
qml/PrimaryNavigation.qml
|
||||
qml/HomePage.qml
|
||||
qml/Main.qml
|
||||
)
|
||||
|
||||
target_link_libraries(koto
|
||||
PRIVATE KF6::Baloo KF6::FileMetaData Qt6::Quick Qt6::QuickControls2
|
||||
)
|
||||
|
||||
install(FILES com.github.joshstrobl.koto.desktop DESTINATION ${KDE_INSTALL_APPDIR})
|
||||
install(TARGETS koto ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
|
||||
|
||||
ecm_finalize_qml_module(koto)
|
40
desktop/config/config.cpp
Normal file
40
desktop/config/config.cpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
#include "config.hpp"
|
||||
#include <QDir>
|
||||
#include <QStandardPaths>
|
||||
#include <filesystem>
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
KotoConfig::KotoConfig() {
|
||||
// Define our application's config location
|
||||
auto configDir = QDir(QStandardPaths::writableLocation(QStandardPaths::StandardLocation::AppConfigLocation));
|
||||
auto configDirPath = configDir.absolutePath();
|
||||
fs::path filePath {};
|
||||
auto configPathStd = configDirPath.toStdString();
|
||||
filePath /= configPathStd;
|
||||
filePath /= "config.toml";
|
||||
|
||||
auto data = toml::parse(filePath);
|
||||
std::optional<toml::value> ui_prefs;
|
||||
|
||||
if (data.contains("preferences.ui")) {
|
||||
auto ui_prefs_at = data.at("preferences.ui");
|
||||
if (ui_prefs_at.is_table()) ui_prefs = ui_prefs_at.as_table();
|
||||
}
|
||||
|
||||
auto prefs = KotoUiPreferences(ui_prefs);
|
||||
this->i_uiPreferences = &prefs;
|
||||
|
||||
this->i_libraries = {};
|
||||
for (const auto& lib_value : toml::find<std::vector<toml::value>>(data, "libraries")) {
|
||||
auto lib = KotoLibraryConfig(lib_value);
|
||||
this->i_libraries.push_back(lib);
|
||||
}
|
||||
}
|
||||
|
||||
KotoUiPreferences * KotoConfig::getUiPreferences() {
|
||||
return this->i_uiPreferences;
|
||||
}
|
||||
|
||||
std::vector<KotoLibraryConfig> KotoConfig::getLibraries() {
|
||||
return this->i_libraries;
|
||||
}
|
18
desktop/config/config.hpp
Normal file
18
desktop/config/config.hpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "library.hpp"
|
||||
#include "ui_prefs.hpp"
|
||||
|
||||
class KotoConfig {
|
||||
public:
|
||||
KotoConfig();
|
||||
~KotoConfig();
|
||||
std::vector<KotoLibraryConfig> getLibraries();
|
||||
KotoUiPreferences * getUiPreferences();
|
||||
|
||||
private:
|
||||
std::vector<KotoLibraryConfig> i_libraries;
|
||||
KotoUiPreferences * i_uiPreferences;
|
||||
|
||||
};
|
15
desktop/config/library.cpp
Normal file
15
desktop/config/library.cpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#include "library.hpp"
|
||||
#include <string>
|
||||
|
||||
KotoLibraryConfig::KotoLibraryConfig(const toml::value &v) {
|
||||
this->i_name = toml::find<std::string>(v, "name");
|
||||
this->i_path = toml::find<std::string>(v, "path");
|
||||
}
|
||||
|
||||
std::string KotoLibraryConfig::getName() {
|
||||
return this->i_name;
|
||||
}
|
||||
|
||||
fs::path KotoLibraryConfig::getPath() {
|
||||
return this->i_path;
|
||||
}
|
17
desktop/config/library.hpp
Normal file
17
desktop/config/library.hpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
#include "includes/toml.hpp"
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
class KotoLibraryConfig {
|
||||
public:
|
||||
KotoLibraryConfig(const toml::value &v);
|
||||
~KotoLibraryConfig();
|
||||
std::string getName();
|
||||
fs::path getPath();
|
||||
private:
|
||||
std::string i_name;
|
||||
fs::path i_path;
|
||||
};
|
38
desktop/config/ui_prefs.cpp
Normal file
38
desktop/config/ui_prefs.cpp
Normal file
|
@ -0,0 +1,38 @@
|
|||
#include "ui_prefs.hpp"
|
||||
|
||||
KotoUiPreferences::KotoUiPreferences(std::optional<toml::value> v) {
|
||||
this->i_albumInfoShowDescription = true;
|
||||
this->i_albumInfoShowGenre = true;
|
||||
this->i_albumInfoShowNarrator = true;
|
||||
this->i_albumInfoShowYear = true;
|
||||
this->i_lastUsedVolume = 0.5;
|
||||
|
||||
// No UI prefs provided
|
||||
if (!v.has_value()) return;
|
||||
toml::value& uiPrefs = v.value();
|
||||
this->i_albumInfoShowDescription = toml::find_or<bool>(uiPrefs, "album_info_show_description", false);
|
||||
this->i_albumInfoShowGenre = toml::find_or<bool>(uiPrefs, "album_info_show_genre", false);
|
||||
this->i_albumInfoShowNarrator = toml::find_or<bool>(uiPrefs, "album_info_show_narrator", false);
|
||||
this->i_albumInfoShowYear = toml::find_or<bool>(uiPrefs, "album_info_show_year", false);
|
||||
this->i_lastUsedVolume = toml::find_or<float>(uiPrefs, "last_used_volume", 0.5);
|
||||
}
|
||||
|
||||
bool KotoUiPreferences::getAlbumInfoShowDescription() {
|
||||
return this->i_albumInfoShowDescription;
|
||||
}
|
||||
|
||||
bool KotoUiPreferences::getAlbumInfoShowGenre() {
|
||||
return this->i_albumInfoShowGenre;
|
||||
}
|
||||
|
||||
bool KotoUiPreferences::getAlbumInfoShowNarrator() {
|
||||
return this->i_albumInfoShowNarrator;
|
||||
}
|
||||
|
||||
bool KotoUiPreferences::getAlbumInfoShowYear() {
|
||||
return this->i_albumInfoShowYear;
|
||||
}
|
||||
|
||||
float KotoUiPreferences::getLastUsedVolume() {
|
||||
return this->i_lastUsedVolume;
|
||||
}
|
30
desktop/config/ui_prefs.hpp
Normal file
30
desktop/config/ui_prefs.hpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
#include "includes/toml.hpp"
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
class KotoUiPreferences {
|
||||
public:
|
||||
KotoUiPreferences(std::optional<toml::value> v);
|
||||
~KotoUiPreferences();
|
||||
|
||||
bool getAlbumInfoShowDescription();
|
||||
bool getAlbumInfoShowGenre();
|
||||
bool getAlbumInfoShowNarrator();
|
||||
bool getAlbumInfoShowYear();
|
||||
float getLastUsedVolume();
|
||||
|
||||
void setAlbumInfoShowDescription(bool show);
|
||||
void setAlbumInfoShowGenre(bool show);
|
||||
void setAlbumInfoShowNarrator(bool show);
|
||||
void setAlbumInfoShowYear(bool show);
|
||||
void setLastUsedVolume(float volume);
|
||||
private:
|
||||
bool i_albumInfoShowDescription;
|
||||
bool i_albumInfoShowGenre;
|
||||
bool i_albumInfoShowNarrator;
|
||||
bool i_albumInfoShowYear;
|
||||
float i_lastUsedVolume;
|
||||
};
|
0
desktop/datalake/artist.hpp
Normal file
0
desktop/datalake/artist.hpp
Normal file
6
desktop/datalake/indexer.cpp
Normal file
6
desktop/datalake/indexer.cpp
Normal file
|
@ -0,0 +1,6 @@
|
|||
#include "indexer.hpp"
|
||||
#include <QDirIterator>
|
||||
|
||||
FileIndexer::FileIndexer(KotoLibraryConfig * config) {
|
||||
|
||||
}
|
19
desktop/datalake/indexer.hpp
Normal file
19
desktop/datalake/indexer.hpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "config/library.hpp"
|
||||
#include "track.hpp"
|
||||
|
||||
class FileIndexer {
|
||||
public:
|
||||
FileIndexer(KotoLibraryConfig * config);
|
||||
~FileIndexer();
|
||||
|
||||
std::vector<KotoTrack *> getFiles();
|
||||
std::string getRoot();
|
||||
|
||||
void index();
|
||||
protected:
|
||||
std::vector<KotoTrack *> i_tracks;
|
||||
std::string i_root;
|
||||
};
|
0
desktop/datalake/track.cpp
Normal file
0
desktop/datalake/track.cpp
Normal file
26
desktop/datalake/track.hpp
Normal file
26
desktop/datalake/track.hpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
#include <KFileMetaData/SimpleExtractionResult>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class KotoTrack {
|
||||
public:
|
||||
KotoTrack(); // No-op constructor
|
||||
static KotoTrack * fromDb();
|
||||
static KotoTrack * fromMetadata(KFileMetaData::SimpleExtractionResult metadata);
|
||||
~KotoTrack();
|
||||
|
||||
private:
|
||||
std::string album;
|
||||
std::string album_artist;
|
||||
std::string artist;
|
||||
int disc_number;
|
||||
int duration;
|
||||
std::vector<std::string> genres;
|
||||
std::string lyrics;
|
||||
std::string narrator;
|
||||
std::string path;
|
||||
std::string title;
|
||||
int track_number;
|
||||
int year;
|
||||
};
|
26
desktop/example-config.toml
Normal file
26
desktop/example-config.toml
Normal file
|
@ -0,0 +1,26 @@
|
|||
[preferences.ui]
|
||||
album_info_show_description = true
|
||||
album_info_show_genre = true
|
||||
album_info_show_narrator = true
|
||||
album_info_show_year = true
|
||||
last_used_volume = 0.5
|
||||
|
||||
[preferences.podcasts]
|
||||
jump_backwards_seconds = 30
|
||||
jump_forward_seconds = 30
|
||||
|
||||
[[libraries]]
|
||||
name = "Audiobooks"
|
||||
path = "/home/joshua/Audiobooks"
|
||||
|
||||
[[libraries]]
|
||||
name = "Music"
|
||||
path = "/home/joshua/Music"
|
||||
|
||||
[[libraries]]
|
||||
name = "Streaming"
|
||||
path = "/home/joshua/StreamingMusic"
|
||||
|
||||
[[libraries]]
|
||||
name = "Podcasts"
|
||||
path = "/home/joshua/Podcasts"
|
17240
desktop/includes/toml.hpp
Normal file
17240
desktop/includes/toml.hpp
Normal file
File diff suppressed because it is too large
Load diff
21
desktop/main.cpp
Normal file
21
desktop/main.cpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
#include <QGuiApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQuickStyle>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QQuickStyle::setStyle(QStringLiteral("org.kde.breeze"));
|
||||
QGuiApplication app(argc, argv);
|
||||
app.setApplicationDisplayName("Koto");
|
||||
app.setDesktopFileName("com.github.joshstrobl.koto.desktop");
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
|
||||
engine.loadFromModule("com.github.joshstrobl.koto", "Main");
|
||||
|
||||
if (engine.rootObjects().isEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return app.exec();
|
||||
}
|
12
desktop/qml/HomePage.qml
Normal file
12
desktop/qml/HomePage.qml
Normal file
|
@ -0,0 +1,12 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls as Controls
|
||||
import QtQuick.Layouts
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
Kirigami.Page {
|
||||
ColumnLayout {
|
||||
Controls.Label {
|
||||
text: qsTr("blah!")
|
||||
}
|
||||
}
|
||||
}
|
20
desktop/qml/Main.qml
Normal file
20
desktop/qml/Main.qml
Normal file
|
@ -0,0 +1,20 @@
|
|||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls as Controls
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
Kirigami.ApplicationWindow {
|
||||
id: root
|
||||
width: 1000
|
||||
height: 600
|
||||
visible: true
|
||||
title: "Koto"
|
||||
|
||||
// TODO: Implement an onboarding page
|
||||
pageStack.initialPage: PrimaryNavigation {
|
||||
Component.onCompleted: {
|
||||
pageStack.push(Qt.createComponent("HomePage.qml"), {});
|
||||
}
|
||||
}
|
||||
}
|
87
desktop/qml/PrimaryNavigation.qml
Normal file
87
desktop/qml/PrimaryNavigation.qml
Normal file
|
@ -0,0 +1,87 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls as Controls
|
||||
import QtQuick.Layouts
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
// Kirigami.Page {
|
||||
// ColumnLayout {
|
||||
// Controls.TextArea {
|
||||
// Layout.alignment: Qt.AlignTop
|
||||
// id: searchEntry
|
||||
// placeholderText: qsTr("Search")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
Kirigami.GlobalDrawer {
|
||||
width: 200
|
||||
height: parent.height
|
||||
edge: Qt.LeftEdge
|
||||
modal: false
|
||||
|
||||
header: Kirigami.SearchField {
|
||||
id: searchEntry
|
||||
placeholderText: qsTr("Search")
|
||||
}
|
||||
|
||||
actions: [
|
||||
Kirigami.Action {
|
||||
text: "Home"
|
||||
icon.name: "go-home"
|
||||
onTriggered: console.log("Home triggered")
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: "Audiobooks"
|
||||
expandible: true
|
||||
icon.name: "bookmark"
|
||||
onTriggered: console.log("Audiobooks triggered")
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: "Music"
|
||||
expandible: true
|
||||
icon.name: "emblem-music-symbolic"
|
||||
children: [
|
||||
Kirigami.Action {
|
||||
text: "Local Library"
|
||||
onTriggered: console.log("Music Local Library triggered")
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: "Radio"
|
||||
onTriggered: console.log("Music Radio triggered")
|
||||
}
|
||||
]
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: "Podcasts"
|
||||
expandible: true
|
||||
icon.name: "application-rss+xml-symbolic"
|
||||
children: [
|
||||
Kirigami.Action {
|
||||
text: "Library"
|
||||
onTriggered: console.log("Podcasts Library triggered")
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: "Find new podcasts"
|
||||
onTriggered: console.log("Podcasts Find new podcasts triggered")
|
||||
}
|
||||
]
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: "Playlists"
|
||||
expandible: true
|
||||
icon.name: "music-playlist-symbolic"
|
||||
children: [
|
||||
Kirigami.Action {
|
||||
text: "Library"
|
||||
onTriggered: console.log("Playlists Library triggered")
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: "Find new playlists"
|
||||
onTriggered: console.log("Playlists Find new playlists triggered")
|
||||
}
|
||||
]
|
||||
// TODO: Generate list of playlists
|
||||
}
|
||||
]
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue