mirror of
https://gitlab.com/kelteseth/ScreenPlay.git
synced 2024-11-22 02:32:29 +01:00
Add timeline reset
This commit is contained in:
parent
00d77d815e
commit
358800a94c
@ -4,9 +4,8 @@
|
|||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QPoint>
|
#include <QPoint>
|
||||||
#include <QVariantMap>
|
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <QtWebSockets/QWebSocket>
|
#include <QVariantMap>
|
||||||
|
|
||||||
#include "ScreenPlayUtil/projectfile.h"
|
#include "ScreenPlayUtil/projectfile.h"
|
||||||
#include "ScreenPlayUtil/util.h"
|
#include "ScreenPlayUtil/util.h"
|
||||||
@ -51,7 +50,6 @@ public:
|
|||||||
Q_INVOKABLE bool removeAllWidgets(bool saveToProfile = false);
|
Q_INVOKABLE bool removeAllWidgets(bool saveToProfile = false);
|
||||||
Q_INVOKABLE bool removeWallpaperAt(const int index);
|
Q_INVOKABLE bool removeWallpaperAt(const int index);
|
||||||
|
|
||||||
|
|
||||||
Q_INVOKABLE ScreenPlayWallpaper* getWallpaperByAppID(const QString& appID);
|
Q_INVOKABLE ScreenPlayWallpaper* getWallpaperByAppID(const QString& appID);
|
||||||
|
|
||||||
Q_INVOKABLE bool moveTimelineAt(
|
Q_INVOKABLE bool moveTimelineAt(
|
||||||
@ -62,12 +60,11 @@ public:
|
|||||||
|
|
||||||
Q_INVOKABLE QString getTimeString(double relativeLinePosition);
|
Q_INVOKABLE QString getTimeString(double relativeLinePosition);
|
||||||
|
|
||||||
|
|
||||||
Q_INVOKABLE bool addTimelineAt(
|
Q_INVOKABLE bool addTimelineAt(
|
||||||
const int index,
|
const int index,
|
||||||
const float reltiaveLinePosition,
|
const float reltiaveLinePosition,
|
||||||
QString identifier);
|
QString identifier);
|
||||||
|
Q_INVOKABLE void removeAllTimlineSections();
|
||||||
Q_INVOKABLE bool removeTimelineAt(const int index);
|
Q_INVOKABLE bool removeTimelineAt(const int index);
|
||||||
Q_INVOKABLE QVariantMap initialStopPositions();
|
Q_INVOKABLE QVariantMap initialStopPositions();
|
||||||
Q_INVOKABLE bool setWallpaperAtTimelineIndex(
|
Q_INVOKABLE bool setWallpaperAtTimelineIndex(
|
||||||
@ -184,8 +181,6 @@ private:
|
|||||||
std::shared_ptr<MonitorListModel> m_monitorListModel;
|
std::shared_ptr<MonitorListModel> m_monitorListModel;
|
||||||
std::shared_ptr<Settings> m_settings;
|
std::shared_ptr<Settings> m_settings;
|
||||||
std::unique_ptr<QLocalServer> m_server;
|
std::unique_ptr<QLocalServer> m_server;
|
||||||
std::unique_ptr<QWebSocketServer> m_websocketServer;
|
|
||||||
QVector<QWebSocket*> m_connections;
|
|
||||||
|
|
||||||
std::shared_ptr<WallpaperTimelineSection> m_activeWallpaperTimeline;
|
std::shared_ptr<WallpaperTimelineSection> m_activeWallpaperTimeline;
|
||||||
QVector<std::shared_ptr<WallpaperTimelineSection>> m_wallpaperTimelineSectionsList;
|
QVector<std::shared_ptr<WallpaperTimelineSection>> m_wallpaperTimelineSectionsList;
|
||||||
@ -201,6 +196,5 @@ private:
|
|||||||
// We use a 24 hour system
|
// We use a 24 hour system
|
||||||
const QString m_timelineTimeFormat = "hh:mm:ss";
|
const QString m_timelineTimeFormat = "hh:mm:ss";
|
||||||
const quint16 m_webSocketPort = 16395;
|
const quint16 m_webSocketPort = 16395;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,8 @@ struct WallpaperTimelineSection {
|
|||||||
QTime startTime;
|
QTime startTime;
|
||||||
QTime endTime;
|
QTime endTime;
|
||||||
// Data from the profiles.json that we need when we
|
// Data from the profiles.json that we need when we
|
||||||
// enable this section of the pipeline
|
// enable this section of the pipeline. We keep a copy
|
||||||
|
// here when this timeline needs to become active
|
||||||
std::vector<WallpaperData> wallpaperData;
|
std::vector<WallpaperData> wallpaperData;
|
||||||
// All active wallpaper.
|
// All active wallpaper.
|
||||||
std::vector<std::shared_ptr<ScreenPlayWallpaper>> activeWallpaperList;
|
std::vector<std::shared_ptr<ScreenPlayWallpaper>> activeWallpaperList;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"profiles": [
|
"profiles": [
|
||||||
{
|
{
|
||||||
"appdrawer": [],
|
|
||||||
"name": "default",
|
"name": "default",
|
||||||
"timelineWallpaper": [
|
"timelineWallpaper": [
|
||||||
{
|
{
|
||||||
|
@ -63,7 +63,15 @@ Control {
|
|||||||
}
|
}
|
||||||
timeLine.sectionsList = []
|
timeLine.sectionsList = []
|
||||||
|
|
||||||
init()
|
App.screenPlayManager.removeAllTimlineSections()
|
||||||
|
|
||||||
|
const position = 1.0
|
||||||
|
const identifier = App.util.generateRandomString(4);
|
||||||
|
const sectionObject = timeLine.addSection(identifier,position)
|
||||||
|
App.screenPlayManager.addTimelineAt(
|
||||||
|
sectionObject.index,
|
||||||
|
sectionObject.relativeLinePosition,
|
||||||
|
sectionObject.identifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
function createAllSections(initialStopPositions) {
|
function createAllSections(initialStopPositions) {
|
||||||
@ -242,11 +250,13 @@ Control {
|
|||||||
|
|
||||||
|
|
||||||
//timeLine.sectionsList[i].relativeLinePosition =prevPos / timeLine.width
|
//timeLine.sectionsList[i].relativeLinePosition =prevPos / timeLine.width
|
||||||
//print("sections: ", i, "prev minimum ",prevPos,"next maximum", nextPos, timeLine.sectionsList[i].relativeLinePosition)
|
print("sections: ", i, "prev minimum ",prevPos,"next maximum", nextPos, timeLine.sectionsList[i].relativeLinePosition)
|
||||||
}
|
}
|
||||||
|
print("++++++++++++++++++")
|
||||||
for (let i = 0; i < timeLine.sectionsList.length; i++) {
|
for (let i = 0; i < timeLine.sectionsList.length; i++) {
|
||||||
let section = timeLine.sectionsList[i]
|
let section = timeLine.sectionsList[i]
|
||||||
section.relativeLinePosition = section.lineHandle.linePosition
|
section.relativeLinePosition = section.lineHandle.linePosition
|
||||||
|
// print(section.relativeLinePosition, section.lineHandle.lineMinimum, section.lineHandle.lineMaximum)
|
||||||
}
|
}
|
||||||
updateIndicatorPositions()
|
updateIndicatorPositions()
|
||||||
updateLastHandle()
|
updateLastHandle()
|
||||||
@ -342,7 +352,7 @@ Control {
|
|||||||
text: "➕"
|
text: "➕"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
const p = this.x / timeLine.width
|
const p = this.x / timeLine.width
|
||||||
const position = p.toFixed(2)
|
const position = p.toFixed(4)
|
||||||
const identifier = App.util.generateRandomString(4);
|
const identifier = App.util.generateRandomString(4);
|
||||||
const sectionObject = timeLine.addSection(identifier,position)
|
const sectionObject = timeLine.addSection(identifier,position)
|
||||||
App.screenPlayManager.addTimelineAt(
|
App.screenPlayManager.addTimelineAt(
|
||||||
|
@ -93,7 +93,6 @@ void ScreenPlayManager::checkActiveWallpaperTimeline()
|
|||||||
// TODO: Check if we can reuse some active wallpaper
|
// TODO: Check if we can reuse some active wallpaper
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Qml function, because we cannot create the WallpaperData in qml.
|
\brief Qml function, because we cannot create the WallpaperData in qml.
|
||||||
*/
|
*/
|
||||||
@ -125,12 +124,12 @@ bool ScreenPlayManager::setWallpaperAtTimelineIndex(
|
|||||||
for (auto& timelineSection : m_wallpaperTimelineSectionsList) {
|
for (auto& timelineSection : m_wallpaperTimelineSectionsList) {
|
||||||
const bool sameIndex = timelineSection->index == timelineIndex;
|
const bool sameIndex = timelineSection->index == timelineIndex;
|
||||||
const bool sameIdentifier = timelineSection->identifier == identifier;
|
const bool sameIdentifier = timelineSection->identifier == identifier;
|
||||||
if(sameIndex && sameIdentifier){
|
if (sameIndex && sameIdentifier) {
|
||||||
// TODO vec
|
// TODO vec
|
||||||
timelineSection->wallpaperData = {wallpaperData};
|
timelineSection->wallpaperData = { wallpaperData };
|
||||||
break;
|
break;
|
||||||
} else if(sameIdentifier || sameIdentifier){
|
} else if (sameIdentifier || sameIdentifier) {
|
||||||
qCritical()<< "Invalid";
|
qCritical() << "Invalid";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,13 +280,13 @@ bool ScreenPlayManager::removeAllWallpapers(bool saveToProfile)
|
|||||||
{
|
{
|
||||||
|
|
||||||
if (m_wallpaperTimelineSectionsList.empty()) {
|
if (m_wallpaperTimelineSectionsList.empty()) {
|
||||||
qWarning() << "Trying to remove all Wallpapers while m_screenPlayWallpapers is not empty.";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList appIDs;
|
QStringList appIDs;
|
||||||
auto activeTimelineSection = findActiveSection();
|
auto activeTimelineSection = findActiveSection();
|
||||||
if (!activeTimelineSection) {
|
if (!activeTimelineSection) {
|
||||||
|
qWarning() << "Trying to remove all Wallpapers while findActiveSection is empty.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Do not remove items from the vector you iterate on.
|
// Do not remove items from the vector you iterate on.
|
||||||
@ -313,7 +312,6 @@ bool ScreenPlayManager::removeAllWallpapers(bool saveToProfile)
|
|||||||
bool ScreenPlayManager::removeAllWidgets(bool saveToProfile)
|
bool ScreenPlayManager::removeAllWidgets(bool saveToProfile)
|
||||||
{
|
{
|
||||||
if (m_screenPlayWidgets.empty()) {
|
if (m_screenPlayWidgets.empty()) {
|
||||||
qWarning() << "Trying to remove all Widgets while m_screenPlayWidgets is empty.";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,8 +436,8 @@ ScreenPlayWallpaper* ScreenPlayManager::getWallpaperByAppID(const QString& appID
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We always handle the endTimeString, because it is the handle for the
|
// We always handle the endTimeString, because it is the handle for the
|
||||||
// timeline. The last, default, timeline does not have a handle.
|
// timeline. The last, default, timeline does not have a handle.
|
||||||
bool ScreenPlayManager::moveTimelineAt(const int index, const QString identifier, const float relativePosition, QString positionTimeString)
|
bool ScreenPlayManager::moveTimelineAt(const int index, const QString identifier, const float relativePosition, QString positionTimeString)
|
||||||
{
|
{
|
||||||
m_contentTimer.stop();
|
m_contentTimer.stop();
|
||||||
@ -466,11 +464,16 @@ bool ScreenPlayManager::moveTimelineAt(const int index, const QString identifier
|
|||||||
wallpapterTimelineSectionNext->startTime = newPositionTime;
|
wallpapterTimelineSectionNext->startTime = newPositionTime;
|
||||||
}
|
}
|
||||||
printTimelines();
|
printTimelines();
|
||||||
|
emit requestSaveProfiles();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ScreenPlayManager::getTimeString(double relativeLinePosition)
|
QString ScreenPlayManager::getTimeString(double relativeLinePosition)
|
||||||
{
|
{
|
||||||
|
if (relativeLinePosition == 1.0) {
|
||||||
|
// We overwrite the endTime here
|
||||||
|
return "23:59:59";
|
||||||
|
}
|
||||||
const double totalHours = relativeLinePosition * 24;
|
const double totalHours = relativeLinePosition * 24;
|
||||||
int hours = static_cast<int>(std::floor(totalHours)); // Gets the whole hour part
|
int hours = static_cast<int>(std::floor(totalHours)); // Gets the whole hour part
|
||||||
double fractionalHours = totalHours - hours;
|
double fractionalHours = totalHours - hours;
|
||||||
@ -545,23 +548,51 @@ bool ScreenPlayManager::addTimelineAt(const int index, const float reltiaveLineP
|
|||||||
newTimelineSection->index = index;
|
newTimelineSection->index = index;
|
||||||
newTimelineSection->identifier = identifier;
|
newTimelineSection->identifier = identifier;
|
||||||
newTimelineSection->endTime = newStopPositionTime;
|
newTimelineSection->endTime = newStopPositionTime;
|
||||||
// We can use the given index here, because it points
|
// In case we do a full reset, we must set the start time manually
|
||||||
// the the current item at that index, and we have not yet
|
if (m_wallpaperTimelineSectionsList.empty()) {
|
||||||
// added our new timelineSection to our list.
|
newTimelineSection->startTime = QTime::fromString("00:00:00", m_timelineTimeFormat);
|
||||||
newTimelineSection->startTime = m_wallpaperTimelineSectionsList.at(index)->startTime;
|
} else {
|
||||||
|
|
||||||
|
// We can use the given index here, because it points
|
||||||
|
// the the current item at that index, and we have not yet
|
||||||
|
// added our new timelineSection to our list.
|
||||||
|
newTimelineSection->startTime = m_wallpaperTimelineSectionsList.at(index)->startTime;
|
||||||
|
}
|
||||||
|
|
||||||
const bool isLast = (m_wallpaperTimelineSectionsList.length() - 1) == index;
|
const bool isLast = (m_wallpaperTimelineSectionsList.length() - 1) == index;
|
||||||
if(isLast){
|
if (isLast) {
|
||||||
m_wallpaperTimelineSectionsList.last()->startTime = newTimelineSection->endTime;
|
m_wallpaperTimelineSectionsList.last()->startTime = newTimelineSection->endTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_wallpaperTimelineSectionsList.append(newTimelineSection);
|
m_wallpaperTimelineSectionsList.append(newTimelineSection);
|
||||||
|
|
||||||
updateIndices();
|
updateIndices();
|
||||||
printTimelines();
|
printTimelines();
|
||||||
|
emit requestSaveProfiles();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScreenPlayManager::removeAllTimlineSections()
|
||||||
|
{
|
||||||
|
m_contentTimer.stop();
|
||||||
|
auto updateTimer = qScopeGuard([this] { m_contentTimer.start(); });
|
||||||
|
|
||||||
|
// First check if there is any active wallpaper that we save in
|
||||||
|
// this shared ptr. We can have many timlines, but the current timeline
|
||||||
|
// can have no active wallpaper
|
||||||
|
if (m_activeWallpaperTimeline) {
|
||||||
|
// Close the localsocket
|
||||||
|
for (auto& activeWallpaper : m_activeWallpaperTimeline->activeWallpaperList) {
|
||||||
|
activeWallpaper->close();
|
||||||
|
}
|
||||||
|
// Reset all active wallpaper
|
||||||
|
m_activeWallpaperTimeline->activeWallpaperList.clear();
|
||||||
|
m_activeWallpaperTimeline.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_wallpaperTimelineSectionsList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
bool ScreenPlayManager::removeTimelineAt(const int index)
|
bool ScreenPlayManager::removeTimelineAt(const int index)
|
||||||
{
|
{
|
||||||
printTimelines();
|
printTimelines();
|
||||||
@ -603,9 +634,9 @@ bool ScreenPlayManager::removeTimelineAt(const int index)
|
|||||||
// check for the timelineAfter, because the last timeline
|
// check for the timelineAfter, because the last timeline
|
||||||
// cannot be deleted
|
// cannot be deleted
|
||||||
QTime endTime;
|
QTime endTime;
|
||||||
if(index == 0){
|
if (index == 0) {
|
||||||
endTime = QTime::fromString("00:00:00", m_timelineTimeFormat);
|
endTime = QTime::fromString("00:00:00", m_timelineTimeFormat);
|
||||||
}else {
|
} else {
|
||||||
endTime = m_wallpaperTimelineSectionsList.at(index - 1)->endTime;
|
endTime = m_wallpaperTimelineSectionsList.at(index - 1)->endTime;
|
||||||
}
|
}
|
||||||
auto timelineAfter = m_wallpaperTimelineSectionsList.at(index + 1);
|
auto timelineAfter = m_wallpaperTimelineSectionsList.at(index + 1);
|
||||||
@ -618,9 +649,8 @@ bool ScreenPlayManager::removeTimelineAt(const int index)
|
|||||||
m_wallpaperTimelineSectionsList.removeAt(index);
|
m_wallpaperTimelineSectionsList.removeAt(index);
|
||||||
updateIndices();
|
updateIndices();
|
||||||
printTimelines();
|
printTimelines();
|
||||||
return true;
|
|
||||||
|
|
||||||
printTimelines();
|
emit requestSaveProfiles();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -628,7 +658,7 @@ void ScreenPlayManager::printTimelines()
|
|||||||
{
|
{
|
||||||
std::cout << "#############################\n";
|
std::cout << "#############################\n";
|
||||||
for (auto& timeline : m_wallpaperTimelineSectionsList) {
|
for (auto& timeline : m_wallpaperTimelineSectionsList) {
|
||||||
std::cout <<timeline->index << ": " << timeline->identifier.toStdString() << "\t" << timeline->relativePosition << " start: " << timeline->startTime.toString().toStdString() << " end: " << timeline->endTime.toString().toStdString() << std::endl;
|
std::cout << timeline->index << ": " << timeline->identifier.toStdString() << "\t" << timeline->relativePosition << " start: " << timeline->startTime.toString().toStdString() << " end: " << timeline->endTime.toString().toStdString() << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -636,7 +666,7 @@ QVariantMap ScreenPlayManager::initialStopPositions()
|
|||||||
{
|
{
|
||||||
QVariantMap sectionPositions;
|
QVariantMap sectionPositions;
|
||||||
for (const auto& timelineSection : m_wallpaperTimelineSectionsList) {
|
for (const auto& timelineSection : m_wallpaperTimelineSectionsList) {
|
||||||
sectionPositions.insert({timelineSection->identifier},{timelineSection->relativePosition});
|
sectionPositions.insert({ timelineSection->identifier }, { timelineSection->relativePosition });
|
||||||
}
|
}
|
||||||
return sectionPositions;
|
return sectionPositions;
|
||||||
}
|
}
|
||||||
@ -796,30 +826,39 @@ bool ScreenPlayManager::saveProfiles()
|
|||||||
{
|
{
|
||||||
m_saveLimiter.stop();
|
m_saveLimiter.stop();
|
||||||
|
|
||||||
// QJsonArray wallpaper {};
|
QJsonArray timelineWallpaperList {};
|
||||||
// for (const auto& activeWallpaper : std::as_const(m_screenPlayWallpapers)) {
|
for (const auto& activeTimelineWallpaper : std::as_const(m_wallpaperTimelineSectionsList)) {
|
||||||
// wallpaper.append(activeWallpaper->getActiveSettingsJson());
|
QJsonObject timelineWallpaper;
|
||||||
// }
|
timelineWallpaper.insert("startTime", activeTimelineWallpaper->startTime.toString());
|
||||||
|
timelineWallpaper.insert("endTime", activeTimelineWallpaper->endTime.toString());
|
||||||
|
QJsonArray wallpaper;
|
||||||
|
for (const auto& activeWallpaper : activeTimelineWallpaper->activeWallpaperList) {
|
||||||
|
wallpaper.append(activeWallpaper->getActiveSettingsJson());
|
||||||
|
}
|
||||||
|
timelineWallpaper.insert("wallpaper", wallpaper);
|
||||||
|
|
||||||
QJsonArray widgets {};
|
timelineWallpaperList.append(timelineWallpaper);
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonArray widgetList {};
|
||||||
for (const auto& activeWidget : std::as_const(m_screenPlayWidgets)) {
|
for (const auto& activeWidget : std::as_const(m_screenPlayWidgets)) {
|
||||||
widgets.append(activeWidget->getActiveSettingsJson());
|
widgetList.append(activeWidget->getActiveSettingsJson());
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject profileDefault;
|
QJsonObject profileDefault;
|
||||||
profileDefault.insert("appdrawer", QJsonArray {});
|
profileDefault.insert("widgets", widgetList);
|
||||||
profileDefault.insert("widgets", widgets);
|
profileDefault.insert("timelineWallpaper", timelineWallpaperList);
|
||||||
// profileDefault.insert("wallpaper", wallpaper);
|
|
||||||
profileDefault.insert("name", "default");
|
profileDefault.insert("name", "default");
|
||||||
|
|
||||||
QJsonArray activeProfileList;
|
QJsonArray activeProfileList;
|
||||||
activeProfileList.append(profileDefault);
|
activeProfileList.append(profileDefault);
|
||||||
|
|
||||||
QJsonObject profile;
|
QJsonObject profile;
|
||||||
profile.insert("version", "1.0.0");
|
profile.insert("version", m_settings->getProfilesVersion().toString());
|
||||||
profile.insert("profiles", activeProfileList);
|
profile.insert("profiles", activeProfileList);
|
||||||
|
|
||||||
if (Util().writeJsonObjectToFile({ m_globalVariables->localSettingsPath().toString() + "/profiles.json" }, profile)) {
|
Util util;
|
||||||
|
if (util.writeJsonObjectToFile({ m_globalVariables->localSettingsPath().toString() + "/profiles.json" }, profile)) {
|
||||||
emit profilesSaved();
|
emit profilesSaved();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,7 @@ public:
|
|||||||
QString toString(const QStringList& list) const;
|
QString toString(const QStringList& list) const;
|
||||||
std::optional<QVector<int>> parseStringToIntegerList(const QString& string) const;
|
std::optional<QVector<int>> parseStringToIntegerList(const QString& string) const;
|
||||||
float roundDecimalPlaces(const float number) const;
|
float roundDecimalPlaces(const float number) const;
|
||||||
Q_INVOKABLE QString generateRandomString(quint32 length = 32);
|
Q_INVOKABLE QString generateRandomString(quint32 length = 32);
|
||||||
QString executableAppEnding();
|
QString executableAppEnding();
|
||||||
QString executableBinEnding();
|
QString executableBinEnding();
|
||||||
QStringList getAvailableWallpaper() const;
|
QStringList getAvailableWallpaper() const;
|
||||||
|
Loading…
Reference in New Issue
Block a user