Still converting to bootstrap 5. Converted release dropdown
This commit is contained in:
+1
-1
@@ -5,7 +5,7 @@ project(lms)
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake/modules/)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
|
||||
if (UNIX)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined")
|
||||
endif ()
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
${name}${<if-tag>}<span class="badge bg-info ms-2">${tag}</span>${</if-tag>}
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
${<if-edit>}${edit-btn class="btn btn-sm btn-warning me-1"} ${del-btn class="btn btn-sm btn-danger"}${</if-edit>}
|
||||
${<if-edit>}${edit-btn class="btn btn-sm btn-primary me-1"} ${del-btn class="btn btn-sm btn-danger"}${</if-edit>}
|
||||
</div>
|
||||
</div>
|
||||
</message>
|
||||
|
||||
+15
-5
@@ -13,25 +13,35 @@
|
||||
</message>
|
||||
|
||||
<message id="Lms.Explore.template.add-filter">
|
||||
<div class="modal fade" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">${tr:Lms.Explore.add-filter}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="row g-3">
|
||||
<div class="col-12">
|
||||
<label class="form-label" for="${id:type}">
|
||||
${tr:Lms.Explore.type}
|
||||
</label>
|
||||
${type}
|
||||
${type class="form-control"}
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label class="form-label" for="${id:value}">
|
||||
${tr:Lms.Explore.value}
|
||||
</label>
|
||||
${value}
|
||||
${value class="form-control"}
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
</form>
|
||||
<div class="modal-footer">
|
||||
${add-btn class="btn btn-primary me-1"}${cancel-btn class="btn btn-secondary"}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</message>
|
||||
|
||||
</messages>
|
||||
|
||||
+5
-2
@@ -22,12 +22,15 @@
|
||||
<div class="mb-3">
|
||||
${play-btn class="btn btn-outline-primary me-2"}
|
||||
<span class="dropdown">
|
||||
<button class="btn btn-outline-primary" type="button" id="dropdownMenuButton1" data-bs-toggle="dropdown" aria-expanded="false">...</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton1">
|
||||
${more-btn class="btn btn-outline-primary" data-bs-toggle="dropdown" aria-expanded="false"}
|
||||
<ul class="dropdown-menu" aria-labelledby="${id:more-btn}">
|
||||
<li>${play-shuffled class="btn dropdown-item"}</li>
|
||||
<li>${play-last class="btn dropdown-item"}</li>
|
||||
<li>${star class="btn dropdown-item"}</li>
|
||||
${<if-has-mbid>}
|
||||
<li><a href="${mbid-link}" target="_blank" class="dropdown-item">${tr:Lms.Explore.musicbrainz-release}</a></li>
|
||||
${</if-has-mbid>}
|
||||
<li>${download class="btn dropdown-item"}</li>
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -31,34 +31,43 @@
|
||||
|
||||
namespace StringUtils {
|
||||
|
||||
[[nodiscard]]
|
||||
std::vector<std::string>
|
||||
splitStringCopy(std::string_view string, std::string_view separators);
|
||||
|
||||
[[nodiscard]]
|
||||
std::vector<std::string_view>
|
||||
splitString(std::string_view string, std::string_view separators);
|
||||
|
||||
[[nodiscard]]
|
||||
std::string
|
||||
joinStrings(const std::vector<std::string>& strings, const std::string& delimiter);
|
||||
|
||||
[[nodiscard]]
|
||||
std::string
|
||||
stringTrim(std::string_view str, std::string_view whitespaces = " \t");
|
||||
|
||||
[[nodiscard]]
|
||||
std::string
|
||||
stringTrimEnd(std::string_view str, std::string_view whitespaces = " \t");
|
||||
|
||||
[[nodiscard]]
|
||||
std::string
|
||||
stringToLower(std::string_view str);
|
||||
|
||||
void
|
||||
stringToLower(std::string& str);
|
||||
|
||||
[[nodiscard]]
|
||||
std::string
|
||||
stringToUpper(const std::string& str);
|
||||
|
||||
[[nodiscard]]
|
||||
std::string
|
||||
bufferToString(const std::vector<unsigned char>& data);
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]]
|
||||
std::optional<T> readAs(std::string_view str)
|
||||
{
|
||||
T res;
|
||||
@@ -72,21 +81,27 @@ std::optional<T> readAs(std::string_view str)
|
||||
}
|
||||
|
||||
template<>
|
||||
[[nodiscard]]
|
||||
std::optional<std::string>
|
||||
readAs(std::string_view str);
|
||||
|
||||
[[nodiscard]]
|
||||
std::string
|
||||
replaceInString(const std::string& str, const std::string& from, const std::string& to);
|
||||
|
||||
[[nodiscard]]
|
||||
std::string
|
||||
jsEscape(const std::string& str);
|
||||
|
||||
[[nodiscard]]
|
||||
std::string
|
||||
escapeString(std::string_view str, std::string_view charsToEscape, char escapeChar);
|
||||
|
||||
[[nodiscard]]
|
||||
bool
|
||||
stringEndsWith(const std::string& str, const std::string& ending);
|
||||
|
||||
[[nodiscard]]
|
||||
std::optional<std::string>
|
||||
stringFromHex(const std::string& str);
|
||||
|
||||
|
||||
@@ -76,6 +76,28 @@ TEST(StringUtils, splitString)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(StringUtils, splitStringCopy)
|
||||
{
|
||||
{
|
||||
const std::string test {"test=foo"};
|
||||
|
||||
const std::vector<std::string> strings {StringUtils::splitStringCopy(test, "=")};
|
||||
ASSERT_EQ(strings.size(), 2);
|
||||
EXPECT_EQ(strings[0], "test");
|
||||
EXPECT_EQ(strings[1], "foo");
|
||||
}
|
||||
|
||||
{
|
||||
const std::string test {"test=foo bar"};
|
||||
|
||||
const std::vector<std::string> strings {StringUtils::splitStringCopy(test, "=")};
|
||||
ASSERT_EQ(strings.size(), 2);
|
||||
EXPECT_EQ(strings[0], "test");
|
||||
EXPECT_EQ(strings[1], "foo bar");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StringUtils, escapeString)
|
||||
{
|
||||
EXPECT_EQ(StringUtils::escapeString("", "*", ' '), "");
|
||||
|
||||
@@ -23,6 +23,7 @@ add_executable(lms
|
||||
ui/common/LoginNameValidator.cpp
|
||||
ui/common/MandatoryValidator.cpp
|
||||
ui/common/PasswordValidator.cpp
|
||||
ui/common/Template.cpp
|
||||
ui/common/UUIDValidator.cpp
|
||||
ui/explore/ArtistCollector.cpp
|
||||
ui/explore/ArtistListHelpers.cpp
|
||||
@@ -33,7 +34,6 @@ add_executable(lms
|
||||
ui/explore/Filters.cpp
|
||||
ui/explore/ReleaseCollector.cpp
|
||||
ui/explore/ReleaseListHelpers.cpp
|
||||
ui/explore/ReleasePopup.cpp
|
||||
ui/explore/ReleasesView.cpp
|
||||
ui/explore/ReleaseView.cpp
|
||||
ui/explore/SearchView.cpp
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Template.hpp"
|
||||
#include "utils/String.hpp"
|
||||
|
||||
namespace UserInterface
|
||||
{
|
||||
void
|
||||
Template::applyArguments(WWidget* widget, const std::vector<Wt::WString>& args)
|
||||
{
|
||||
for (const Wt::WString& arg : args)
|
||||
{
|
||||
const std::vector<std::string> operands {StringUtils::splitStringCopy(arg.toUTF8(), "=")};
|
||||
|
||||
if (operands.size() == 2)
|
||||
{
|
||||
if (operands[0] == "class")
|
||||
widget->addStyleClass(operands[1]);
|
||||
else
|
||||
widget->setAttributeValue(operands[0], operands[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace UserInterface
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Emeric Poupon
|
||||
* Copyright (C) 2022 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
@@ -19,15 +19,18 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Wt/WWidget.h>
|
||||
|
||||
#include "services/database/Types.hpp"
|
||||
#include "PlayQueueAction.hpp"
|
||||
#include <Wt/WTemplate.h>
|
||||
|
||||
namespace UserInterface
|
||||
{
|
||||
void displayReleasePopupMenu(Wt::WInteractWidget& target,
|
||||
Database::ReleaseId releaseId,
|
||||
PlayQueueActionReleaseSignal& releasesAction);
|
||||
} // namespace UserInterface
|
||||
|
||||
class Template : public Wt::WTemplate
|
||||
{
|
||||
public:
|
||||
using Wt::WTemplate::WTemplate;
|
||||
|
||||
private:
|
||||
void applyArguments(Wt::WWidget* w, const std::vector<Wt::WString>& args) override;
|
||||
};
|
||||
|
||||
} // namespace UserInterface
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ReleasePopup.hpp"
|
||||
|
||||
#include <Wt/WPopupMenu.h>
|
||||
|
||||
#include "services/database/Release.hpp"
|
||||
#include "services/database/Session.hpp"
|
||||
#include "services/database/User.hpp"
|
||||
#include "services/scrobbling/IScrobblingService.hpp"
|
||||
#include "resource/DownloadResource.hpp"
|
||||
#include "utils/Service.hpp"
|
||||
#include "LmsApplication.hpp"
|
||||
|
||||
namespace UserInterface
|
||||
{
|
||||
void
|
||||
displayReleasePopupMenu(Wt::WInteractWidget& target,
|
||||
Database::ReleaseId releaseId,
|
||||
PlayQueueActionReleaseSignal& releasesAction)
|
||||
{
|
||||
Wt::WPopupMenu* popup {LmsApp->createPopupMenu()};
|
||||
|
||||
popup->addItem(Wt::WString::tr("Lms.Explore.play-shuffled"))
|
||||
->triggered().connect(&target, [&releasesAction, releaseId]
|
||||
{
|
||||
releasesAction.emit(PlayQueueAction::PlayShuffled, {releaseId});
|
||||
});
|
||||
popup->addItem(Wt::WString::tr("Lms.Explore.play-last"))
|
||||
->triggered().connect(&target, [&releasesAction, releaseId]
|
||||
{
|
||||
releasesAction.emit(PlayQueueAction::PlayLast, {releaseId});
|
||||
});
|
||||
|
||||
const bool isStarred {Service<Scrobbling::IScrobblingService>::get()->isStarred(LmsApp->getUserId(), releaseId)};
|
||||
popup->addItem(Wt::WString::tr(isStarred ? "Lms.Explore.unstar" : "Lms.Explore.star"))
|
||||
->triggered().connect(&target, [=]
|
||||
{
|
||||
if (isStarred)
|
||||
Service<Scrobbling::IScrobblingService>::get()->unstar(LmsApp->getUserId(), releaseId);
|
||||
else
|
||||
Service<Scrobbling::IScrobblingService>::get()->star(LmsApp->getUserId(), releaseId);
|
||||
});
|
||||
popup->addItem(Wt::WString::tr("Lms.Explore.download"))
|
||||
->setLink(Wt::WLink {std::make_unique<DownloadReleaseResource>(releaseId)});
|
||||
|
||||
popup->popup(&target);
|
||||
}
|
||||
} // namespace UserInterface
|
||||
@@ -32,8 +32,8 @@
|
||||
#include "services/database/Session.hpp"
|
||||
#include "services/database/Track.hpp"
|
||||
#include "services/recommendation/IRecommendationService.hpp"
|
||||
#include "services/scrobbling/IScrobblingService.hpp"
|
||||
#include "utils/Logger.hpp"
|
||||
#include "utils/String.hpp"
|
||||
|
||||
#include "resource/DownloadResource.hpp"
|
||||
#include "resource/CoverResource.hpp"
|
||||
@@ -42,7 +42,6 @@
|
||||
#include "LmsApplicationException.hpp"
|
||||
#include "MediaPlayer.hpp"
|
||||
#include "ReleaseListHelpers.hpp"
|
||||
#include "ReleasePopup.hpp"
|
||||
#include "TrackPopup.hpp"
|
||||
#include "TrackStringUtils.hpp"
|
||||
|
||||
@@ -51,10 +50,11 @@ using namespace Database;
|
||||
namespace UserInterface {
|
||||
|
||||
Release::Release(Filters* filters)
|
||||
: Wt::WTemplate {Wt::WString::tr("Lms.Explore.Release.template")}
|
||||
: Template {Wt::WString::tr("Lms.Explore.Release.template")}
|
||||
, _filters {filters}
|
||||
{
|
||||
addFunction("tr", &Wt::WTemplate::Functions::tr);
|
||||
addFunction("id", &Wt::WTemplate::Functions::id);
|
||||
|
||||
wApp->internalPathChanged().connect(this, [this]
|
||||
{
|
||||
@@ -159,21 +159,45 @@ Release::refreshView()
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Wt::WPushButton* playBtn {bindNew<Wt::WPushButton>("play-btn", Wt::WString::tr("Lms.Explore.template.play-btn"), Wt::TextFormat::XHTML)};
|
||||
playBtn->clicked().connect([=]
|
||||
bindNew<Wt::WPushButton>("more-btn", Wt::WString::tr("Lms.Explore.template.more-btn"), Wt::TextFormat::XHTML);
|
||||
bindNew<Wt::WPushButton>("play-btn", Wt::WString::tr("Lms.Explore.template.play-btn"), Wt::TextFormat::XHTML)
|
||||
->clicked().connect([=]
|
||||
{
|
||||
releasesAction.emit(PlayQueueAction::Play, {*releaseId});
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
Wt::WPushButton* playShuffled {bindNew<Wt::WPushButton>("play-shuffled", Wt::WString::tr("Lms.Explore.play-shuffled"), Wt::TextFormat::Plain)};
|
||||
playShuffled->setDefault(false);
|
||||
playShuffled->clicked().connect([=]
|
||||
bindNew<Wt::WPushButton>("play-shuffled", Wt::WString::tr("Lms.Explore.play-shuffled"), Wt::TextFormat::Plain)
|
||||
->clicked().connect([=]
|
||||
{
|
||||
releasesAction.emit(PlayQueueAction::PlayShuffled, {*releaseId});
|
||||
});
|
||||
|
||||
bindNew<Wt::WPushButton>("play-last", Wt::WString::tr("Lms.Explore.play-last"), Wt::TextFormat::Plain)
|
||||
->clicked().connect([=]
|
||||
{
|
||||
releasesAction.emit(PlayQueueAction::PlayLast, {*releaseId});
|
||||
});
|
||||
|
||||
bindNew<Wt::WPushButton>("download", Wt::WString::tr("Lms.Explore.download"))
|
||||
->setLink(Wt::WLink {std::make_unique<DownloadReleaseResource>(*releaseId)});
|
||||
|
||||
{
|
||||
auto isStarred {[=] { return Service<Scrobbling::IScrobblingService>::get()->isStarred(LmsApp->getUserId(), *releaseId); }};
|
||||
|
||||
Wt::WPushButton* star {bindNew<Wt::WPushButton>("star", Wt::WString::tr(isStarred() ? "Lms.Explore.unstar" : "Lms.Explore.star"))};
|
||||
star->clicked().connect([=]
|
||||
{
|
||||
if (isStarred())
|
||||
{
|
||||
Service<Scrobbling::IScrobblingService>::get()->unstar(LmsApp->getUserId(), *releaseId);
|
||||
star->setText(Wt::WString::tr("Lms.Explore.star"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Service<Scrobbling::IScrobblingService>::get()->star(LmsApp->getUserId(), *releaseId);
|
||||
star->setText(Wt::WString::tr("Lms.Explore.unstar"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Wt::WContainerWidget* rootContainer {bindNew<Wt::WContainerWidget>("container")};
|
||||
@@ -265,12 +289,6 @@ Release::refreshView()
|
||||
tracksAction.emit(PlayQueueAction::Play, {trackId});
|
||||
});
|
||||
|
||||
Wt::WPushButton* moreBtn {entry->bindNew<Wt::WPushButton>("more-btn", Wt::WString::tr("Lms.Explore.template.more-btn"), Wt::TextFormat::XHTML)};
|
||||
moreBtn->clicked().connect([=]
|
||||
{
|
||||
displayTrackPopupMenu(*moreBtn, trackId, tracksAction);
|
||||
});
|
||||
|
||||
entry->bindString("duration", durationToString(track->getDuration()), Wt::TextFormat::Plain);
|
||||
|
||||
LmsApp->getMediaPlayer().trackLoaded.connect(entry, [=] (TrackId loadedTrackId)
|
||||
|
||||
@@ -19,10 +19,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unordered_set>
|
||||
#include <Wt/WTemplate.h>
|
||||
|
||||
#include "services/database/Object.hpp"
|
||||
#include "common/Template.hpp"
|
||||
#include "PlayQueueAction.hpp"
|
||||
|
||||
namespace Database
|
||||
@@ -33,7 +31,9 @@ namespace Database
|
||||
namespace UserInterface
|
||||
{
|
||||
class Filters;
|
||||
class Release : public Wt::WTemplate
|
||||
|
||||
|
||||
class Release : public Template
|
||||
{
|
||||
public:
|
||||
Release(Filters* filters);
|
||||
|
||||
Reference in New Issue
Block a user