qml format changes and format
This commit is contained in:
+13
-13
@@ -123,7 +123,7 @@ OverlayController::OverlayController( bool desktopMode,
|
||||
m_reviveTabController.initStage1(
|
||||
m_settingsTabController.forceRevivePage() );
|
||||
m_utilitiesTabController.initStage1();
|
||||
m_videoTabController.initStage1();
|
||||
m_videoTabController.initStage1();
|
||||
|
||||
// init action handles
|
||||
|
||||
@@ -253,16 +253,16 @@ OverlayController::OverlayController( bool desktopMode,
|
||||
QQmlEngine::setObjectOwnership( obj, QQmlEngine::CppOwnership );
|
||||
return obj;
|
||||
} );
|
||||
qmlRegisterSingletonType<SteamVRTabController>(
|
||||
qmlSingletonImportName,
|
||||
1,
|
||||
0,
|
||||
"VideoTabController",
|
||||
[](QQmlEngine*, QJSEngine*) {
|
||||
QObject* obj = &(objectAddress->m_videoTabController);
|
||||
QQmlEngine::setObjectOwnership(obj, QQmlEngine::CppOwnership);
|
||||
return obj;
|
||||
});
|
||||
qmlRegisterSingletonType<SteamVRTabController>(
|
||||
qmlSingletonImportName,
|
||||
1,
|
||||
0,
|
||||
"VideoTabController",
|
||||
[]( QQmlEngine*, QJSEngine* ) {
|
||||
QObject* obj = &( objectAddress->m_videoTabController );
|
||||
QQmlEngine::setObjectOwnership( obj, QQmlEngine::CppOwnership );
|
||||
return obj;
|
||||
} );
|
||||
qmlRegisterSingletonType<overlay::DesktopOverlay>(
|
||||
qmlSingletonImportName,
|
||||
1,
|
||||
@@ -427,7 +427,7 @@ void OverlayController::SetWidget( QQuickItem* quickItem,
|
||||
m_settingsTabController.initStage2( this, m_pWindow.get() );
|
||||
m_reviveTabController.initStage2( this, m_pWindow.get() );
|
||||
m_utilitiesTabController.initStage2( this, m_pWindow.get() );
|
||||
m_videoTabController.initStage2(this, m_pWindow.get());
|
||||
m_videoTabController.initStage2( this, m_pWindow.get() );
|
||||
}
|
||||
|
||||
void OverlayController::OnRenderRequest()
|
||||
@@ -846,7 +846,7 @@ void OverlayController::mainEventLoop()
|
||||
m_settingsTabController.eventLoopTick();
|
||||
m_reviveTabController.eventLoopTick();
|
||||
m_audioTabController.eventLoopTick();
|
||||
//TODO do I need loop for vide?
|
||||
// TODO do I need loop for vide?
|
||||
|
||||
if ( m_ulOverlayThumbnailHandle != vr::k_ulOverlayHandleInvalid )
|
||||
{
|
||||
|
||||
@@ -123,7 +123,7 @@ public: // I know it's an ugly hack to make them public to enable external
|
||||
SettingsTabController m_settingsTabController;
|
||||
ReviveTabController m_reviveTabController;
|
||||
UtilitiesTabController m_utilitiesTabController;
|
||||
VideoTabController m_videoTabController;
|
||||
VideoTabController m_videoTabController;
|
||||
overlay::DesktopOverlay m_desktopOverlay;
|
||||
|
||||
private:
|
||||
|
||||
+12
-12
@@ -25,7 +25,7 @@ MyStackViewPage {
|
||||
Layout.preferredWidth: 250
|
||||
Layout.maximumWidth: 250
|
||||
Layout.fillHeight: true
|
||||
spacing: 18
|
||||
spacing: 10
|
||||
MyPushButton {
|
||||
id: steamVRButton
|
||||
activationSoundEnabled: false
|
||||
@@ -92,6 +92,17 @@ MyStackViewPage {
|
||||
}
|
||||
}
|
||||
|
||||
MyPushButton {
|
||||
id: videoButton
|
||||
activationSoundEnabled: false
|
||||
text: "Video"
|
||||
Layout.fillWidth: true
|
||||
onClicked: {
|
||||
MyResources.playFocusChangedSound()
|
||||
mainView.push(videoPage)
|
||||
}
|
||||
}
|
||||
|
||||
MyPushButton {
|
||||
id: reviveButton
|
||||
activationSoundEnabled: false
|
||||
@@ -137,17 +148,6 @@ MyStackViewPage {
|
||||
}
|
||||
}
|
||||
|
||||
MyPushButton {
|
||||
id: videoButton
|
||||
activationSoundEnabled: false
|
||||
text: "Video"
|
||||
Layout.fillWidth: true
|
||||
onClicked: {
|
||||
MyResources.playFocusChangedSound()
|
||||
mainView.push(videoPage)
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
@@ -77,6 +77,7 @@ Rectangle {
|
||||
stackView: mainView
|
||||
visible:false
|
||||
}
|
||||
|
||||
property DesktopOverlayPage desktopOverlayPage: DesktopOverlayPage {
|
||||
stackView: mainView
|
||||
visible: false
|
||||
|
||||
@@ -6,167 +6,171 @@
|
||||
|
||||
namespace advsettings
|
||||
{
|
||||
void VideoTabController::initStage1()
|
||||
{
|
||||
|
||||
}
|
||||
void VideoTabController::initStage1() {}
|
||||
|
||||
void VideoTabController::initStage2(OverlayController* var_parent,
|
||||
QQuickWindow* var_widget)
|
||||
{
|
||||
this->parent = var_parent;
|
||||
this->widget = var_widget;
|
||||
void VideoTabController::initStage2( OverlayController* var_parent,
|
||||
QQuickWindow* var_widget )
|
||||
{
|
||||
this->parent = var_parent;
|
||||
this->widget = var_widget;
|
||||
|
||||
std::string notifKey = std::string(application_strings::applicationKey)
|
||||
+ ".dimnotification";
|
||||
std::string notifKey = std::string( application_strings::applicationKey )
|
||||
+ ".dimnotification";
|
||||
|
||||
vr::VROverlayError overlayError = vr::VROverlay()->CreateOverlay(
|
||||
notifKey.c_str(), notifKey.c_str(), &m_brightnessNotificationOverlayHandle);
|
||||
if (overlayError == vr::VROverlayError_None)
|
||||
{
|
||||
const auto notifIconPath
|
||||
= paths::binaryDirectoryFindFile(video_keys::k_brightnessOverlayFilename);
|
||||
if (notifIconPath.has_value())
|
||||
{
|
||||
vr::VROverlay()->SetOverlayFromFile(m_brightnessNotificationOverlayHandle,
|
||||
notifIconPath->c_str());
|
||||
vr::VROverlay()->SetOverlayWidthInMeters(
|
||||
m_brightnessNotificationOverlayHandle, k_overlayWidth);
|
||||
vr::HmdMatrix34_t notificationTransform
|
||||
= { { { 1.0f, 0.0f, 0.0f, 0.00f },
|
||||
{ 0.0f, 1.0f, 0.0f, 0.00f },
|
||||
{ 0.0f, 0.0f, 1.0f, k_hmdDistance } } };
|
||||
vr::VROverlay()->SetOverlayTransformTrackedDeviceRelative(
|
||||
m_brightnessNotificationOverlayHandle,
|
||||
vr::k_unTrackedDeviceIndex_Hmd,
|
||||
¬ificationTransform);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(ERROR) << "Could not find notification icon \""
|
||||
<< video_keys::k_brightnessOverlayFilename << "\"";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(ERROR) << "Could not create dimmer notification overlay: "
|
||||
<< vr::VROverlay()->GetOverlayErrorNameFromEnum(
|
||||
overlayError);
|
||||
}
|
||||
vr::VROverlayError overlayError = vr::VROverlay()->CreateOverlay(
|
||||
notifKey.c_str(),
|
||||
notifKey.c_str(),
|
||||
&m_brightnessNotificationOverlayHandle );
|
||||
if ( overlayError == vr::VROverlayError_None )
|
||||
{
|
||||
const auto notifIconPath = paths::binaryDirectoryFindFile(
|
||||
video_keys::k_brightnessOverlayFilename );
|
||||
if ( notifIconPath.has_value() )
|
||||
{
|
||||
vr::VROverlay()->SetOverlayFromFile(
|
||||
m_brightnessNotificationOverlayHandle, notifIconPath->c_str() );
|
||||
vr::VROverlay()->SetOverlayWidthInMeters(
|
||||
m_brightnessNotificationOverlayHandle, k_overlayWidth );
|
||||
vr::HmdMatrix34_t notificationTransform
|
||||
= { { { 1.0f, 0.0f, 0.0f, 0.00f },
|
||||
{ 0.0f, 1.0f, 0.0f, 0.00f },
|
||||
{ 0.0f, 0.0f, 1.0f, k_hmdDistance } } };
|
||||
vr::VROverlay()->SetOverlayTransformTrackedDeviceRelative(
|
||||
m_brightnessNotificationOverlayHandle,
|
||||
vr::k_unTrackedDeviceIndex_Hmd,
|
||||
¬ificationTransform );
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( ERROR ) << "Could not find notification icon \""
|
||||
<< video_keys::k_brightnessOverlayFilename << "\"";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( ERROR ) << "Could not create dimmer notification overlay: "
|
||||
<< vr::VROverlay()->GetOverlayErrorNameFromEnum(
|
||||
overlayError );
|
||||
}
|
||||
|
||||
reloadVideoConfig();
|
||||
}
|
||||
reloadVideoConfig();
|
||||
}
|
||||
|
||||
void VideoTabController::eventLoopTick()
|
||||
{
|
||||
void VideoTabController::eventLoopTick() {}
|
||||
|
||||
}
|
||||
void VideoTabController::reloadVideoConfig()
|
||||
{
|
||||
auto settings = OverlayController::appSettings();
|
||||
settings->beginGroup( getSettingsName() );
|
||||
setBrightnessEnabled(
|
||||
settings->value( "brightnessEnabled", false ).toBool(), true );
|
||||
m_opacityValue = settings->value( "opacityValue", 0.0f ).toFloat();
|
||||
m_brightnessValue = settings->value( "brightnessValue", 1.0f ).toFloat();
|
||||
settings->endGroup();
|
||||
setOpacityValue();
|
||||
}
|
||||
|
||||
void VideoTabController::reloadVideoConfig() {
|
||||
auto settings = OverlayController::appSettings();
|
||||
settings->beginGroup(getSettingsName());
|
||||
setBrightnessEnabled(settings->value("brightnessEnabled", false).toBool(), true);
|
||||
m_opacityValue = settings->value("opacityValue", 0.0f).toFloat();
|
||||
m_brightnessValue=settings->value("brightnessValue", 1.0f).toFloat();
|
||||
settings->endGroup();
|
||||
setOpacityValue();
|
||||
void VideoTabController::saveVideoConfig()
|
||||
{
|
||||
auto settings = OverlayController::appSettings();
|
||||
settings->beginGroup( getSettingsName() );
|
||||
settings->setValue( "brightnessEnabled", brightnessEnabled() );
|
||||
settings->setValue( "opacityValue", opacityValue() );
|
||||
settings->setValue( "brightnessValue", brightnessValue() );
|
||||
settings->endGroup();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
float VideoTabController::opacityValue() const
|
||||
{
|
||||
return m_opacityValue;
|
||||
}
|
||||
|
||||
|
||||
void VideoTabController::saveVideoConfig() {
|
||||
auto settings = OverlayController::appSettings();
|
||||
settings->beginGroup(getSettingsName());
|
||||
settings->setValue("brightnessEnabled", brightnessEnabled());
|
||||
settings->setValue("opacityValue", opacityValue());
|
||||
settings->setValue("brightnessValue", brightnessValue());
|
||||
settings->endGroup();
|
||||
float VideoTabController::brightnessValue() const
|
||||
{
|
||||
return m_brightnessValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
float VideoTabController::opacityValue() const {
|
||||
return m_opacityValue;
|
||||
}
|
||||
bool VideoTabController::brightnessEnabled() const
|
||||
{
|
||||
return m_brightnessEnabled;
|
||||
}
|
||||
|
||||
float VideoTabController::brightnessValue() const
|
||||
{
|
||||
return m_brightnessValue;
|
||||
}
|
||||
void VideoTabController::setBrightnessEnabled( bool value, bool notify )
|
||||
{
|
||||
if ( value != m_brightnessEnabled )
|
||||
{
|
||||
m_brightnessEnabled = value;
|
||||
if ( value )
|
||||
{
|
||||
if ( getBrightnessOverlayHandle() != vr::k_ulOverlayHandleInvalid )
|
||||
{
|
||||
vr::VROverlay()->ShowOverlay( getBrightnessOverlayHandle() );
|
||||
LOG( INFO ) << "Brightness Overlay toggled on";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( getBrightnessOverlayHandle() != vr::k_ulOverlayHandleInvalid )
|
||||
{
|
||||
vr::VROverlay()->HideOverlay( getBrightnessOverlayHandle() );
|
||||
LOG( INFO ) << "Brightness Overlay toggled off";
|
||||
}
|
||||
}
|
||||
saveVideoConfig();
|
||||
if ( notify )
|
||||
{
|
||||
emit brightnessEnabledChanged( value );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool VideoTabController::brightnessEnabled() const
|
||||
{
|
||||
return m_brightnessEnabled;
|
||||
}
|
||||
|
||||
void VideoTabController::setBrightnessValue( float percvalue, bool notify )
|
||||
{
|
||||
// This takes the Perceived value, and converts it to allow more accurate
|
||||
// linear positioning. (human perception logarithmic)
|
||||
float realvalue = static_cast<float>(
|
||||
std::pow( static_cast<double>( 1.0f - percvalue ), 1 / 3. ) );
|
||||
|
||||
void VideoTabController::setBrightnessEnabled(bool value, bool notify)
|
||||
{
|
||||
if (value != m_brightnessEnabled)
|
||||
{
|
||||
m_brightnessEnabled = value;
|
||||
if (value) {
|
||||
if(getBrightnessOverlayHandle() != vr::k_ulOverlayHandleInvalid)
|
||||
{
|
||||
vr::VROverlay()->ShowOverlay(getBrightnessOverlayHandle());
|
||||
LOG(INFO) << "Brightness Overlay toggled on";
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (getBrightnessOverlayHandle() != vr::k_ulOverlayHandleInvalid)
|
||||
{
|
||||
vr::VROverlay()->HideOverlay(getBrightnessOverlayHandle());
|
||||
LOG(INFO) << "Brightness Overlay toggled off";
|
||||
}
|
||||
}
|
||||
saveVideoConfig();
|
||||
if (notify)
|
||||
{
|
||||
emit brightnessEnabledChanged(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( realvalue != m_opacityValue )
|
||||
{
|
||||
m_brightnessValue = percvalue;
|
||||
if ( realvalue <= 1.0f && realvalue >= 0.0f )
|
||||
{
|
||||
m_opacityValue = realvalue;
|
||||
vr::VROverlayError overlayError = vr::VROverlay()->SetOverlayAlpha(
|
||||
m_brightnessNotificationOverlayHandle, realvalue );
|
||||
if ( overlayError != vr::VROverlayError_None )
|
||||
{
|
||||
LOG( ERROR ) << "Could not set alpha: "
|
||||
<< vr::VROverlay()->GetOverlayErrorNameFromEnum(
|
||||
overlayError );
|
||||
}
|
||||
// only saves if opacity Value is valid. [1-0]
|
||||
saveVideoConfig();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( WARNING ) << "alpha value is invalid setting to 1.0";
|
||||
m_opacityValue = 0.0f;
|
||||
}
|
||||
|
||||
void VideoTabController::setBrightnessValue(float percvalue, bool notify)
|
||||
{
|
||||
if ( notify )
|
||||
{
|
||||
emit brightnessValueChanged( percvalue );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//This takes the Perceived value, and converts it to allow more accurate linear positioning. (human perception logarithmic)
|
||||
float realvalue = static_cast<float>(std::pow(static_cast<double>(1.0f - percvalue), 1/3.));
|
||||
|
||||
if (realvalue != m_opacityValue)
|
||||
{
|
||||
m_brightnessValue = percvalue;
|
||||
if (realvalue <= 1.0f && realvalue >= 0.0f) {
|
||||
m_opacityValue = realvalue;
|
||||
vr::VROverlayError overlayError = vr::VROverlay()->SetOverlayAlpha(m_brightnessNotificationOverlayHandle, realvalue);
|
||||
if (overlayError != vr::VROverlayError_None) {
|
||||
LOG(ERROR) << "Could not set alpha: "
|
||||
<< vr::VROverlay()->GetOverlayErrorNameFromEnum(
|
||||
overlayError);
|
||||
}
|
||||
//only saves if opacity Value is valid. [1-0]
|
||||
saveVideoConfig();
|
||||
}
|
||||
else {
|
||||
LOG(WARNING) << "alpha value is invalid setting to 1.0";
|
||||
m_opacityValue = 0.0f;
|
||||
}
|
||||
|
||||
|
||||
if (notify)
|
||||
{
|
||||
emit brightnessValueChanged(percvalue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VideoTabController::setOpacityValue() {
|
||||
vr::VROverlayError overlayError = vr::VROverlay()->SetOverlayAlpha(m_brightnessNotificationOverlayHandle, m_opacityValue);
|
||||
if (overlayError != vr::VROverlayError_None) {
|
||||
LOG(ERROR) << "Could not set alpha: "
|
||||
<< vr::VROverlay()->GetOverlayErrorNameFromEnum(
|
||||
overlayError);
|
||||
}
|
||||
emit brightnessValueChanged(m_brightnessValue);
|
||||
}
|
||||
}
|
||||
void VideoTabController::setOpacityValue()
|
||||
{
|
||||
vr::VROverlayError overlayError = vr::VROverlay()->SetOverlayAlpha(
|
||||
m_brightnessNotificationOverlayHandle, m_opacityValue );
|
||||
if ( overlayError != vr::VROverlayError_None )
|
||||
{
|
||||
LOG( ERROR ) << "Could not set alpha: "
|
||||
<< vr::VROverlay()->GetOverlayErrorNameFromEnum(
|
||||
overlayError );
|
||||
}
|
||||
emit brightnessValueChanged( m_brightnessValue );
|
||||
}
|
||||
} // namespace advsettings
|
||||
@@ -1,84 +1,76 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include <openvr.h>
|
||||
|
||||
|
||||
class QQuickWindow;
|
||||
|
||||
namespace video_keys {
|
||||
namespace video_keys
|
||||
{
|
||||
constexpr auto k_brightnessOverlayFilename = "/res/img/video/dimmer.png";
|
||||
|
||||
constexpr auto k_brightnessOverlayFilename = "/res/img/video/dimmer.png";
|
||||
} // namespace video_keys
|
||||
|
||||
}//namespace video_keys
|
||||
namespace advsettings
|
||||
{
|
||||
// forward declaration
|
||||
class OverlayController;
|
||||
|
||||
namespace advsettings {
|
||||
// forward declaration
|
||||
class OverlayController;
|
||||
class VideoTabController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY( bool brightnessEnabled READ brightnessEnabled WRITE
|
||||
setBrightnessEnabled NOTIFY brightnessEnabledChanged )
|
||||
Q_PROPERTY( float brightnessValue READ brightnessValue WRITE
|
||||
setBrightnessValue NOTIFY brightnessValueChanged )
|
||||
|
||||
class VideoTabController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool brightnessEnabled READ brightnessEnabled WRITE
|
||||
setBrightnessEnabled NOTIFY brightnessEnabledChanged)
|
||||
Q_PROPERTY(float brightnessValue READ brightnessValue WRITE
|
||||
setBrightnessValue NOTIFY brightnessValueChanged)
|
||||
private:
|
||||
// how far away the overlay is, any OVERLAY closer will not be dimmed.
|
||||
const float k_hmdDistance = -0.15f;
|
||||
// how wide overlay is, Increase this value if edges of view are not dimmed.
|
||||
const float k_overlayWidth = 1.0f;
|
||||
OverlayController* parent;
|
||||
QQuickWindow* widget;
|
||||
|
||||
private:
|
||||
vr::VROverlayHandle_t m_brightnessNotificationOverlayHandle
|
||||
= vr::k_ulOverlayHandleInvalid;
|
||||
float m_opacityValue = 0.0f;
|
||||
float m_brightnessValue = 1.0f;
|
||||
bool m_brightnessEnabled = false;
|
||||
|
||||
// how far away the overlay is, any OVERLAY closer will not be dimmed.
|
||||
const float k_hmdDistance = -0.15f;
|
||||
// how wide overlay is, Increase this value if edges of view are not dimmed.
|
||||
const float k_overlayWidth = 1.0f;
|
||||
OverlayController * parent;
|
||||
QQuickWindow* widget;
|
||||
void reloadVideoConfig();
|
||||
void saveVideoConfig();
|
||||
void setOpacityValue();
|
||||
|
||||
vr::VROverlayHandle_t m_brightnessNotificationOverlayHandle
|
||||
= vr::k_ulOverlayHandleInvalid;
|
||||
float m_opacityValue = 0.0f;
|
||||
float m_brightnessValue = 1.0f;
|
||||
bool m_brightnessEnabled = false;
|
||||
QString getSettingsName()
|
||||
{
|
||||
return "videoSettings";
|
||||
}
|
||||
|
||||
vr::VROverlayHandle_t getBrightnessOverlayHandle()
|
||||
{
|
||||
return m_brightnessNotificationOverlayHandle;
|
||||
}
|
||||
|
||||
void reloadVideoConfig();
|
||||
void saveVideoConfig();
|
||||
void setOpacityValue();
|
||||
public:
|
||||
float opacityValue() const;
|
||||
// inverse of brightnessValue
|
||||
float brightnessValue() const;
|
||||
bool brightnessEnabled() const;
|
||||
|
||||
void initStage1();
|
||||
void initStage2( OverlayController* var_parent, QQuickWindow* var_widget );
|
||||
void eventLoopTick();
|
||||
|
||||
QString getSettingsName(){
|
||||
return "videoSettings";
|
||||
}
|
||||
public slots:
|
||||
void setBrightnessEnabled( bool value, bool notify = true );
|
||||
void setBrightnessValue( float percvalue, bool notify = true );
|
||||
|
||||
vr::VROverlayHandle_t getBrightnessOverlayHandle()
|
||||
{
|
||||
return m_brightnessNotificationOverlayHandle;
|
||||
}
|
||||
signals:
|
||||
void brightnessEnabledChanged( bool value );
|
||||
void brightnessValueChanged( float value );
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
|
||||
|
||||
float opacityValue() const;
|
||||
//inverse of brightnessValue
|
||||
float brightnessValue() const;
|
||||
bool brightnessEnabled() const;
|
||||
|
||||
void initStage1();
|
||||
void initStage2(OverlayController* var_parent, QQuickWindow* var_widget);
|
||||
void eventLoopTick();
|
||||
|
||||
|
||||
public slots:
|
||||
void setBrightnessEnabled(bool value, bool notify = true);
|
||||
void setBrightnessValue(float percvalue, bool notify = true);
|
||||
|
||||
|
||||
signals:
|
||||
void brightnessEnabledChanged(bool value);
|
||||
void brightnessValueChanged(float value);
|
||||
};
|
||||
|
||||
}// namespace advsettings
|
||||
} // namespace advsettings
|
||||
Reference in New Issue
Block a user