mirror of
https://gitlab.com/pholy/OSCAR-code.git
synced 2025-04-05 10:40:42 +00:00
Initial Oximeter Live view Save Feature
This commit is contained in:
parent
e2f304c2e6
commit
cafdfc5563
@ -44,6 +44,8 @@ public:
|
||||
void setMin(EventDataType v) { m_min=v; }
|
||||
void setMax(EventDataType v) { m_max=v; }
|
||||
void setRate(EventDataType v) { m_rate=v; }
|
||||
void setCode(ChannelID id) { m_code=id; }
|
||||
|
||||
inline const EventDataType & min() { return m_min; }
|
||||
inline const EventDataType & max() { return m_max; }
|
||||
inline const EventDataType & gain() { return m_gain; }
|
||||
|
@ -30,7 +30,7 @@ CPAP_CSR, CPAP_VSnore, CPAP_PressurePulse, CPAP_Mode, CPAP_FlowRate, CPAP_MaskPr
|
||||
CPAP_EPAP, CPAP_IPAP, CPAP_IPAP_Low, CPAP_IPAP_High, CPAP_PressureSupport, CPAP_Snore, CPAP_Leak,
|
||||
CPAP_RespiratoryRate, CPAP_TidalVolume, CPAP_MinuteVentilation, CPAP_PatientTriggeredBreaths,
|
||||
CPAP_FlowLimitGraph, CPAP_TherapyPressure, CPAP_ExpiratoryPressure, CPAP_AHI, CPAP_BrokenSummary,
|
||||
CPAP_BrokenWaveform, CPAP_Pulse, CPAP_SPO2;
|
||||
CPAP_BrokenWaveform, CPAP_Pulse, CPAP_SPO2, CPAP_Plethy;
|
||||
|
||||
ChannelID RMS9_PressureReliefType, RMS9_PressureReliefSetting, RMS9_Empty1, RMS9_Empty2;
|
||||
ChannelID PRS1_PressureMin,PRS1_PressureMax, PRS1_PressureMinAchieved, PRS1_PressureMaxAchieved,
|
||||
@ -176,8 +176,9 @@ void InitMapsWithoutAwesomeInitializerLists()
|
||||
PRS1_VSnore2=CPAP_CODES.Get(CT_Event,QObject::tr("Vibratory Snore (Type 2)"),QObject::tr("VS2"),"VS2");
|
||||
|
||||
// CPAP Integrated oximetery codes..
|
||||
CPAP_Pulse=CPAP_CODES.Get(CT_Event,QObject::tr("Pulse Rate"),QObject::tr("Pulse"),"CPPR");
|
||||
CPAP_SPO2=CPAP_CODES.Get(CT_Event,QObject::tr("SpO2"),QObject::tr("SpO2"),"CPSP");
|
||||
CPAP_Pulse=CPAP_CODES.Get(CT_Graph,QObject::tr("Pulse Rate"),QObject::tr("Pulse"),"CPPR");
|
||||
CPAP_SPO2=CPAP_CODES.Get(CT_Graph,QObject::tr("SpO2"),QObject::tr("SpO2"),"CPSP");
|
||||
CPAP_Plethy=CPAP_CODES.Get(CT_Graph,QObject::tr("Plethysomagram"),QObject::tr("Plethysomagram"),"CPPL");
|
||||
|
||||
OXI_Pulse=OXI_CODES.Get(CT_Graph,QObject::tr("Pulse Rate"),QObject::tr("PR"),"PR"),
|
||||
OXI_SPO2=OXI_CODES.Get(CT_Graph,QObject::tr("Oxygen Saturation"),QObject::tr("SPO2"),"SPO2"),
|
||||
|
@ -119,7 +119,7 @@ CPAP_CSR, CPAP_VSnore, CPAP_PressurePulse, CPAP_Mode, CPAP_FlowRate, CPAP_MaskPr
|
||||
CPAP_EPAP, CPAP_IPAP, CPAP_IPAP_Low, CPAP_IPAP_High, CPAP_PressureSupport, CPAP_Snore, CPAP_Leak,
|
||||
CPAP_RespiratoryRate, CPAP_TidalVolume, CPAP_MinuteVentilation, CPAP_PatientTriggeredBreaths,
|
||||
CPAP_FlowLimitGraph, CPAP_TherapyPressure, CPAP_ExpiratoryPressure, CPAP_AHI, CPAP_BrokenSummary,
|
||||
CPAP_BrokenWaveform, CPAP_Pulse, CPAP_SPO2;
|
||||
CPAP_BrokenWaveform, CPAP_Pulse, CPAP_SPO2, CPAP_Plethy;
|
||||
|
||||
extern ChannelID RMS9_PressureReliefType, RMS9_PressureReliefSetting, RMS9_Empty1, RMS9_Empty2;
|
||||
extern ChannelID PRS1_PressureMin,PRS1_PressureMax, PRS1_PressureMinAchieved, PRS1_PressureMaxAchieved,
|
||||
|
@ -35,20 +35,23 @@ public:
|
||||
|
||||
const SessionID & session() {
|
||||
return s_session;
|
||||
};
|
||||
}
|
||||
qint64 first() {
|
||||
return s_first;
|
||||
};
|
||||
}
|
||||
qint64 last() {
|
||||
return s_last;
|
||||
};
|
||||
}
|
||||
qint64 length() {
|
||||
return s_last-s_first;
|
||||
}
|
||||
void SetSessionID(SessionID s) {
|
||||
s_session=s;
|
||||
};
|
||||
}
|
||||
void set_first(qint64 d) {
|
||||
if (!s_first) s_first=d;
|
||||
else if (d<s_first) s_first=d;
|
||||
};
|
||||
}
|
||||
void set_last(qint64 d) {
|
||||
if (d<=s_first) {
|
||||
qWarning() << "Session::set_last() d<=s_first";
|
||||
@ -56,20 +59,20 @@ public:
|
||||
}
|
||||
if (!s_last) s_last=d;
|
||||
else if (s_last<d) s_last=d;
|
||||
};
|
||||
}
|
||||
|
||||
double hours() {
|
||||
double t=(s_last-s_first)/3600000.0;
|
||||
return t;
|
||||
};
|
||||
}
|
||||
|
||||
void SetChanged(bool val) {
|
||||
s_changed=val;
|
||||
s_events_loaded=val; // dirty hack putting this here
|
||||
};
|
||||
}
|
||||
bool IsChanged() {
|
||||
return s_changed;
|
||||
};
|
||||
}
|
||||
|
||||
QHash<ChannelID,QVector<EventList *> > eventlist;
|
||||
QHash<ChannelID,QVariant> settings;
|
||||
|
89
daily.cpp
89
daily.cpp
@ -77,7 +77,9 @@ Daily::Daily(QWidget *parent,QGLWidget * shared, MainWindow *mw)
|
||||
|
||||
scrollArea=new MyScrollArea(ui->graphMainArea,this);
|
||||
ui->graphLayout->addWidget(scrollArea,1);
|
||||
|
||||
ui->graphLayout->setSpacing(0);
|
||||
ui->graphLayout->setMargin(0);
|
||||
ui->graphLayout->setContentsMargins(0,0,0,0);
|
||||
scrollArea->setWidgetResizable(true);
|
||||
scrollArea->setAutoFillBackground(false);
|
||||
|
||||
@ -130,6 +132,7 @@ Daily::Daily(QWidget *parent,QGLWidget * shared, MainWindow *mw)
|
||||
INTSPO2=new gGraphWindow(parental,tr("SPO2"),SF); // Integrated Pulse
|
||||
PULSE=new gGraphWindow(parental,tr("Pulse"),SF);
|
||||
SPO2=new gGraphWindow(parental,tr("SPO2"),SF);
|
||||
PLETHY=new gGraphWindow(parental,tr("Plethysomogram"),SF);
|
||||
|
||||
TAP=new gGraphWindow(NULL,"",(QGLWidget* )NULL);
|
||||
TAP_EAP=new gGraphWindow(NULL,"",(QGLWidget* )NULL);
|
||||
@ -268,6 +271,11 @@ Daily::Daily(QWidget *parent,QGLWidget * shared, MainWindow *mw)
|
||||
INTSPO2->AddLayer(AddCPAP(new gLineChart(CPAP_SPO2,Qt::blue,true)));
|
||||
INTSPO2->setMinimumHeight(min_height);
|
||||
|
||||
PLETHY->AddLayer(new gXAxis());
|
||||
PLETHY->AddLayer(new gYAxis());
|
||||
PLETHY->AddLayer(AddOXI(new gLineChart(OXI_Plethysomogram,Qt::darkCyan,true)));
|
||||
PLETHY->setMinimumHeight(min_height);
|
||||
|
||||
PULSE->AddLayer(new gXAxis());
|
||||
PULSE->AddLayer(new gYAxis());
|
||||
PULSE->AddLayer(AddOXI(new gLineChart(OXI_Pulse,Qt::red,true)));
|
||||
@ -356,11 +364,16 @@ Daily::Daily(QWidget *parent,QGLWidget * shared, MainWindow *mw)
|
||||
//AddGraph(OF);
|
||||
AddGraph(PULSE);
|
||||
AddGraph(SPO2);
|
||||
AddGraph(PLETHY);
|
||||
|
||||
//SPO2->LinkZoom(OF);
|
||||
//PULSE->LinkZoom(OF);
|
||||
SPO2->LinkZoom(PULSE);
|
||||
SPO2->LinkZoom(PLETHY);
|
||||
PULSE->LinkZoom(SPO2);
|
||||
PULSE->LinkZoom(PLETHY);
|
||||
PLETHY->LinkZoom(PULSE);
|
||||
PLETHY->LinkZoom(SPO2);
|
||||
//OF->LinkZoom(PULSE);
|
||||
//OF->LinkZoom(SPO2);
|
||||
|
||||
@ -634,9 +647,9 @@ void Daily::Load(QDate date)
|
||||
GraphAction[i]->setVisible(false);
|
||||
Graphs[i]->hide();
|
||||
} else {
|
||||
Graphs[i]->ResetBounds();
|
||||
GraphAction[i]->setVisible(true);
|
||||
if (GraphAction[i]->isChecked()) {
|
||||
Graphs[i]->ResetBounds();
|
||||
Graphs[i]->show();
|
||||
vis++;
|
||||
} else {
|
||||
@ -645,7 +658,10 @@ void Daily::Load(QDate date)
|
||||
}
|
||||
}
|
||||
if (!cpap) {
|
||||
GraphAction[0]->setVisible(false);
|
||||
SF->hide();
|
||||
vis--;
|
||||
|
||||
}
|
||||
//splitter->layout();
|
||||
for (int i=0;i<Graphs.size();i++) {
|
||||
@ -668,6 +684,8 @@ void Daily::Load(QDate date)
|
||||
// }
|
||||
// splitter->blockSignals(true);
|
||||
|
||||
splitter->setSpacing(0);
|
||||
splitter->setMargin(0);
|
||||
splitter->layout();
|
||||
scrollArea->setUpdatesEnabled(true);
|
||||
scrollArea->update();
|
||||
@ -760,6 +778,7 @@ void Daily::Load(QDate date)
|
||||
|
||||
// Note, this may not be a problem since Qt bug 13622 was discovered
|
||||
// as it only relates to text drawing, which the Pie chart does not do
|
||||
// ^^ Scratch that.. pie now includes text..
|
||||
|
||||
if (pref["EnableGraphSnapshots"].toBool()) { // AHI Pie Chart
|
||||
html+="</tr>\n<tr><td colspan=4 align=center><i>"+tr("Event Breakdown")+"</i></td></tr>\n";
|
||||
@ -771,9 +790,11 @@ void Daily::Load(QDate date)
|
||||
pixmap.save(&buffer, "PNG");
|
||||
html += "<tr><td colspan=4 align=center><img src=\"data:image/png;base64," + byteArray.toBase64() + "\"></td></tr>\n";
|
||||
}
|
||||
}
|
||||
html+="</table>"
|
||||
"<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n"
|
||||
"<tr height='2'><td colspan=5 height='2'><hr></td></tr>\n";
|
||||
"<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n";
|
||||
if (cpap || oxi) {
|
||||
html+="<tr height='2'><td colspan=5 height='2'><hr></td></tr>\n";
|
||||
|
||||
/* if (mode==MODE_BIPAP) {
|
||||
html+="<tr><td colspan=4 align='center'><i>"+tr("90% EPAP ")+QString().sprintf("%.2f",eap90)+tr("cmH2O")+"</td></tr>\n"
|
||||
@ -787,12 +808,11 @@ void Daily::Load(QDate date)
|
||||
//html+=("<tr><td colspan=4 align=center> </td></tr>\n");
|
||||
|
||||
html+=("<tr><td> </td><td><b>Min</b></td><td><b>Avg</b></td><td><b>90%</b></td><td><b>Max</b></td></tr>");
|
||||
|
||||
ChannelID chans[]={CPAP_Pressure,CPAP_EPAP,CPAP_IPAP,CPAP_PressureSupport,CPAP_PatientTriggeredBreaths, CPAP_MinuteVentilation,CPAP_RespiratoryRate,CPAP_FlowLimitGraph,CPAP_Leak,CPAP_Snore,CPAP_TidalVolume,CPAP_Pulse,CPAP_SPO2};
|
||||
ChannelID chans[]={CPAP_Pressure,CPAP_EPAP,CPAP_IPAP,CPAP_PressureSupport,CPAP_PatientTriggeredBreaths, CPAP_MinuteVentilation,CPAP_RespiratoryRate,CPAP_FlowLimitGraph,CPAP_Leak,CPAP_Snore,CPAP_TidalVolume,CPAP_Pulse,CPAP_SPO2,OXI_Pulse,OXI_SPO2};
|
||||
int numchans=sizeof(chans)/sizeof(ChannelID);
|
||||
for (int i=0;i<numchans;i++) {
|
||||
ChannelID code=chans[i];
|
||||
if (cpap->channelExists(code)) {
|
||||
if (cpap && cpap->channelExists(code)) {
|
||||
html+="<tr><td align=left>"+channel[code].label();
|
||||
html+="</td><td>"+a.sprintf("%.2f",cpap->min(code));
|
||||
html+="</td><td>"+a.sprintf("%.2f",cpap->wavg(code));
|
||||
@ -800,58 +820,25 @@ void Daily::Load(QDate date)
|
||||
html+="</td><td>"+a.sprintf("%.2f",cpap->max(code));
|
||||
html+="</td><tr>";
|
||||
}
|
||||
if (oxi && oxi->channelExists(code)) {
|
||||
html+="<tr><td align=left>"+channel[code].label();
|
||||
html+="</td><td>"+a.sprintf("%.2f",oxi->min(code));
|
||||
html+="</td><td>"+a.sprintf("%.2f",oxi->wavg(code));
|
||||
html+="</td><td>"+a.sprintf("%.2f",oxi->p90(code));
|
||||
html+="</td><td>"+a.sprintf("%.2f",oxi->max(code));
|
||||
html+="</td><tr>";
|
||||
}
|
||||
}
|
||||
|
||||
/*html+="<tr><td align=left>"+tr("Snore:");
|
||||
html+="</td><td>"+a.sprintf("%.2f",cpap->min(CPAP_Snore));
|
||||
html+="</td><td>"+a.sprintf("%.2f",cpap->avg(CPAP_Snore));
|
||||
html+="</td><td>"+a.sprintf("%.2f",cpap->max(CPAP_Snore))+("</td><tr>");
|
||||
*/
|
||||
|
||||
} else {
|
||||
html+="<tr><td colspan=5 align=center><i>"+tr("No CPAP data available")+"</i></td></tr>";
|
||||
html+="<tr><td colspan=5 align=center><i>"+tr("No data available")+"</i></td></tr>";
|
||||
html+="<tr><td colspan=5> </td></tr>\n";
|
||||
|
||||
}
|
||||
// Instead of doing this, check whether any data exists..
|
||||
// and show based on this factor.
|
||||
|
||||
|
||||
bool merge_oxi_graphs=true;
|
||||
if (!merge_oxi_graphs) {
|
||||
//spo2->isEmpty() ? SPO2->hide() : SPO2->show();
|
||||
//pulse->isEmpty() ? PULSE->hide() : PULSE->show();
|
||||
} else {
|
||||
//pulse->isEmpty() && spo2->isEmpty() ? PULSE->hide() : PULSE->show();
|
||||
}
|
||||
|
||||
if (oxi) {
|
||||
html+="<tr><td>"+tr("Pulse:");
|
||||
html+="</td><td>"+a.sprintf("%.2fbpm",oxi->min(OXI_Pulse));
|
||||
html+="</td><td>"+a.sprintf("%.2fbpm",oxi->wavg(OXI_Pulse));
|
||||
html+="</td><td>"+a.sprintf("%.2fbpm",oxi->p90(OXI_Pulse));
|
||||
html+="</td><td>"+a.sprintf("%.2fbpm",oxi->max(OXI_Pulse));
|
||||
html+="</td><tr>";
|
||||
|
||||
html+="<tr><td>"+tr("SpO2:");
|
||||
html+="</td><td>"+a.sprintf("%.2f%%",oxi->min(OXI_SPO2));
|
||||
html+="</td><td>"+a.sprintf("%.2f%%",oxi->wavg(OXI_SPO2));
|
||||
html+="</td><td>"+a.sprintf("%.2f%%",oxi->p90(OXI_SPO2));
|
||||
html+="</td><td>"+a.sprintf("%.2f%%",oxi->max(OXI_SPO2));
|
||||
html+="</td><tr>";
|
||||
|
||||
//html+=wxT("<tr><td colspan=4> </td></tr>\n");
|
||||
|
||||
//PULSE->show();
|
||||
//SPO2->show();
|
||||
} else {
|
||||
//PULSE->hide();
|
||||
//SPO2->hide();
|
||||
}
|
||||
html+="</table>";
|
||||
html+="<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n";
|
||||
|
||||
if (cpap) {
|
||||
html+="</table>"
|
||||
"<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n";
|
||||
if (pref["EnableGraphSnapshots"].toBool()) {
|
||||
if (cpap->channelExists(CPAP_Pressure)) {
|
||||
html+=("<tr><td colspan=4 align=center><i>")+tr("Time@Pressure")+("</i></td></tr>\n");
|
||||
|
3
daily.h
3
daily.h
@ -88,7 +88,8 @@ private:
|
||||
|
||||
gFlagsGroup *fg;
|
||||
gGraphWindow *PRD,*FRW,*G_AHI,*TAP,*LEAK,*SF,*TAP_EAP,*TAP_IAP,*PULSE,*SPO2,
|
||||
*SNORE,*RR,*MP,*MV,*TV,*FLG,*PTB,*OF,*INTPULSE,*INTSPO2, *THPR;
|
||||
*SNORE,*RR,*MP,*MV,*TV,*FLG,*PTB,*OF,*INTPULSE,*INTSPO2, *THPR,
|
||||
*PLETHY;
|
||||
|
||||
gLineChart *pressure, *epap, *ipap;
|
||||
|
||||
|
79
oximetry.cpp
79
oximetry.cpp
@ -174,6 +174,8 @@ void Oximetry::on_RunButton_toggled(bool checked)
|
||||
lasttime=QDateTime::currentMSecsSinceEpoch();
|
||||
starttime=lasttime;
|
||||
|
||||
session->SetSessionID(lasttime/1000L);
|
||||
|
||||
day->setFirst(lasttime);
|
||||
day->setLast(lasttime+30000);
|
||||
session->set_first(lasttime);
|
||||
@ -245,6 +247,81 @@ void Oximetry::on_RunButton_toggled(bool checked)
|
||||
PLETHY->updateGL();
|
||||
SPO2->updateGL();
|
||||
PULSE->updateGL();
|
||||
|
||||
qint64 d=session->length();
|
||||
// if (d<=30000)
|
||||
// return;
|
||||
if (QMessageBox::question(this,"Keep This Recording?","Would you like to keep this oximeter recording?",QMessageBox::Yes|QMessageBox::No)==QMessageBox::Yes) {
|
||||
qDebug() << "Saving oximeter session data";
|
||||
Session *sess=new Session(mach,starttime/1000L);
|
||||
|
||||
/*ev_spo2->setCode(CPAP_SPO2);
|
||||
ev_pulse->setCode(CPAP_Pulse);
|
||||
ev_plethy->setCode(CPAP_Plethy); */
|
||||
sess->eventlist[OXI_SPO2].push_back(ev_spo2);
|
||||
sess->eventlist[OXI_Pulse].push_back(ev_pulse);
|
||||
sess->eventlist[OXI_Plethysomogram].push_back(ev_plethy);
|
||||
//Session *sess=session;
|
||||
sess->SetSessionID(starttime/1000L);
|
||||
|
||||
sess->setMin(OXI_Pulse,ev_pulse->min());
|
||||
sess->setMax(OXI_Pulse,ev_pulse->min());
|
||||
sess->setFirst(OXI_Pulse,ev_pulse->first());
|
||||
sess->setLast(OXI_Pulse,ev_pulse->last());
|
||||
sess->avg(OXI_Pulse);
|
||||
sess->wavg(OXI_Pulse);
|
||||
sess->p90(OXI_Pulse);
|
||||
//sess->min(OXI_Pulse);
|
||||
//sess->max(OXI_Pulse);
|
||||
|
||||
sess->setMin(OXI_SPO2,ev_spo2->min());
|
||||
sess->setMax(OXI_SPO2,ev_spo2->max());
|
||||
sess->setFirst(OXI_SPO2,ev_spo2->first());
|
||||
sess->setLast(OXI_SPO2,ev_spo2->last());
|
||||
sess->avg(OXI_SPO2);
|
||||
sess->wavg(OXI_SPO2);
|
||||
sess->p90(OXI_SPO2);
|
||||
//sess->min(OXI_SPO2);
|
||||
//sess->max(OXI_SPO2);
|
||||
|
||||
sess->setMin(OXI_SPO2,ev_spo2->min());
|
||||
sess->setMax(OXI_SPO2,ev_spo2->max());
|
||||
sess->setFirst(OXI_SPO2,ev_spo2->first());
|
||||
sess->setLast(OXI_SPO2,ev_spo2->last());
|
||||
|
||||
//sess->min(OXI_Plethysomogram);
|
||||
//sess->max(OXI_Plethysomogram);
|
||||
sess->avg(OXI_Plethysomogram);
|
||||
sess->wavg(OXI_Plethysomogram);
|
||||
sess->p90(OXI_Plethysomogram);
|
||||
sess->setMin(OXI_Plethysomogram,ev_plethy->min());
|
||||
sess->setMax(OXI_Plethysomogram,ev_plethy->max());
|
||||
sess->setFirst(OXI_Plethysomogram,ev_plethy->first());
|
||||
sess->setLast(OXI_Plethysomogram,ev_plethy->last());
|
||||
|
||||
sess->updateFirst(sess->first(OXI_Pulse));
|
||||
sess->updateLast(sess->last(OXI_Pulse));
|
||||
sess->updateFirst(sess->first(OXI_SPO2));
|
||||
sess->updateLast(sess->last(OXI_SPO2));
|
||||
sess->updateFirst(sess->first(OXI_Plethysomogram));
|
||||
sess->updateLast(sess->last(OXI_Plethysomogram));
|
||||
|
||||
sess->SetChanged(true);
|
||||
mach->AddSession(sess,profile);
|
||||
mach->Save();
|
||||
|
||||
|
||||
session->eventlist.clear();
|
||||
ev_plethy=new EventList(OXI_Plethysomogram,EVL_Waveform,1,0,0,0,1000.0/50.0);
|
||||
session->eventlist[OXI_Plethysomogram].push_back(ev_plethy);
|
||||
|
||||
ev_pulse=new EventList(OXI_Pulse,EVL_Event,1);
|
||||
session->eventlist[OXI_Pulse].push_back(ev_pulse);
|
||||
|
||||
ev_spo2=new EventList(OXI_SPO2,EVL_Event,1);
|
||||
session->eventlist[OXI_SPO2].push_back(ev_spo2);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -627,7 +704,7 @@ void Oximetry::on_ImportButton_clicked()
|
||||
day->AddSession(session);
|
||||
|
||||
// As did these
|
||||
ev_plethy=new EventList(OXI_Plethysomogram,EVL_Waveform,1,0,0,0,1.0/50.0);
|
||||
ev_plethy=new EventList(OXI_Plethysomogram,EVL_Waveform,1,0,0,0,1000.0/50.0);
|
||||
session->eventlist[OXI_Plethysomogram].push_back(ev_plethy);
|
||||
|
||||
ev_pulse=new EventList(OXI_Pulse,EVL_Event,1);
|
||||
|
Loading…
Reference in New Issue
Block a user