mirror of
https://github.com/YACReader/yacreader
synced 2025-06-04 01:28:55 -04:00
Update FolderModel to support new functionality
This commit is contained in:
parent
0a00fd3020
commit
2e16dec51a
@ -54,26 +54,26 @@ void drawMacOSXFinishedFolderIcon()
|
|||||||
#define ROOT 1
|
#define ROOT 1
|
||||||
|
|
||||||
FolderModel::FolderModel(QObject *parent)
|
FolderModel::FolderModel(QObject *parent)
|
||||||
: QAbstractItemModel(parent), rootItem(0)
|
: QAbstractItemModel(parent), isSubfolder(false), rootItem(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
FolderModel::FolderModel(QSqlQuery &sqlquery, QObject *parent)
|
FolderModel::FolderModel(QSqlQuery &sqlquery, QObject *parent)
|
||||||
: QAbstractItemModel(parent), rootItem(0)
|
: QAbstractItemModel(parent), isSubfolder(false), rootItem(nullptr)
|
||||||
{
|
{
|
||||||
// lo m<>s probable es que el nodo ra<72>z no necesite tener informaci<63>n
|
// lo m<>s probable es que el nodo ra<72>z no necesite tener informaci<63>n
|
||||||
QList<QVariant> rootData;
|
QList<QVariant> rootData;
|
||||||
rootData << "root"; // id 0, padre 0, title "root" (el id, y el id del padre van a ir en la clase TreeItem)
|
rootData << "root"; // id 0, padre 0, title "root" (el id, y el id del padre van a ir en la clase TreeItem)
|
||||||
rootItem = new FolderItem(rootData);
|
rootItem = new FolderItem(rootData);
|
||||||
rootItem->id = ROOT;
|
rootItem->id = ROOT;
|
||||||
rootItem->parentItem = 0;
|
rootItem->parentItem = nullptr;
|
||||||
setupModelData(sqlquery, rootItem);
|
setupModelData(sqlquery, rootItem);
|
||||||
// sqlquery.finish();
|
// sqlquery.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
FolderModel::~FolderModel()
|
FolderModel::~FolderModel()
|
||||||
{
|
{
|
||||||
if (rootItem != 0)
|
if (rootItem != nullptr)
|
||||||
delete rootItem;
|
delete rootItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,8 +81,31 @@ int FolderModel::columnCount(const QModelIndex &parent) const
|
|||||||
{
|
{
|
||||||
if (parent.isValid())
|
if (parent.isValid())
|
||||||
return static_cast<FolderItem *>(parent.internalPointer())->columnCount();
|
return static_cast<FolderItem *>(parent.internalPointer())->columnCount();
|
||||||
else
|
else {
|
||||||
|
if (rootItem == nullptr) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return rootItem->columnCount();
|
return rootItem->columnCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<int, QByteArray> FolderModel::roleNames() const
|
||||||
|
{
|
||||||
|
QHash<int, QByteArray> roles;
|
||||||
|
|
||||||
|
roles[FinishedRole] = "is_finished";
|
||||||
|
roles[CompletedRole] = "is_completed";
|
||||||
|
roles[IdRole] = "id";
|
||||||
|
roles[MangaRole] = "is_manga";
|
||||||
|
roles[CoverPathRole] = "cover_path";
|
||||||
|
roles[FolderName] = "name";
|
||||||
|
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FolderModel::reload()
|
||||||
|
{
|
||||||
|
setupModelData(_databasePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant FolderModel::data(const QModelIndex &index, int role) const
|
QVariant FolderModel::data(const QModelIndex &index, int role) const
|
||||||
@ -121,6 +144,10 @@ QVariant FolderModel::data(const QModelIndex &index, int role) const
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (role == FolderModel::FolderName) {
|
||||||
|
return item->data(FolderModel::Name);
|
||||||
|
}
|
||||||
|
|
||||||
if (role == FolderModel::CompletedRole)
|
if (role == FolderModel::CompletedRole)
|
||||||
return item->data(FolderModel::Completed);
|
return item->data(FolderModel::Completed);
|
||||||
|
|
||||||
@ -133,6 +160,9 @@ QVariant FolderModel::data(const QModelIndex &index, int role) const
|
|||||||
if (role == FolderModel::IdRole)
|
if (role == FolderModel::IdRole)
|
||||||
return item->id;
|
return item->id;
|
||||||
|
|
||||||
|
if (role == FolderModel::CoverPathRole)
|
||||||
|
return getCoverUrlPathForComicHash(item->data(FirstChildHash).toString());
|
||||||
|
|
||||||
if (role != Qt::DisplayRole)
|
if (role != Qt::DisplayRole)
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
@ -150,6 +180,10 @@ Qt::ItemFlags FolderModel::flags(const QModelIndex &index) const
|
|||||||
QVariant FolderModel::headerData(int section, Qt::Orientation orientation,
|
QVariant FolderModel::headerData(int section, Qt::Orientation orientation,
|
||||||
int role) const
|
int role) const
|
||||||
{
|
{
|
||||||
|
if (rootItem == nullptr) {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
||||||
return rootItem->data(section);
|
return rootItem->data(section);
|
||||||
|
|
||||||
@ -196,10 +230,14 @@ int FolderModel::rowCount(const QModelIndex &parent) const
|
|||||||
if (parent.column() > 0)
|
if (parent.column() > 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!parent.isValid())
|
if (!parent.isValid()) {
|
||||||
|
if (rootItem == nullptr) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
parentItem = rootItem;
|
parentItem = rootItem;
|
||||||
else
|
} else {
|
||||||
parentItem = static_cast<FolderItem *>(parent.internalPointer());
|
parentItem = static_cast<FolderItem *>(parent.internalPointer());
|
||||||
|
}
|
||||||
|
|
||||||
return parentItem->childCount();
|
return parentItem->childCount();
|
||||||
}
|
}
|
||||||
@ -207,17 +245,17 @@ int FolderModel::rowCount(const QModelIndex &parent) const
|
|||||||
void FolderModel::setupModelData(QString path)
|
void FolderModel::setupModelData(QString path)
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
if (rootItem != 0)
|
if (rootItem != nullptr)
|
||||||
delete rootItem; // TODO comprobar que se libera bien la memoria
|
delete rootItem; // TODO comprobar que se libera bien la memoria
|
||||||
|
|
||||||
rootItem = 0;
|
rootItem = nullptr;
|
||||||
|
|
||||||
// inicializar el nodo ra<72>z
|
// inicializar el nodo ra<72>z
|
||||||
QList<QVariant> rootData;
|
QList<QVariant> rootData;
|
||||||
rootData << "root"; // id 0, padre 0, title "root" (el id, y el id del padre van a ir en la clase TreeItem)
|
rootData << "root"; // id 0, padre 0, title "root" (el id, y el id del padre van a ir en la clase TreeItem)
|
||||||
rootItem = new FolderItem(rootData);
|
rootItem = new FolderItem(rootData);
|
||||||
rootItem->id = ROOT;
|
rootItem->id = ROOT;
|
||||||
rootItem->parentItem = 0;
|
rootItem->parentItem = nullptr;
|
||||||
|
|
||||||
// cargar la base de datos
|
// cargar la base de datos
|
||||||
_databasePath = path;
|
_databasePath = path;
|
||||||
@ -235,6 +273,13 @@ void FolderModel::setupModelData(QString path)
|
|||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FolderModel::fullSetup(QSqlQuery &sqlquery, FolderItem *parent)
|
||||||
|
{
|
||||||
|
rootItem = parent;
|
||||||
|
|
||||||
|
setupModelData(sqlquery, parent);
|
||||||
|
}
|
||||||
|
|
||||||
void FolderModel::setupModelData(QSqlQuery &sqlquery, FolderItem *parent)
|
void FolderModel::setupModelData(QSqlQuery &sqlquery, FolderItem *parent)
|
||||||
{
|
{
|
||||||
// 64 bits para la primary key, es decir la misma precisi<73>n que soporta sqlit 2^64
|
// 64 bits para la primary key, es decir la misma precisi<73>n que soporta sqlit 2^64
|
||||||
@ -252,6 +297,7 @@ void FolderModel::setupModelData(QSqlQuery &sqlquery, FolderItem *parent)
|
|||||||
int manga = record.indexOf("manga");
|
int manga = record.indexOf("manga");
|
||||||
int id = record.indexOf("id");
|
int id = record.indexOf("id");
|
||||||
int parentId = record.indexOf("parentId");
|
int parentId = record.indexOf("parentId");
|
||||||
|
int firstChildHash = record.indexOf("firstChildHash");
|
||||||
|
|
||||||
while (sqlquery.next()) {
|
while (sqlquery.next()) {
|
||||||
QList<QVariant> data;
|
QList<QVariant> data;
|
||||||
@ -261,6 +307,7 @@ void FolderModel::setupModelData(QSqlQuery &sqlquery, FolderItem *parent)
|
|||||||
data << sqlquery.value(finished).toBool();
|
data << sqlquery.value(finished).toBool();
|
||||||
data << sqlquery.value(completed).toBool();
|
data << sqlquery.value(completed).toBool();
|
||||||
data << sqlquery.value(manga).toBool();
|
data << sqlquery.value(manga).toBool();
|
||||||
|
data << sqlquery.value(firstChildHash).toString();
|
||||||
auto item = new FolderItem(data);
|
auto item = new FolderItem(data);
|
||||||
|
|
||||||
item->id = sqlquery.value(id).toULongLong();
|
item->id = sqlquery.value(id).toULongLong();
|
||||||
@ -286,6 +333,7 @@ void FolderModel::updateFolderModelData(QSqlQuery &sqlquery, FolderItem *parent)
|
|||||||
int manga = record.indexOf("manga");
|
int manga = record.indexOf("manga");
|
||||||
int id = record.indexOf("id");
|
int id = record.indexOf("id");
|
||||||
int parentId = record.indexOf("parentId");
|
int parentId = record.indexOf("parentId");
|
||||||
|
int firstChildHash = record.indexOf("firstChildHash");
|
||||||
|
|
||||||
while (sqlquery.next()) {
|
while (sqlquery.next()) {
|
||||||
QList<QVariant> data;
|
QList<QVariant> data;
|
||||||
@ -295,6 +343,7 @@ void FolderModel::updateFolderModelData(QSqlQuery &sqlquery, FolderItem *parent)
|
|||||||
data << sqlquery.value(finished).toBool();
|
data << sqlquery.value(finished).toBool();
|
||||||
data << sqlquery.value(completed).toBool();
|
data << sqlquery.value(completed).toBool();
|
||||||
data << sqlquery.value(manga).toBool();
|
data << sqlquery.value(manga).toBool();
|
||||||
|
data << sqlquery.value(firstChildHash).toString();
|
||||||
auto item = new FolderItem(data);
|
auto item = new FolderItem(data);
|
||||||
|
|
||||||
item->id = sqlquery.value(id).toULongLong();
|
item->id = sqlquery.value(id).toULongLong();
|
||||||
@ -338,7 +387,7 @@ void FolderModel::updateFolderCompletedStatus(const QModelIndexList &list, bool
|
|||||||
}
|
}
|
||||||
QSqlDatabase::removeDatabase(connectionName);
|
QSqlDatabase::removeDatabase(connectionName);
|
||||||
|
|
||||||
emit dataChanged(index(list.first().row(), FolderModel::Name), index(list.last().row(), FolderModel::Completed));
|
emit dataChanged(index(list.first().row(), FolderModel::Name), index(list.last().row(), FolderModel::FirstChildHash));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderModel::updateFolderFinishedStatus(const QModelIndexList &list, bool status)
|
void FolderModel::updateFolderFinishedStatus(const QModelIndexList &list, bool status)
|
||||||
@ -360,7 +409,7 @@ void FolderModel::updateFolderFinishedStatus(const QModelIndexList &list, bool s
|
|||||||
}
|
}
|
||||||
QSqlDatabase::removeDatabase(connectionName);
|
QSqlDatabase::removeDatabase(connectionName);
|
||||||
|
|
||||||
emit dataChanged(index(list.first().row(), FolderModel::Name), index(list.last().row(), FolderModel::Completed));
|
emit dataChanged(index(list.first().row(), FolderModel::Name), index(list.last().row(), FolderModel::FirstChildHash));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderModel::updateFolderManga(const QModelIndexList &list, bool manga)
|
void FolderModel::updateFolderManga(const QModelIndexList &list, bool manga)
|
||||||
@ -390,7 +439,7 @@ void FolderModel::updateFolderManga(const QModelIndexList &list, bool manga)
|
|||||||
}
|
}
|
||||||
QSqlDatabase::removeDatabase(connectionName);
|
QSqlDatabase::removeDatabase(connectionName);
|
||||||
|
|
||||||
emit dataChanged(index(list.first().row(), FolderModel::Name), index(list.last().row(), FolderModel::Manga));
|
emit dataChanged(index(list.first().row(), FolderModel::Name), index(list.last().row(), FolderModel::FirstChildHash));
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList FolderModel::getSubfoldersNames(const QModelIndex &mi)
|
QStringList FolderModel::getSubfoldersNames(const QModelIndex &mi)
|
||||||
@ -417,6 +466,97 @@ QStringList FolderModel::getSubfoldersNames(const QModelIndex &mi)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FolderModel *FolderModel::getSubfoldersModel(const QModelIndex &mi)
|
||||||
|
{
|
||||||
|
qulonglong id = 1;
|
||||||
|
FolderItem *parent = nullptr;
|
||||||
|
if (mi.isValid()) {
|
||||||
|
auto item = static_cast<FolderItem *>(mi.internalPointer());
|
||||||
|
parent = new FolderItem(item->getData(), item->parent());
|
||||||
|
id = parent->id = item->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == 1) {
|
||||||
|
if (parent != nullptr) {
|
||||||
|
delete parent;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto model = new FolderModel();
|
||||||
|
|
||||||
|
QString connectionName = "";
|
||||||
|
{
|
||||||
|
QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath);
|
||||||
|
|
||||||
|
QSqlQuery selectQuery(db); // TODO check
|
||||||
|
selectQuery.prepare("SELECT * FROM folder WHERE parentId = :parentId and id <> 1");
|
||||||
|
selectQuery.bindValue(":parentId", id);
|
||||||
|
selectQuery.exec();
|
||||||
|
|
||||||
|
if (parent != nullptr) {
|
||||||
|
model->fullSetup(selectQuery, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
connectionName = db.connectionName();
|
||||||
|
}
|
||||||
|
QSqlDatabase::removeDatabase(connectionName);
|
||||||
|
|
||||||
|
model->_databasePath = _databasePath;
|
||||||
|
|
||||||
|
model->isSubfolder = true;
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
Folder FolderModel::getFolder(const QModelIndex &mi)
|
||||||
|
{
|
||||||
|
auto folderItem = static_cast<FolderItem *>(mi.internalPointer());
|
||||||
|
auto name = folderItem->data(FolderModel::Name).toString();
|
||||||
|
auto parentItem = folderItem->parent();
|
||||||
|
auto folder = Folder(folderItem->id,
|
||||||
|
parentItem->id,
|
||||||
|
name,
|
||||||
|
folderItem->parent()->data(Columns::Path).toString() + "/" + name,
|
||||||
|
folderItem->data(Columns::Completed).toBool(),
|
||||||
|
folderItem->data(Columns::Finished).toBool(),
|
||||||
|
folderItem->data(Columns::Manga).toBool());
|
||||||
|
|
||||||
|
return folder;
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex FolderModel::getIndexFromFolder(const Folder &folder, const QModelIndex &parent)
|
||||||
|
{
|
||||||
|
if (rootItem == nullptr) {
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto numRows = rowCount(parent);
|
||||||
|
for (auto i = 0; i < numRows; i++) {
|
||||||
|
auto modelIndex = index(i, 0, parent);
|
||||||
|
|
||||||
|
if (modelIndex.isValid()) {
|
||||||
|
auto folderItem = static_cast<FolderItem *>(modelIndex.internalPointer());
|
||||||
|
|
||||||
|
if (folderItem->id == folder.id) {
|
||||||
|
return modelIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto childModelIndex = getIndexFromFolder(folder, modelIndex);
|
||||||
|
|
||||||
|
if (childModelIndex.isValid()) {
|
||||||
|
auto folderItem = static_cast<FolderItem *>(childModelIndex.internalPointer());
|
||||||
|
|
||||||
|
if (folderItem->id == folder.id) {
|
||||||
|
return childModelIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
void FolderModel::fetchMoreFromDB(const QModelIndex &parent)
|
void FolderModel::fetchMoreFromDB(const QModelIndex &parent)
|
||||||
{
|
{
|
||||||
FolderItem *item;
|
FolderItem *item;
|
||||||
@ -531,6 +671,11 @@ QModelIndex FolderModel::addFolderAtParent(const QString &folderName, const QMod
|
|||||||
return index(destRow, 0, parent);
|
return index(destRow, 0, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QUrl FolderModel::getCoverUrlPathForComicHash(const QString &hash) const
|
||||||
|
{
|
||||||
|
return QUrl("file:" + _databasePath + "/covers/" + hash + ".jpg");
|
||||||
|
}
|
||||||
|
|
||||||
void FolderModel::deleteFolder(const QModelIndex &mi)
|
void FolderModel::deleteFolder(const QModelIndex &mi)
|
||||||
{
|
{
|
||||||
beginRemoveRows(mi.parent(), mi.row(), mi.row());
|
beginRemoveRows(mi.parent(), mi.row(), mi.row());
|
||||||
|
@ -7,9 +7,11 @@
|
|||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <QSqlQuery>
|
#include <QSqlQuery>
|
||||||
#include <QSqlDatabase>
|
#include <QSqlDatabase>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
#include "yacreader_global.h"
|
#include "folder.h"
|
||||||
#include "folder_query_result_processor.h"
|
#include "folder_query_result_processor.h"
|
||||||
|
#include "yacreader_global.h"
|
||||||
|
|
||||||
class FolderItem;
|
class FolderItem;
|
||||||
|
|
||||||
@ -54,8 +56,10 @@ public:
|
|||||||
QModelIndex parent(const QModelIndex &index) const override;
|
QModelIndex parent(const QModelIndex &index) const override;
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
// Convenience methods
|
// Convenience methods
|
||||||
|
void reload();
|
||||||
void setupModelData(QString path);
|
void setupModelData(QString path);
|
||||||
QString getDatabase();
|
QString getDatabase();
|
||||||
QString getFolderPath(const QModelIndex &folder);
|
QString getFolderPath(const QModelIndex &folder);
|
||||||
@ -68,31 +72,44 @@ public:
|
|||||||
void updateFolderManga(const QModelIndexList &list, bool manga);
|
void updateFolderManga(const QModelIndexList &list, bool manga);
|
||||||
|
|
||||||
QStringList getSubfoldersNames(const QModelIndex &mi);
|
QStringList getSubfoldersNames(const QModelIndex &mi);
|
||||||
|
FolderModel *getSubfoldersModel(const QModelIndex &mi);
|
||||||
|
|
||||||
|
Folder getFolder(const QModelIndex &mi);
|
||||||
|
QModelIndex getIndexFromFolder(const Folder &folder, const QModelIndex &parent = QModelIndex());
|
||||||
|
|
||||||
void fetchMoreFromDB(const QModelIndex &parent);
|
void fetchMoreFromDB(const QModelIndex &parent);
|
||||||
|
|
||||||
QModelIndex addFolderAtParent(const QString &folderName, const QModelIndex &parent);
|
QModelIndex addFolderAtParent(const QString &folderName, const QModelIndex &parent);
|
||||||
|
|
||||||
|
Q_INVOKABLE QUrl getCoverUrlPathForComicHash(const QString &hash) const;
|
||||||
|
|
||||||
enum Columns {
|
enum Columns {
|
||||||
Name = 0,
|
Name = 0,
|
||||||
Path = 1,
|
Path = 1,
|
||||||
Finished = 2,
|
Finished = 2,
|
||||||
Completed = 3,
|
Completed = 3,
|
||||||
Manga = 4
|
Manga = 4,
|
||||||
|
FirstChildHash = 5
|
||||||
}; // id INTEGER PRIMARY KEY, parentId INTEGER NOT NULL, name TEXT NOT NULL, path TEXT NOT NULL
|
}; // id INTEGER PRIMARY KEY, parentId INTEGER NOT NULL, name TEXT NOT NULL, path TEXT NOT NULL
|
||||||
|
|
||||||
enum Roles {
|
enum Roles {
|
||||||
FinishedRole = Qt::UserRole + 1,
|
FinishedRole = Qt::UserRole + 1,
|
||||||
CompletedRole,
|
CompletedRole,
|
||||||
IdRole,
|
IdRole,
|
||||||
MangaRole
|
MangaRole,
|
||||||
|
CoverPathRole,
|
||||||
|
FolderName,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool isSubfolder;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void deleteFolder(const QModelIndex &mi);
|
void deleteFolder(const QModelIndex &mi);
|
||||||
void updateFolderChildrenInfo(qulonglong folderId);
|
void updateFolderChildrenInfo(qulonglong folderId);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void fullSetup(QSqlQuery &sqlquery, FolderItem *parent);
|
||||||
|
|
||||||
void setupModelData(QSqlQuery &sqlquery, FolderItem *parent);
|
void setupModelData(QSqlQuery &sqlquery, FolderItem *parent);
|
||||||
void updateFolderModelData(QSqlQuery &sqlquery, FolderItem *parent);
|
void updateFolderModelData(QSqlQuery &sqlquery, FolderItem *parent);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user