Redesign. Move initialization in ui file. Use QListWidget instead of a custom solution. Basic functions do not work yet.
This commit is contained in:
parent
5fc927b32a
commit
f1057de239
|
@ -51,4 +51,5 @@ HEADERS += \
|
||||||
|
|
||||||
FORMS += \
|
FORMS += \
|
||||||
$$PWD/puzzlemainwindow.ui \
|
$$PWD/puzzlemainwindow.ui \
|
||||||
$$PWD/dialogs/dialogaboutpuzzle.ui
|
$$PWD/dialogs/dialogaboutpuzzle.ui \
|
||||||
|
$$PWD/vpiececarrousel.ui
|
||||||
|
|
|
@ -26,98 +26,57 @@
|
||||||
**
|
**
|
||||||
*************************************************************************/
|
*************************************************************************/
|
||||||
#include "vpiececarrousel.h"
|
#include "vpiececarrousel.h"
|
||||||
|
#include "ui_vpiececarrousel.h"
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
|
|
||||||
#include "../vmisc/backport/qoverload.h"
|
#include "../vmisc/backport/qoverload.h"
|
||||||
|
#include "vpuzzlelayer.h"
|
||||||
|
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
Q_LOGGING_CATEGORY(pCarrousel, "p.carrousel")
|
Q_LOGGING_CATEGORY(pCarrousel, "p.carrousel")
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
VPieceCarrousel::VPieceCarrousel(VPuzzleLayout *layout, QWidget *parent) :
|
VPieceCarrousel::VPieceCarrousel(VPuzzleLayout *layout, QWidget *parent) :
|
||||||
QWidget(parent),
|
QWidget(parent),
|
||||||
m_layout(layout),
|
ui(new Ui::VPieceCarrousel),
|
||||||
m_comboBoxLayer(new QComboBox(this)),
|
m_layout(layout)
|
||||||
m_scrollArea(new QScrollArea(this)),
|
|
||||||
m_layersContainer(new QWidget(this)),
|
|
||||||
m_carrouselLayers(QList<VPieceCarrouselLayer *>())
|
|
||||||
{
|
{
|
||||||
Init();
|
ui->setupUi(this);
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
|
||||||
VPieceCarrousel::~VPieceCarrousel()
|
|
||||||
{
|
|
||||||
delete m_comboBoxLayer;
|
|
||||||
delete m_layersContainer;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
|
||||||
void VPieceCarrousel::Init()
|
|
||||||
{
|
|
||||||
// ------ first we initialize the structure of the carrousel
|
|
||||||
|
|
||||||
// init the combo box
|
// init the combo box
|
||||||
connect(m_comboBoxLayer, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
connect(ui->comboBoxLayer, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||||
&VPieceCarrousel::on_ActiveLayerChanged);
|
&VPieceCarrousel::on_ActiveLayerChanged);
|
||||||
|
|
||||||
// init the layers container and corresponding scroll area
|
ui->listWidget->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
QWidget *layersContainerWrapper = new QWidget();
|
|
||||||
|
|
||||||
QVBoxLayout *layersContainerWrapperLayout = new QVBoxLayout();
|
|
||||||
layersContainerWrapperLayout->setMargin(0);
|
|
||||||
layersContainerWrapper->setLayout(layersContainerWrapperLayout);
|
|
||||||
|
|
||||||
QVBoxLayout *layersContainerLayout = new QVBoxLayout();
|
|
||||||
layersContainerLayout->setMargin(0);
|
|
||||||
m_layersContainer->setLayout(layersContainerLayout);
|
|
||||||
m_layersContainer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
|
||||||
QSpacerItem *spacer = new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
||||||
|
|
||||||
|
|
||||||
layersContainerWrapperLayout->addWidget(m_layersContainer);
|
|
||||||
layersContainerWrapperLayout->addSpacerItem(spacer);
|
|
||||||
|
|
||||||
m_scrollArea->setWidgetResizable( true );
|
|
||||||
m_scrollArea->setWidget(layersContainerWrapper);
|
|
||||||
|
|
||||||
// init the layout of the piece carrousel
|
|
||||||
QVBoxLayout *mainLayout = new QVBoxLayout();
|
|
||||||
setLayout(mainLayout);
|
|
||||||
|
|
||||||
mainLayout->addWidget(m_comboBoxLayer);
|
|
||||||
mainLayout->addWidget(m_scrollArea);
|
|
||||||
|
|
||||||
// ------ then we fill the carrousel with the layout content
|
// ------ then we fill the carrousel with the layout content
|
||||||
Refresh();
|
Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
void VPieceCarrousel::Refresh()
|
void VPieceCarrousel::Refresh()
|
||||||
{
|
{
|
||||||
|
|
||||||
// NOTE: alternative to clearing the carrousel and adding things again, we could make comparision
|
// NOTE: alternative to clearing the carrousel and adding things again, we could make comparision
|
||||||
|
|
||||||
// --- clears the content of the carrousel
|
// --- clears the content of the carrousel
|
||||||
Clear();
|
Clear();
|
||||||
|
|
||||||
// --- add the content saved in the layout to the carrousel.
|
// --- add the content saved in the layout to the carrousel.
|
||||||
QList<VPuzzleLayer*> layers = m_layout->GetLayers();
|
// Do not rely on m_layout because we do not control it.
|
||||||
layers.prepend(m_layout->GetUnplacedPiecesLayer());
|
m_layers = m_layout->GetLayers();
|
||||||
|
m_layers.prepend(m_layout->GetUnplacedPiecesLayer());
|
||||||
|
|
||||||
for (auto layer : layers)
|
for (auto layer : m_layers)
|
||||||
{
|
{
|
||||||
// add layer name to combo
|
// add layer name to combo
|
||||||
m_comboBoxLayer->addItem(layer->GetName());
|
ui->comboBoxLayer->blockSignals(true);
|
||||||
|
ui->comboBoxLayer->addItem(layer->GetName());
|
||||||
// add new carrousel layer
|
ui->comboBoxLayer->blockSignals(false);
|
||||||
VPieceCarrouselLayer *carrouselLayer = new VPieceCarrouselLayer(layer, this);
|
|
||||||
m_carrouselLayers.append(carrouselLayer);
|
|
||||||
m_layersContainer->layout()->addWidget(carrouselLayer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
on_ActiveLayerChanged(0);
|
on_ActiveLayerChanged(0);
|
||||||
|
@ -129,31 +88,9 @@ void VPieceCarrousel::Refresh()
|
||||||
void VPieceCarrousel::Clear()
|
void VPieceCarrousel::Clear()
|
||||||
{
|
{
|
||||||
// remove the combobox entries
|
// remove the combobox entries
|
||||||
int layerCount = m_comboBoxLayer->count();
|
ui->comboBoxLayer->clear();
|
||||||
for(int i=0;i<layerCount;i++)
|
|
||||||
{
|
|
||||||
m_comboBoxLayer->removeItem(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove the carrousel layers from the qlayout
|
ui->listWidget->clear();
|
||||||
while(!m_layersContainer->layout()->isEmpty())
|
|
||||||
{
|
|
||||||
QLayoutItem* item = m_layersContainer->layout()->takeAt(0);
|
|
||||||
if(item != nullptr)
|
|
||||||
{
|
|
||||||
delete item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Removes and deletes the carrousel layers from the list
|
|
||||||
while (!m_carrouselLayers.isEmpty())
|
|
||||||
{
|
|
||||||
VPieceCarrouselLayer *carrouselLayer = m_carrouselLayers.takeLast();
|
|
||||||
if(carrouselLayer != nullptr)
|
|
||||||
{
|
|
||||||
delete carrouselLayer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
@ -161,10 +98,21 @@ void VPieceCarrousel::on_ActiveLayerChanged(int index)
|
||||||
{
|
{
|
||||||
qCDebug(pCarrousel, "index changed %i", index);
|
qCDebug(pCarrousel, "index changed %i", index);
|
||||||
|
|
||||||
int j=0;
|
ui->listWidget->clear();
|
||||||
for (VPieceCarrouselLayer *carrouselLayer: m_carrouselLayers) {
|
|
||||||
carrouselLayer->setVisible(j == index);
|
if (index >= 0 && index < m_layers.size())
|
||||||
j++;
|
{
|
||||||
|
VPuzzleLayer *layer = m_layers.at(index);
|
||||||
|
|
||||||
|
if (layer)
|
||||||
|
{
|
||||||
|
QList<VPuzzlePiece*> pieces = layer->GetPieces();
|
||||||
|
|
||||||
|
for (auto piece : pieces)
|
||||||
|
{
|
||||||
|
new QListWidgetItem(piece->PieceIcon(QSize(120, 120)) , piece->GetName(), ui->listWidget);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,47 +126,26 @@ void VPieceCarrousel::SetOrientation(Qt::Orientation orientation)
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
void VPieceCarrousel::RefreshOrientation()
|
void VPieceCarrousel::RefreshOrientation()
|
||||||
{
|
{
|
||||||
QBoxLayout::Direction direction = (m_orientation == Qt::Horizontal)?
|
|
||||||
QBoxLayout::LeftToRight
|
|
||||||
:
|
|
||||||
QBoxLayout::TopToBottom;
|
|
||||||
|
|
||||||
// Update the various qlayouts
|
|
||||||
QBoxLayout* mainScrollAreaLayout = qobject_cast<QBoxLayout*>(m_layersContainer->layout());
|
|
||||||
mainScrollAreaLayout->setDirection(direction);
|
|
||||||
|
|
||||||
QBoxLayout* layerContainerWrapper = qobject_cast<QBoxLayout*>(m_scrollArea->widget()->layout());
|
|
||||||
layerContainerWrapper->setDirection(direction);
|
|
||||||
|
|
||||||
for (VPieceCarrouselLayer *widget: m_carrouselLayers) {
|
|
||||||
QBoxLayout* layerLayout = qobject_cast<QBoxLayout*>(widget->layout());
|
|
||||||
layerLayout->setDirection(direction);
|
|
||||||
}
|
|
||||||
|
|
||||||
// then update the scrollarea min height / width and scrollbar behaviour
|
// then update the scrollarea min height / width and scrollbar behaviour
|
||||||
if(m_orientation == Qt::Horizontal)
|
if(m_orientation == Qt::Horizontal)
|
||||||
{
|
{
|
||||||
m_comboBoxLayer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
ui->comboBoxLayer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
|
|
||||||
// scroll bar policy of scroll area
|
// scroll bar policy of scroll area
|
||||||
m_scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
ui->listWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||||
m_scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
ui->listWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||||
|
|
||||||
// FIXME: find a nicer way than putting directly the 120 height of the piece
|
ui->listWidget->setFlow(QListView::TopToBottom);
|
||||||
m_scrollArea->setMinimumHeight(128 + m_scrollArea->horizontalScrollBar()->sizeHint().height()+2);
|
|
||||||
m_scrollArea->setMinimumWidth(0);
|
|
||||||
}
|
}
|
||||||
else // Qt::Vertical
|
else // Qt::Vertical
|
||||||
{
|
{
|
||||||
m_comboBoxLayer->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
ui->comboBoxLayer->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||||
|
|
||||||
// scroll bar policy of scroll area
|
// scroll bar policy of scroll area
|
||||||
m_scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
ui->listWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||||
m_scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
ui->listWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||||
|
|
||||||
m_scrollArea->setMinimumHeight(0);
|
ui->listWidget->setFlow(QListView::LeftToRight);
|
||||||
m_scrollArea->setMinimumWidth(124 + m_scrollArea->verticalScrollBar()->sizeHint().width()+2);
|
|
||||||
// FIXME: find a nicer way than putting directly the 120 width of the piece
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,14 +34,18 @@
|
||||||
#include <QScrollArea>
|
#include <QScrollArea>
|
||||||
#include "vpuzzlelayout.h"
|
#include "vpuzzlelayout.h"
|
||||||
#include "vpuzzlepiece.h"
|
#include "vpuzzlepiece.h"
|
||||||
#include "vpiececarrousellayer.h"
|
|
||||||
|
namespace Ui
|
||||||
|
{
|
||||||
|
class VPieceCarrousel;
|
||||||
|
}
|
||||||
|
|
||||||
class VPieceCarrousel : public QWidget
|
class VPieceCarrousel : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit VPieceCarrousel(VPuzzleLayout *layout, QWidget *parent = nullptr);
|
explicit VPieceCarrousel(VPuzzleLayout *layout, QWidget *parent = nullptr);
|
||||||
virtual ~VPieceCarrousel();
|
virtual ~VPieceCarrousel() = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief SetOrientation Sets the orientation to the given value and refreshes
|
* @brief SetOrientation Sets the orientation to the given value and refreshes
|
||||||
|
@ -56,11 +60,6 @@ public:
|
||||||
*/
|
*/
|
||||||
void RefreshOrientation();
|
void RefreshOrientation();
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Inits the carroussel
|
|
||||||
*/
|
|
||||||
void Init();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Refresh Refreshes the content of the carrousel
|
* @brief Refresh Refreshes the content of the carrousel
|
||||||
*/
|
*/
|
||||||
|
@ -78,14 +77,10 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Q_DISABLE_COPY(VPieceCarrousel)
|
Q_DISABLE_COPY(VPieceCarrousel)
|
||||||
|
Ui::VPieceCarrousel *ui;
|
||||||
|
|
||||||
VPuzzleLayout *m_layout;
|
VPuzzleLayout *m_layout;
|
||||||
|
QList<VPuzzleLayer*> m_layers{};
|
||||||
QComboBox *m_comboBoxLayer;
|
|
||||||
QScrollArea *m_scrollArea;
|
|
||||||
QWidget *m_layersContainer;
|
|
||||||
|
|
||||||
QList<VPieceCarrouselLayer*> m_carrouselLayers;
|
|
||||||
|
|
||||||
Qt::Orientation m_orientation{Qt::Vertical};
|
Qt::Orientation m_orientation{Qt::Vertical};
|
||||||
|
|
||||||
|
|
77
src/app/puzzle/vpiececarrousel.ui
Normal file
77
src/app/puzzle/vpiececarrousel.ui
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>VPieceCarrousel</class>
|
||||||
|
<widget class="QWidget" name="VPieceCarrousel">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>583</width>
|
||||||
|
<height>557</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string notr="true">Carrousel</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="comboBoxLayer">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="listWidget">
|
||||||
|
<property name="verticalScrollBarPolicy">
|
||||||
|
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||||
|
</property>
|
||||||
|
<property name="dragDropMode">
|
||||||
|
<enum>QAbstractItemView::DragOnly</enum>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>120</width>
|
||||||
|
<height>120</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="movement">
|
||||||
|
<enum>QListView::Static</enum>
|
||||||
|
</property>
|
||||||
|
<property name="flow">
|
||||||
|
<enum>QListView::TopToBottom</enum>
|
||||||
|
</property>
|
||||||
|
<property name="resizeMode">
|
||||||
|
<enum>QListView::Adjust</enum>
|
||||||
|
</property>
|
||||||
|
<property name="spacing">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<property name="viewMode">
|
||||||
|
<enum>QListView::IconMode</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sortingEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
|
@ -32,7 +32,9 @@
|
||||||
#include "vpuzzlelayer.h"
|
#include "vpuzzlelayer.h"
|
||||||
#include "../vmisc/def.h"
|
#include "../vmisc/def.h"
|
||||||
|
|
||||||
|
#include <QIcon>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
Q_LOGGING_CATEGORY(pPiece, "p.piece")
|
Q_LOGGING_CATEGORY(pPiece, "p.piece")
|
||||||
|
|
||||||
|
@ -253,3 +255,46 @@ void VPuzzlePiece::SetLayer(VPuzzleLayer* layer)
|
||||||
m_layer = layer;
|
m_layer = layer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
QIcon VPuzzlePiece::PieceIcon(const QSize &size) const
|
||||||
|
{
|
||||||
|
QVector<QPointF> points = GetSeamLine();
|
||||||
|
if(points.isEmpty())
|
||||||
|
{
|
||||||
|
points = GetCuttingLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
QPolygonF shape(points);
|
||||||
|
shape << shape.first();
|
||||||
|
|
||||||
|
QRectF boundingRect = shape.boundingRect();
|
||||||
|
qreal canvasSize = qMax(boundingRect.height(), boundingRect.width());
|
||||||
|
QRectF canvas = QRectF(0, 0, canvasSize, canvasSize);
|
||||||
|
|
||||||
|
qreal dx = canvas.center().x() - boundingRect.center().x();
|
||||||
|
qreal dy = canvas.center().y() - boundingRect.center().y();
|
||||||
|
|
||||||
|
QPixmap pixmap(size);
|
||||||
|
pixmap.fill(QColor("white"));
|
||||||
|
|
||||||
|
QPainter painter;
|
||||||
|
painter.begin(&pixmap);
|
||||||
|
painter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
painter.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||||
|
|
||||||
|
int spacing = 2;
|
||||||
|
painter.translate(spacing, spacing);
|
||||||
|
|
||||||
|
qreal scaleFactorX = canvasSize * 100 / (size.width() - spacing*2) / 100;
|
||||||
|
qreal scaleFactorY = canvasSize * 100 / (size.height() - spacing*2) / 100;
|
||||||
|
painter.scale(1./scaleFactorX, 1./scaleFactorY);
|
||||||
|
painter.setPen(QPen(Qt::black, 0.8*qMax(scaleFactorX, scaleFactorY)));
|
||||||
|
|
||||||
|
painter.translate(dx, dy);
|
||||||
|
|
||||||
|
painter.drawPolygon(shape);
|
||||||
|
painter.end();
|
||||||
|
|
||||||
|
return QIcon(pixmap);
|
||||||
|
}
|
||||||
|
|
|
@ -198,6 +198,8 @@ public:
|
||||||
*/
|
*/
|
||||||
void SetLayer(VPuzzleLayer* layer);
|
void SetLayer(VPuzzleLayer* layer);
|
||||||
|
|
||||||
|
QIcon PieceIcon(const QSize &size) const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/**
|
/**
|
||||||
* @brief SelectionChanged emited when the selection of the piece was
|
* @brief SelectionChanged emited when the selection of the piece was
|
||||||
|
|
Loading…
Reference in New Issue
Block a user