Merge branch 'inline-credits' into develop
This commit is contained in:
@@ -309,8 +309,10 @@
|
||||
<message id="Lms.Settings.default-transcoding-output-bitrate">Default transcoding output bitrate</message>
|
||||
<message id="Lms.Settings.default-transcoding-output-format">Default transcoding output format</message>
|
||||
<message id="Lms.Settings.demo-cannot-save">Cannot save using a demo account!</message>
|
||||
<message id="Lms.Settings.enable-inline-artist-relationships">Display artist relationships inline within albums</message>
|
||||
<message id="Lms.Settings.enable-transcoding-by-default">Enable transcoding by default</message>
|
||||
<message id="Lms.Settings.feedback">Feedback</message>
|
||||
<message id="Lms.Settings.inline-artist-relationships">Types of artist relationships to display</message>
|
||||
<message id="Lms.Settings.menu-settings"><i class="fa fa-fw fa-cog" aria-hidden="true"></i> Settings</message>
|
||||
<message id="Lms.Settings.name">Album Name</message>
|
||||
<message id="Lms.Settings.original-date-asc">Original Release Date (Ascending)</message>
|
||||
|
||||
@@ -309,8 +309,10 @@
|
||||
<message id="Lms.Settings.default-transcoding-output-bitrate">Bitrate par défaut du transcodage</message>
|
||||
<message id="Lms.Settings.default-transcoding-output-format">Format par défaut du transcodage</message>
|
||||
<message id="Lms.Settings.demo-cannot-save">Impossible de sauvegarder en utilisant un compte de démo !</message>
|
||||
<message id="Lms.Settings.enable-inline-artist-relationships">Afficher les relations d'artiste en ligne dans les albums</message>
|
||||
<message id="Lms.Settings.enable-transcoding-by-default">Activer par défaut le transcodage</message>
|
||||
<message id="Lms.Settings.feedback">Feedback</message>
|
||||
<message id="Lms.Settings.inline-artist-relationships">Types de relations d'artiste à afficher</message>
|
||||
<message id="Lms.Settings.menu-settings"><i class="fa fa-fw fa-cog" aria-hidden="true"></i> Paramètres</message>
|
||||
<message id="Lms.Settings.name">Nom de l'album</message>
|
||||
<message id="Lms.Settings.original-date-asc">Date de sortie originale (Croissant)</message>
|
||||
|
||||
@@ -309,8 +309,10 @@
|
||||
<message id="Lms.Settings.default-transcoding-output-bitrate">Bitrate di default per la transcodifica</message>
|
||||
<message id="Lms.Settings.default-transcoding-output-format">Formato di default per la transcodifica</message>
|
||||
<message id="Lms.Settings.demo-cannot-save">Non posso salvare le impostazioni utilizzando l'account demo!</message>
|
||||
<message id="Lms.Settings.enable-inline-artist-relationships">Mostra le relazioni degli artisti in linea negli album</message>
|
||||
<message id="Lms.Settings.enable-transcoding-by-default">Abilita transcodifica di default</message>
|
||||
<message id="Lms.Settings.feedback">Feedback</message>
|
||||
<message id="Lms.Settings.inline-artist-relationships">Tipi di relazioni artistiche da visualizzare</message>
|
||||
<message id="Lms.Settings.menu-settings"><i class="fa fa-fw fa-cog" aria-hidden="true"></i> Impostazioni</message>
|
||||
<message id="Lms.Settings.name">Nome dell'album</message>
|
||||
<message id="Lms.Settings.original-date-asc">Data di uscita originale (Crescente)</message>
|
||||
|
||||
@@ -335,8 +335,10 @@
|
||||
<message id="Lms.Settings.default-transcoding-output-bitrate">Domyślna przepływność transkodowania</message>
|
||||
<message id="Lms.Settings.default-transcoding-output-format">Domyślny format wyjściowy transkodowania</message>
|
||||
<message id="Lms.Settings.demo-cannot-save">Nie można zapisywać na koncie demonstracyjnym!</message>
|
||||
<message id="Lms.Settings.enable-inline-artist-relationships">Wyświetlaj powiązania artystów w albumach</message>
|
||||
<message id="Lms.Settings.enable-transcoding-by-default">Aktywuj domyślnie transkodowanie</message>
|
||||
<message id="Lms.Settings.feedback">Feedback</message>
|
||||
<message id="Lms.Settings.inline-artist-relationships">Typy powiązań artystów do wyświetlenia</message>
|
||||
<message id="Lms.Settings.menu-settings"><i class="fa fa-fw fa-cog" aria-hidden="true"></i> Ustawienia</message>
|
||||
<message id="Lms.Settings.name">Nazwa albumu</message>
|
||||
<message id="Lms.Settings.original-date-asc">Oryginalna data wydania (Rosnąco)</message>
|
||||
|
||||
@@ -311,6 +311,8 @@
|
||||
<message id="Lms.Settings.demo-cannot-save">使用演示账号时不能保存!</message>
|
||||
|
||||
|
||||
|
||||
|
||||
<message id="Lms.Settings.menu-settings"><i class="fa fa-fw fa-cog" aria-hidden="true"></i> 设置</message>
|
||||
|
||||
|
||||
|
||||
+9
-2
@@ -94,13 +94,14 @@
|
||||
${<if-has-track-number>}${track-number}${</if-has-track-number>}
|
||||
</div>
|
||||
<div class="row align-items-center flex-fill overflow-hidden">
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="col-12 col-md-8">
|
||||
<div class="p-2">
|
||||
${name}
|
||||
${<if-has-artists>}${artists class="d-block d-md-none"}${</if-has-artists>}
|
||||
${<if-has-artist-links>}${artist-links}${</if-has-artist-links>}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-4">
|
||||
${<if-has-artists>}${artists-md class="d-none d-md-block"}${</if-has-artists>}
|
||||
</div>
|
||||
</div>
|
||||
@@ -125,6 +126,12 @@
|
||||
</div>
|
||||
</message>
|
||||
|
||||
<message id="Lms.Explore.Release.template.artist-links-entry">
|
||||
<div class=" text-muted small ms-2 d-flex">
|
||||
<span class="text-nowrap text-muted">${role} — </span>${anchors class="ms-1"}
|
||||
</div>
|
||||
</message>
|
||||
|
||||
<message id="Lms.Explore.Release.template.release-info">
|
||||
<div class="modal fade" tabindex="-1">
|
||||
<div class="modal-dialog modal-dialog-scrollable">
|
||||
|
||||
@@ -15,6 +15,26 @@
|
||||
${artist-release-sort-method-info}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="form-check">
|
||||
${enable-inline-artist-relationships class="form-check-input"}
|
||||
<label class="form-check-label" for="${id:enable-inline-artist-relationships}">
|
||||
${tr:Lms.Settings.enable-inline-artist-relationships}
|
||||
</label>
|
||||
<div class="invalid-feedback">
|
||||
${enable-inline-artist-relationships}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label class="form-label" for="${id:inline-artist-relationships}">
|
||||
${tr:Lms.Settings.inline-artist-relationships}
|
||||
</label>
|
||||
${inline-artist-relationships class="form-control"}
|
||||
<div class="invalid-feedback">
|
||||
${inline-artist-relationships-info}
|
||||
</div>
|
||||
</div>
|
||||
<legend>${tr:Lms.Settings.audio}
|
||||
<button type="button" class="btn btn-sm p-0" data-bs-toggle="tooltip" data-bs-placement="right" title="${tr:Lms.Settings.audio-settings-are-local}">
|
||||
<i class="fa fa-fw fa-info-circle" aria-hidden="true"></i>
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace lms::db
|
||||
{
|
||||
namespace
|
||||
{
|
||||
static constexpr Version LMS_DATABASE_VERSION{ 82 };
|
||||
static constexpr Version LMS_DATABASE_VERSION{ 83 };
|
||||
}
|
||||
|
||||
VersionInfo::VersionInfo()
|
||||
@@ -1099,6 +1099,13 @@ FROM tracklist)");
|
||||
utils::executeCommand(*session.getDboSession(), "UPDATE scan_settings SET scan_version = scan_version + 1");
|
||||
}
|
||||
|
||||
void migrateFromV82(Session& session)
|
||||
{
|
||||
// new setting to display inline artist relationships in the release view
|
||||
utils::executeCommand(*session.getDboSession(), "ALTER TABLE user ADD COLUMN ui_enable_inline_artist_relationships BOOLEAN NOT NULL DEFAULT(false)");
|
||||
utils::executeCommand(*session.getDboSession(), "ALTER TABLE user ADD COLUMN ui_inline_artist_relationships BIGINT NOT NULL DEFAULT(68)"); // Composer + Performer
|
||||
}
|
||||
|
||||
bool doDbMigration(Session& session)
|
||||
{
|
||||
constexpr std::string_view outdatedMsg{ "Outdated database, please rebuild it (delete the .db file and restart)" };
|
||||
@@ -1157,6 +1164,7 @@ FROM tracklist)");
|
||||
{ 79, migrateFromV79 },
|
||||
{ 80, migrateFromV80 },
|
||||
{ 81, migrateFromV81 },
|
||||
{ 82, migrateFromV82 },
|
||||
};
|
||||
|
||||
bool migrationPerformed{};
|
||||
|
||||
@@ -19,13 +19,15 @@
|
||||
|
||||
#include "database/User.hpp"
|
||||
|
||||
#include "core/ILogger.hpp"
|
||||
#include <cassert>
|
||||
|
||||
#include "database/Artist.hpp"
|
||||
#include "database/Release.hpp"
|
||||
#include "database/Session.hpp"
|
||||
#include "database/Track.hpp"
|
||||
#include "database/UIState.hpp"
|
||||
|
||||
#include "EnumSetTraits.hpp"
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "StringViewTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
@@ -21,11 +21,11 @@
|
||||
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <Wt/Dbo/Dbo.h>
|
||||
#include <Wt/WDateTime.h>
|
||||
|
||||
#include "core/EnumSet.hpp"
|
||||
#include "core/UUID.hpp"
|
||||
#include "database/Object.hpp"
|
||||
#include "database/Types.hpp"
|
||||
@@ -110,6 +110,8 @@ namespace lms::db
|
||||
void setSubsonicDefaultTranscodingOutputBitrate(Bitrate bitrate);
|
||||
void setUITheme(UITheme uiTheme) { _uiTheme = uiTheme; }
|
||||
void setUIArtistReleaseSortMethod(ReleaseSortMethod method) { _uiArtistReleaseSortMethod = method; }
|
||||
void setUIEnableInlineArtistRelationships(bool enable) { _uiEnableInlineArtistRelationships = enable; }
|
||||
void setUIInlineArtistRelationships(core::EnumSet<TrackArtistLinkType> types) { _uiInlineArtistRelationships = types; }
|
||||
void setSubsonicArtistListMode(SubsonicArtistListMode mode) { _subsonicArtistListMode = mode; }
|
||||
void setFeedbackBackend(FeedbackBackend feedbackBackend) { _feedbackBackend = feedbackBackend; }
|
||||
void setScrobblingBackend(ScrobblingBackend scrobblingBackend) { _scrobblingBackend = scrobblingBackend; }
|
||||
@@ -124,6 +126,8 @@ namespace lms::db
|
||||
Bitrate getSubsonicDefaultTranscodingOutputBitrate() const { return _subsonicDefaultTranscodingOutputBitrate; }
|
||||
UITheme getUITheme() const { return _uiTheme; }
|
||||
ReleaseSortMethod getUIArtistReleaseSortMethod() const { return _uiArtistReleaseSortMethod; }
|
||||
bool getUIEnableInlineArtistRelationships() const { return _uiEnableInlineArtistRelationships; }
|
||||
core::EnumSet<TrackArtistLinkType> getUIInlineArtistRelationships() const { return _uiInlineArtistRelationships; }
|
||||
SubsonicArtistListMode getSubsonicArtistListMode() const { return _subsonicArtistListMode; }
|
||||
FeedbackBackend getFeedbackBackend() const { return _feedbackBackend; }
|
||||
ScrobblingBackend getScrobblingBackend() const { return _scrobblingBackend; }
|
||||
@@ -144,6 +148,8 @@ namespace lms::db
|
||||
Wt::Dbo::field(a, _subsonicArtistListMode, "subsonic_artist_list_mode");
|
||||
Wt::Dbo::field(a, _uiTheme, "ui_theme");
|
||||
Wt::Dbo::field(a, _uiArtistReleaseSortMethod, "ui_artist_release_sort_method");
|
||||
Wt::Dbo::field(a, _uiEnableInlineArtistRelationships, "ui_enable_inline_artist_relationships");
|
||||
Wt::Dbo::field(a, _uiInlineArtistRelationships, "ui_inline_artist_relationships");
|
||||
Wt::Dbo::field(a, _feedbackBackend, "feedback_backend");
|
||||
Wt::Dbo::field(a, _scrobblingBackend, "scrobbling_backend");
|
||||
Wt::Dbo::field(a, _listenbrainzToken, "listenbrainz_token");
|
||||
@@ -164,6 +170,8 @@ namespace lms::db
|
||||
Wt::WDateTime _lastLogin;
|
||||
UITheme _uiTheme{ defaultUITheme };
|
||||
ReleaseSortMethod _uiArtistReleaseSortMethod{ _defaultUIArtistReleaseSortMethod };
|
||||
bool _uiEnableInlineArtistRelationships{};
|
||||
core::EnumSet<TrackArtistLinkType> _uiInlineArtistRelationships{ TrackArtistLinkType::Composer, TrackArtistLinkType::Performer };
|
||||
FeedbackBackend _feedbackBackend{ defaultFeedbackBackend };
|
||||
ScrobblingBackend _scrobblingBackend{ defaultScrobblingBackend };
|
||||
std::string _listenbrainzToken; // Musicbrainz Identifier
|
||||
|
||||
+107
-1
@@ -25,12 +25,15 @@
|
||||
#include <Wt/WFormModel.h>
|
||||
#include <Wt/WLineEdit.h>
|
||||
#include <Wt/WPushButton.h>
|
||||
#include <Wt/WSelectionBox.h>
|
||||
#include <Wt/WString.h>
|
||||
#include <Wt/WTemplateFormView.h>
|
||||
|
||||
#include "core/IConfig.hpp"
|
||||
#include "core/Service.hpp"
|
||||
#include "core/String.hpp"
|
||||
#include "database/Session.hpp"
|
||||
#include "database/Types.hpp"
|
||||
#include "database/User.hpp"
|
||||
#include "services/auth/IAuthTokenService.hpp"
|
||||
#include "services/auth/IPasswordService.hpp"
|
||||
@@ -46,6 +49,44 @@
|
||||
|
||||
namespace lms::ui
|
||||
{
|
||||
namespace
|
||||
{
|
||||
// highly unefficient hack to make WSelectionBox work with Wt::WFormModel
|
||||
class SelectionBox : public Wt::WSelectionBox
|
||||
{
|
||||
public:
|
||||
static inline constexpr std::string_view valueSeparator{ ", " };
|
||||
|
||||
private:
|
||||
void setValueText(const Wt::WString& values) override
|
||||
{
|
||||
std::set<int> selectedIndexes;
|
||||
const std::string strValues{ values.toUTF8() };
|
||||
for (std::string_view value : core::stringUtils::splitString(strValues, valueSeparator))
|
||||
{
|
||||
const int index{ findText(std::string{ value }) };
|
||||
if (index >= 0)
|
||||
selectedIndexes.insert(index);
|
||||
}
|
||||
|
||||
setSelectedIndexes(selectedIndexes);
|
||||
}
|
||||
|
||||
Wt::WString valueText() const override
|
||||
{
|
||||
Wt::WString res;
|
||||
for (int index : selectedIndexes())
|
||||
{
|
||||
if (!res.empty())
|
||||
res += std::string{ valueSeparator };
|
||||
res += itemText(index);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
using namespace db;
|
||||
|
||||
class SettingsModel : public Wt::WFormModel
|
||||
@@ -53,6 +94,8 @@ namespace lms::ui
|
||||
public:
|
||||
// Associate each field with a unique string literal.
|
||||
static inline const Field ArtistReleaseSortMethodField{ "artist-release-sort-method" };
|
||||
static inline const Field EnableInlineArtistRelationships{ "enable-inline-artist-relationships" };
|
||||
static inline const Field InlineArtistRelationships{ "inline-artist-relationships" };
|
||||
static inline const Field TranscodingModeField{ "transcoding-mode" };
|
||||
static inline const Field TranscodeFormatField{ "transcoding-output-format" };
|
||||
static inline const Field TranscodeBitrateField{ "transcoding-output-bitrate" };
|
||||
@@ -72,6 +115,7 @@ namespace lms::ui
|
||||
static inline const Field PasswordConfirmField{ "password-confirm" };
|
||||
|
||||
using ArtistReleaseSortMethodModel = ValueStringModel<db::ReleaseSortMethod>;
|
||||
using ArtistRelationshipsModel = ValueStringModel<db::TrackArtistLinkType>;
|
||||
using TranscodingModeModel = ValueStringModel<MediaPlayer::Settings::Transcoding::Mode>;
|
||||
using ReplayGainModeModel = ValueStringModel<MediaPlayer::Settings::ReplayGain::Mode>;
|
||||
using FeedbackBackendModel = ValueStringModel<db::FeedbackBackend>;
|
||||
@@ -85,6 +129,8 @@ namespace lms::ui
|
||||
initializeModels();
|
||||
|
||||
addField(ArtistReleaseSortMethodField);
|
||||
addField(EnableInlineArtistRelationships);
|
||||
addField(InlineArtistRelationships);
|
||||
addField(TranscodingModeField);
|
||||
addField(TranscodeBitrateField);
|
||||
addField(TranscodeFormatField);
|
||||
@@ -133,6 +179,7 @@ namespace lms::ui
|
||||
}
|
||||
|
||||
std::shared_ptr<ArtistReleaseSortMethodModel> getArtistReleaseSortMethodModel() { return _artistReleaseSortMethodModel; }
|
||||
std::shared_ptr<ArtistRelationshipsModel> getArtistRelationshipsModel() { return _artistRelationshipsModel; }
|
||||
std::shared_ptr<TranscodingModeModel> getTranscodingModeModel() { return _transcodingModeModeModel; }
|
||||
std::shared_ptr<Wt::WAbstractItemModel> getTranscodingOutputBitrateModel() { return _transcodingOutputBitrateModel; }
|
||||
std::shared_ptr<Wt::WAbstractItemModel> getTranscodingOutputFormatModel() { return _transcodingOutputFormatModel; }
|
||||
@@ -148,9 +195,23 @@ namespace lms::ui
|
||||
User::pointer user{ LmsApp->getUser() };
|
||||
|
||||
{
|
||||
auto artistReleaseSortMethodRow{ _artistReleaseSortMethodModel->getRowFromString(valueText(ArtistReleaseSortMethodField)) };
|
||||
const auto artistReleaseSortMethodRow{ _artistReleaseSortMethodModel->getRowFromString(valueText(ArtistReleaseSortMethodField)) };
|
||||
if (artistReleaseSortMethodRow)
|
||||
user.modify()->setUIArtistReleaseSortMethod(_artistReleaseSortMethodModel->getValue(*artistReleaseSortMethodRow));
|
||||
|
||||
const bool enableInlineArtistRelationships{ Wt::asNumber(value(EnableInlineArtistRelationships)) != 0 };
|
||||
user.modify()->setUIEnableInlineArtistRelationships(enableInlineArtistRelationships);
|
||||
|
||||
core::EnumSet<db::TrackArtistLinkType> artistLinkTypes;
|
||||
const std::string relationships{ valueText(InlineArtistRelationships).toUTF8() };
|
||||
for (std::string_view relationship : core::stringUtils::splitString(relationships, SelectionBox::valueSeparator))
|
||||
{
|
||||
auto artistRelationshipRow{ _artistRelationshipsModel->getRowFromString(Wt::WString{ std::string{ relationship } }) };
|
||||
if (artistRelationshipRow)
|
||||
artistLinkTypes.insert(_artistRelationshipsModel->getValue(*artistRelationshipRow));
|
||||
}
|
||||
|
||||
user.modify()->setUIInlineArtistRelationships(artistLinkTypes);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -248,12 +309,30 @@ namespace lms::ui
|
||||
|
||||
const User::pointer user{ LmsApp->getUser() };
|
||||
|
||||
// UI
|
||||
{
|
||||
auto artistReleaseSortMethodRow{ _artistReleaseSortMethodModel->getRowFromValue(user->getUIArtistReleaseSortMethod()) };
|
||||
if (artistReleaseSortMethodRow)
|
||||
setValue(ArtistReleaseSortMethodField, _artistReleaseSortMethodModel->getString(*artistReleaseSortMethodRow));
|
||||
|
||||
setValue(EnableInlineArtistRelationships, user->getUIEnableInlineArtistRelationships());
|
||||
setReadOnly(InlineArtistRelationships, !user->getUIEnableInlineArtistRelationships());
|
||||
|
||||
Wt::WString inlineArtistRelationships;
|
||||
for (db::TrackArtistLinkType artistLinkType : user->getUIInlineArtistRelationships())
|
||||
{
|
||||
if (auto artistRelationshipsRow{ _artistRelationshipsModel->getRowFromValue(artistLinkType) })
|
||||
{
|
||||
if (!inlineArtistRelationships.empty())
|
||||
inlineArtistRelationships += std::string{ SelectionBox::valueSeparator };
|
||||
inlineArtistRelationships += _artistRelationshipsModel->getString(*artistRelationshipsRow);
|
||||
}
|
||||
}
|
||||
|
||||
setValue(InlineArtistRelationships, inlineArtistRelationships);
|
||||
}
|
||||
|
||||
// Audio
|
||||
{
|
||||
const auto settings{ *LmsApp->getMediaPlayer().getSettings() };
|
||||
|
||||
@@ -379,6 +458,15 @@ namespace lms::ui
|
||||
_artistReleaseSortMethodModel->add(Wt::WString::tr("Lms.Settings.original-date-desc"), db::ReleaseSortMethod::OriginalDateDesc);
|
||||
_artistReleaseSortMethodModel->add(Wt::WString::tr("Lms.Settings.name"), db::ReleaseSortMethod::Name);
|
||||
|
||||
_artistRelationshipsModel = std::make_shared<ArtistRelationshipsModel>();
|
||||
_artistRelationshipsModel->add(Wt::WString::trn("Lms.Explore.Artists.linktype-composer", 2), db::TrackArtistLinkType::Composer);
|
||||
_artistRelationshipsModel->add(Wt::WString::trn("Lms.Explore.Artists.linktype-conductor", 2), db::TrackArtistLinkType::Conductor);
|
||||
_artistRelationshipsModel->add(Wt::WString::trn("Lms.Explore.Artists.linktype-lyricist", 2), db::TrackArtistLinkType::Lyricist);
|
||||
_artistRelationshipsModel->add(Wt::WString::trn("Lms.Explore.Artists.linktype-mixer", 2), db::TrackArtistLinkType::Mixer);
|
||||
_artistRelationshipsModel->add(Wt::WString::trn("Lms.Explore.Artists.linktype-performer", 2), db::TrackArtistLinkType::Performer);
|
||||
_artistRelationshipsModel->add(Wt::WString::trn("Lms.Explore.Artists.linktype-producer", 2), db::TrackArtistLinkType::Producer);
|
||||
_artistRelationshipsModel->add(Wt::WString::trn("Lms.Explore.Artists.linktype-remixer", 2), db::TrackArtistLinkType::Remixer);
|
||||
|
||||
_transcodingModeModeModel = std::make_shared<TranscodingModeModel>();
|
||||
_transcodingModeModeModel->add(Wt::WString::tr("Lms.Settings.transcoding-mode.always"), MediaPlayer::Settings::Transcoding::Mode::Always);
|
||||
_transcodingModeModeModel->add(Wt::WString::tr("Lms.Settings.transcoding-mode.never"), MediaPlayer::Settings::Transcoding::Mode::Never);
|
||||
@@ -422,6 +510,7 @@ namespace lms::ui
|
||||
auth::IAuthTokenService& _authTokenService;
|
||||
|
||||
std::shared_ptr<ArtistReleaseSortMethodModel> _artistReleaseSortMethodModel;
|
||||
std::shared_ptr<ArtistRelationshipsModel> _artistRelationshipsModel;
|
||||
std::shared_ptr<TranscodingModeModel> _transcodingModeModeModel;
|
||||
std::shared_ptr<ValueStringModel<Bitrate>> _transcodingOutputBitrateModel;
|
||||
std::shared_ptr<ValueStringModel<TranscodingOutputFormat>> _transcodingOutputFormatModel;
|
||||
@@ -498,6 +587,23 @@ namespace lms::ui
|
||||
auto artistReleaseSortMethod{ std::make_unique<Wt::WComboBox>() };
|
||||
artistReleaseSortMethod->setModel(model->getArtistReleaseSortMethodModel());
|
||||
t->setFormWidget(SettingsModel::ArtistReleaseSortMethodField, std::move(artistReleaseSortMethod));
|
||||
|
||||
auto enableInlineArtistRelationships{ std::make_unique<Wt::WCheckBox>() };
|
||||
auto inlineArtistRelationships{ std::make_unique<SelectionBox>() };
|
||||
inlineArtistRelationships->setSelectionMode(Wt::SelectionMode::Extended);
|
||||
inlineArtistRelationships->setVerticalSize(3);
|
||||
inlineArtistRelationships->setModel(model->getArtistRelationshipsModel());
|
||||
|
||||
auto updateInlineArtistRelationships{ [=](bool readOnly) {
|
||||
model->setReadOnly(SettingsModel::InlineArtistRelationships, readOnly);
|
||||
t->updateModel(model.get());
|
||||
t->updateView(model.get());
|
||||
} };
|
||||
enableInlineArtistRelationships->checked().connect([=] { updateInlineArtistRelationships(false); });
|
||||
enableInlineArtistRelationships->unChecked().connect([=] { updateInlineArtistRelationships(true); });
|
||||
|
||||
t->setFormWidget(SettingsModel::EnableInlineArtistRelationships, std::move(enableInlineArtistRelationships));
|
||||
t->setFormWidget(SettingsModel::InlineArtistRelationships, std::move(inlineArtistRelationships));
|
||||
}
|
||||
|
||||
// Audio
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "database/Session.hpp"
|
||||
#include "database/Track.hpp"
|
||||
#include "database/TrackArtistLink.hpp"
|
||||
#include "database/Types.hpp"
|
||||
#include "database/User.hpp"
|
||||
#include "services/feedback/IFeedbackService.hpp"
|
||||
#include "services/recommendation/IRecommendationService.hpp"
|
||||
@@ -185,6 +186,31 @@ namespace lms::ui
|
||||
|
||||
return core::stringUtils::readAs<ReleaseId::ValueType>(wApp->internalPathNextPart("/release/"));
|
||||
}
|
||||
|
||||
void fillTrackArtistLinks(Wt::WTemplate* trackEntry, db::TrackId trackId)
|
||||
{
|
||||
const User::pointer user{ LmsApp->getUser() };
|
||||
if (!user->getUIEnableInlineArtistRelationships())
|
||||
return;
|
||||
|
||||
const core::EnumSet<db::TrackArtistLinkType> inlineArtistRelationships{ user->getUIInlineArtistRelationships() };
|
||||
if (inlineArtistRelationships.empty())
|
||||
return;
|
||||
|
||||
const std::map<Wt::WString, std::set<ArtistId>> artistsByRole{ TrackListHelpers::getArtistsByRole(trackId, inlineArtistRelationships) };
|
||||
if (artistsByRole.empty())
|
||||
return;
|
||||
|
||||
trackEntry->setCondition("if-has-artist-links", true);
|
||||
Wt::WContainerWidget* artistLinksContainer = trackEntry->bindNew<Wt::WContainerWidget>("artist-links");
|
||||
|
||||
for (const auto& [role, artists] : artistsByRole)
|
||||
{
|
||||
Wt::WTemplate* artistLinkEntry{ artistLinksContainer->addNew<Wt::WTemplate>(Wt::WString::tr("Lms.Explore.Release.template.artist-links-entry")) };
|
||||
artistLinkEntry->bindString("role", role, Wt::TextFormat::Plain);
|
||||
artistLinkEntry->bindWidget("anchors", utils::createArtistAnchorList(std::vector<db::ArtistId>(std::cbegin(artists), std::cend(artists))));
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Release::Release(Filters& filters, PlayQueueController& playQueueController)
|
||||
@@ -415,7 +441,7 @@ namespace lms::ui
|
||||
const db::TrackId trackId{ track->getId() };
|
||||
const auto discNumber{ track->getDiscNumber() };
|
||||
|
||||
Wt::WContainerWidget* container;
|
||||
Wt::WContainerWidget* container{};
|
||||
if (useSubtitleContainers && discNumber)
|
||||
container = getOrAddDiscContainer(*discNumber, track->getDiscSubtitle());
|
||||
else if (hasDiscSubtitle && !discNumber)
|
||||
@@ -437,6 +463,8 @@ namespace lms::ui
|
||||
entry->bindWidget("artists-md", utils::createArtistDisplayNameWithAnchors(track->getArtistDisplayName(), artists));
|
||||
}
|
||||
|
||||
fillTrackArtistLinks(entry, track->getId());
|
||||
|
||||
auto trackNumber{ track->getTrackNumber() };
|
||||
if (trackNumber)
|
||||
{
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
|
||||
#include "TrackListHelpers.hpp"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <Wt/WAnchor.h>
|
||||
#include <Wt/WImage.h>
|
||||
#include <Wt/WPushButton.h>
|
||||
@@ -33,6 +31,7 @@
|
||||
#include "database/Track.hpp"
|
||||
#include "database/TrackArtistLink.hpp"
|
||||
#include "database/TrackLyrics.hpp"
|
||||
#include "database/Types.hpp"
|
||||
#include "database/User.hpp"
|
||||
#include "services/feedback/IFeedbackService.hpp"
|
||||
#include "services/scrobbling/IScrobblingService.hpp"
|
||||
@@ -50,21 +49,14 @@ namespace lms::ui::TrackListHelpers
|
||||
{
|
||||
using namespace db;
|
||||
|
||||
void showTrackInfoModal(db::TrackId trackId, Filters& filters)
|
||||
std::map<Wt::WString, std::set<ArtistId>> getArtistsByRole(db::TrackId trackId, core::EnumSet<db::TrackArtistLinkType> artistLinkTypes)
|
||||
{
|
||||
auto transaction{ LmsApp->getDbSession().createReadTransaction() };
|
||||
|
||||
const db::Track::pointer track{ Track::find(LmsApp->getDbSession(), trackId) };
|
||||
if (!track)
|
||||
return;
|
||||
|
||||
auto trackInfo{ std::make_unique<Template>(Wt::WString::tr("Lms.Explore.Tracks.template.track-info")) };
|
||||
Wt::WWidget* trackInfoPtr{ trackInfo.get() };
|
||||
trackInfo->addFunction("tr", &Wt::WTemplate::Functions::tr);
|
||||
|
||||
std::map<Wt::WString, std::set<ArtistId>> artistMap;
|
||||
|
||||
auto addArtists = [&](TrackArtistLinkType linkType, const char* type) {
|
||||
if (!artistLinkTypes.contains(linkType))
|
||||
return;
|
||||
|
||||
Artist::FindParameters params;
|
||||
params.setTrack(trackId);
|
||||
params.setLinkType(linkType);
|
||||
@@ -73,12 +65,15 @@ namespace lms::ui::TrackListHelpers
|
||||
return;
|
||||
|
||||
Wt::WString typeStr{ Wt::WString::trn(type, artistIds.results.size()) };
|
||||
;
|
||||
|
||||
for (ArtistId artistId : artistIds.results)
|
||||
artistMap[typeStr].insert(artistId);
|
||||
};
|
||||
|
||||
auto addPerformerArtists = [&] {
|
||||
if (!artistLinkTypes.contains(db::TrackArtistLinkType::Performer))
|
||||
return;
|
||||
|
||||
TrackArtistLink::FindParameters params;
|
||||
params.setTrack(trackId);
|
||||
params.setLinkType(TrackArtistLinkType::Performer);
|
||||
@@ -103,6 +98,22 @@ namespace lms::ui::TrackListHelpers
|
||||
artistMap.erase(itRolelessPerformers);
|
||||
}
|
||||
|
||||
return artistMap;
|
||||
}
|
||||
|
||||
void showTrackInfoModal(db::TrackId trackId, Filters& filters)
|
||||
{
|
||||
auto transaction{ LmsApp->getDbSession().createReadTransaction() };
|
||||
|
||||
const db::Track::pointer track{ Track::find(LmsApp->getDbSession(), trackId) };
|
||||
if (!track)
|
||||
return;
|
||||
|
||||
auto trackInfo{ std::make_unique<Template>(Wt::WString::tr("Lms.Explore.Tracks.template.track-info")) };
|
||||
Wt::WWidget* trackInfoPtr{ trackInfo.get() };
|
||||
trackInfo->addFunction("tr", &Wt::WTemplate::Functions::tr);
|
||||
|
||||
std::map<Wt::WString, std::set<ArtistId>> artistMap{ getArtistsByRole(trackId) };
|
||||
if (!artistMap.empty())
|
||||
{
|
||||
trackInfo->setCondition("if-has-artist", true);
|
||||
|
||||
@@ -19,12 +19,18 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
#include <Wt/WString.h>
|
||||
#include <Wt/WWidget.h>
|
||||
|
||||
#include "core/EnumSet.hpp"
|
||||
#include "database/ArtistId.hpp"
|
||||
#include "database/Object.hpp"
|
||||
#include "database/TrackId.hpp"
|
||||
#include "database/Types.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
@@ -39,6 +45,17 @@ namespace lms::ui
|
||||
|
||||
namespace lms::ui::TrackListHelpers
|
||||
{
|
||||
inline constexpr core::EnumSet<db::TrackArtistLinkType> AllArtistRoles{
|
||||
db::TrackArtistLinkType::Composer,
|
||||
db::TrackArtistLinkType::Conductor,
|
||||
db::TrackArtistLinkType::Lyricist,
|
||||
db::TrackArtistLinkType::Mixer,
|
||||
db::TrackArtistLinkType::Remixer,
|
||||
db::TrackArtistLinkType::Performer,
|
||||
db::TrackArtistLinkType::Producer,
|
||||
};
|
||||
|
||||
std::map<Wt::WString, std::set<db::ArtistId>> getArtistsByRole(db::TrackId trackId, core::EnumSet<db::TrackArtistLinkType> artistLinkTypes = AllArtistRoles);
|
||||
void showTrackInfoModal(db::TrackId trackId, Filters& filters);
|
||||
void showTrackLyricsModal(db::TrackId trackId);
|
||||
std::unique_ptr<Wt::WWidget> createEntry(const db::ObjectPtr<db::Track>& track, PlayQueueController& playQueueController, Filters& filters);
|
||||
|
||||
Reference in New Issue
Block a user