mirror of
https://github.com/MarlinFirmware/Marlin.git
synced 2024-11-27 13:56:24 +00:00
🚸 Fix and improve MKS LVGL UI (#22783)
Co-authored-by: makerbase <4164049@qq.com> Co-authored-by: MKS-Sean <56996910+MKS-Sean@users.noreply.github.com> Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
This commit is contained in:
parent
ab9609146f
commit
4d113c2efd
@ -69,8 +69,8 @@ void TFT::LCD_init() {
|
||||
}
|
||||
|
||||
void TFT::LCD_clear(uint16_t color) {
|
||||
setWindow(0, 0, (TFT_WIDTH), (TFT_HEIGHT));
|
||||
tftio.WriteMultiple(color, (uint32_t)(TFT_WIDTH) * (TFT_HEIGHT));
|
||||
setWindow(0, 0, TFT_WIDTH, TFT_HEIGHT);
|
||||
tftio.WriteMultiple(color, uint32_t(TFT_WIDTH) * uint32_t(TFT_HEIGHT));
|
||||
}
|
||||
|
||||
void TFT::LCD_Draw_Logo() {
|
||||
|
@ -124,9 +124,8 @@ void lv_draw_baby_stepping() {
|
||||
buttonV = lv_imgbtn_create(scr, nullptr, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_BABY_STEP_DIST);
|
||||
labelV = lv_label_create_empty(buttonV);
|
||||
#if HAS_ROTARY_ENCODER
|
||||
if (gCfgItems.encoder_enable) {
|
||||
if (gCfgItems.encoder_enable)
|
||||
lv_group_add_obj(g, buttonV);
|
||||
}
|
||||
#endif
|
||||
|
||||
lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_BABY_STEP_RETURN);
|
||||
|
@ -109,9 +109,7 @@ static void btn_ok_event_cb(lv_obj_t *btn, lv_event_t event) {
|
||||
planner.e_factor[1] = planner.flow_percentage[1] * 0.01f;
|
||||
#endif
|
||||
card.startOrResumeFilePrinting();
|
||||
#if ENABLED(POWER_LOSS_RECOVERY)
|
||||
recovery.prepare();
|
||||
#endif
|
||||
TERN_(POWER_LOSS_RECOVERY, recovery.prepare());
|
||||
once_flag = false;
|
||||
}
|
||||
}
|
||||
|
@ -44,9 +44,11 @@ enum {
|
||||
ID_F_RETURN
|
||||
};
|
||||
|
||||
uint8_t fanPercent = 0;
|
||||
static void event_handler(lv_obj_t *obj, lv_event_t event) {
|
||||
if (event != LV_EVENT_RELEASED) return;
|
||||
uint8_t fanPercent = map(thermalManager.fan_speed[0], 0, 255, 0, 100);
|
||||
const uint8_t temp = map(thermalManager.fan_speed[0], 0, 255, 0, 100);
|
||||
if (abs(fanPercent - temp) > 2) fanPercent = temp;
|
||||
switch (obj->mks_obj_id) {
|
||||
case ID_F_ADD: if (fanPercent < 100) fanPercent++; break;
|
||||
case ID_F_DEC: if (fanPercent != 0) fanPercent--; break;
|
||||
@ -56,6 +58,7 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) {
|
||||
case ID_F_RETURN: clear_cur_ui(); draw_return_ui(); return;
|
||||
}
|
||||
thermalManager.set_fan_speed(0, map(fanPercent, 0, 100, 0, 255));
|
||||
if (obj->mks_obj_id != ID_F_RETURN) disp_fan_value();
|
||||
}
|
||||
|
||||
void lv_draw_fan() {
|
||||
@ -78,7 +81,7 @@ void lv_draw_fan() {
|
||||
|
||||
void disp_fan_value() {
|
||||
#if HAS_FAN
|
||||
sprintf_P(public_buf_l, PSTR("%s: %3d%%"), fan_menu.state, (int)map(thermalManager.fan_speed[0], 0, 255, 0, 100));
|
||||
sprintf_P(public_buf_l, PSTR("%s: %3d%%"), fan_menu.state, fanPercent);
|
||||
#else
|
||||
sprintf_P(public_buf_l, PSTR("%s: ---"), fan_menu.state);
|
||||
#endif
|
||||
|
@ -52,7 +52,8 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) {
|
||||
case ID_FILAMNT_IN:
|
||||
uiCfg.filament_load_heat_flg = true;
|
||||
if (ABS(thermalManager.degTargetHotend(uiCfg.extruderIndex) - thermalManager.wholeDegHotend(uiCfg.extruderIndex)) <= 1
|
||||
|| gCfgItems.filament_limit_temp <= thermalManager.wholeDegHotend(uiCfg.extruderIndex)) {
|
||||
|| gCfgItems.filament_limit_temp <= thermalManager.wholeDegHotend(uiCfg.extruderIndex)
|
||||
) {
|
||||
lv_clear_filament_change();
|
||||
lv_draw_dialog(DIALOG_TYPE_FILAMENT_HEAT_LOAD_COMPLETED);
|
||||
}
|
||||
@ -115,9 +116,8 @@ void lv_draw_filament_change() {
|
||||
|
||||
buttonType = lv_imgbtn_create(scr, nullptr, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_FILAMNT_TYPE);
|
||||
#if HAS_ROTARY_ENCODER
|
||||
if (gCfgItems.encoder_enable) {
|
||||
if (gCfgItems.encoder_enable)
|
||||
lv_group_add_obj(g, buttonType);
|
||||
}
|
||||
#endif
|
||||
|
||||
lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_FILAMNT_RETURN);
|
||||
|
@ -69,17 +69,17 @@ void lv_show_gcode_output(void * that, const char * txt) {
|
||||
}
|
||||
}
|
||||
|
||||
void lv_serial_capt_hook(void * userPointer, uint8_t c)
|
||||
{
|
||||
void lv_serial_capt_hook(void * userPointer, uint8_t c) {
|
||||
if (c == '\n' || currentWritePos == sizeof(public_buf_m) - 1) { // End of line, probably end of command anyway
|
||||
public_buf_m[currentWritePos] = 0;
|
||||
lv_show_gcode_output(userPointer, public_buf_m);
|
||||
currentWritePos = 0;
|
||||
}
|
||||
else public_buf_m[currentWritePos++] = c;
|
||||
else
|
||||
public_buf_m[currentWritePos++] = c;
|
||||
}
|
||||
void lv_eom_hook(void *)
|
||||
{
|
||||
|
||||
void lv_eom_hook(void *) {
|
||||
// Message is done, let's remove the hook now
|
||||
MYSERIAL1.setHook();
|
||||
// We are back from the keyboard, so let's redraw ourselves
|
||||
|
@ -72,7 +72,8 @@ static const lv_btnm_ctrl_t kb_ctrl_num_map[] = {
|
||||
1, 1, 1, LV_KB_CTRL_BTN_FLAGS | 2,
|
||||
1, 1, 1, LV_KB_CTRL_BTN_FLAGS | 2,
|
||||
1, 1, 1, 2,
|
||||
1, 1, 1, 1, 1};
|
||||
1, 1, 1, 1, 1
|
||||
};
|
||||
|
||||
static void lv_kb_event_cb(lv_obj_t *kb, lv_event_t event) {
|
||||
if (event != LV_EVENT_VALUE_CHANGED) return;
|
||||
@ -252,7 +253,7 @@ void lv_draw_keyboard() {
|
||||
switch (keyboard_value) {
|
||||
case autoLevelGcodeCommand:
|
||||
get_gcode_command(AUTO_LEVELING_COMMAND_ADDR, (uint8_t *)public_buf_m);
|
||||
public_buf_m[sizeof(public_buf_m)-1] = 0;
|
||||
public_buf_m[sizeof(public_buf_m) - 1] = '\0';
|
||||
lv_ta_set_text(ta, public_buf_m);
|
||||
break;
|
||||
case GCodeCommand:
|
||||
@ -272,5 +273,4 @@ void lv_clear_keyboard() {
|
||||
lv_obj_del(scr);
|
||||
}
|
||||
|
||||
|
||||
#endif // HAS_TFT_LVGL_UI
|
||||
|
@ -32,10 +32,17 @@
|
||||
|
||||
static lv_obj_t *scr;
|
||||
extern lv_group_t* g;
|
||||
static lv_obj_t *buttonType, *buttonStep;
|
||||
static lv_obj_t *buttonType, *buttonStep, *buttonAdd, *buttonDec;
|
||||
static lv_obj_t *labelType;
|
||||
static lv_obj_t *labelStep;
|
||||
static lv_obj_t *tempText1;
|
||||
static lv_obj_t *btn_pla;
|
||||
static lv_obj_t *btn_abs;
|
||||
static lv_obj_t *label_abs;
|
||||
static lv_obj_t *label_pla;
|
||||
|
||||
static lv_style_t btn_style_pre;
|
||||
static lv_style_t btn_style_rel;
|
||||
|
||||
enum {
|
||||
ID_P_ADD = 1,
|
||||
@ -43,7 +50,9 @@ enum {
|
||||
ID_P_TYPE,
|
||||
ID_P_STEP,
|
||||
ID_P_OFF,
|
||||
ID_P_RETURN
|
||||
ID_P_RETURN,
|
||||
ID_P_ABS,
|
||||
ID_P_PLA
|
||||
};
|
||||
|
||||
static void event_handler(lv_obj_t *obj, lv_event_t event) {
|
||||
@ -55,10 +64,11 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) {
|
||||
thermalManager.temp_hotend[uiCfg.extruderIndex].target += uiCfg.stepHeat;
|
||||
if (uiCfg.extruderIndex == 0)
|
||||
max_target = HEATER_0_MAXTEMP - (WATCH_TEMP_INCREASE + TEMP_HYSTERESIS + 1);
|
||||
else {
|
||||
#if HAS_MULTI_HOTEND
|
||||
else
|
||||
max_target = HEATER_1_MAXTEMP - (WATCH_TEMP_INCREASE + TEMP_HYSTERESIS + 1);
|
||||
#endif
|
||||
}
|
||||
if (thermalManager.degTargetHotend(uiCfg.extruderIndex) > max_target)
|
||||
thermalManager.setTargetHotend(max_target, uiCfg.extruderIndex);
|
||||
thermalManager.start_watching_hotend(uiCfg.extruderIndex);
|
||||
@ -83,16 +93,16 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) {
|
||||
thermalManager.setTargetHotend(0, uiCfg.extruderIndex);
|
||||
thermalManager.start_watching_hotend(uiCfg.extruderIndex);
|
||||
}
|
||||
#if HAS_HEATED_BED
|
||||
else {
|
||||
#if HAS_HEATED_BED
|
||||
if (thermalManager.degTargetBed() > uiCfg.stepHeat)
|
||||
thermalManager.temp_bed.target -= uiCfg.stepHeat;
|
||||
else
|
||||
thermalManager.setTargetBed(0);
|
||||
|
||||
thermalManager.start_watching_bed();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
disp_desire_temp();
|
||||
break;
|
||||
case ID_P_TYPE:
|
||||
@ -102,7 +112,7 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) {
|
||||
uiCfg.extruderIndex = 1;
|
||||
}
|
||||
else if (uiCfg.extruderIndex == 1) {
|
||||
if (TEMP_SENSOR_BED != 0) {
|
||||
if (ENABLED(HAS_HEATED_BED)) {
|
||||
uiCfg.curTempType = 1;
|
||||
}
|
||||
else {
|
||||
@ -112,15 +122,14 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) {
|
||||
}
|
||||
}
|
||||
else if (uiCfg.extruderIndex == 0) {
|
||||
if (TEMP_SENSOR_BED != 0)
|
||||
uiCfg.curTempType = 1;
|
||||
else
|
||||
uiCfg.curTempType = 0;
|
||||
uiCfg.curTempType = TERN(HAS_HEATED_BED, 1, 0);
|
||||
}
|
||||
}
|
||||
else if (uiCfg.curTempType == 1) {
|
||||
uiCfg.extruderIndex = 0;
|
||||
uiCfg.curTempType = 0;
|
||||
disp_add_dec();
|
||||
disp_ext_heart();
|
||||
}
|
||||
disp_temp_type();
|
||||
break;
|
||||
@ -138,30 +147,44 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) {
|
||||
thermalManager.setTargetHotend(0, uiCfg.extruderIndex);
|
||||
thermalManager.start_watching_hotend(uiCfg.extruderIndex);
|
||||
}
|
||||
#if HAS_HEATED_BED
|
||||
else {
|
||||
#if HAS_HEATED_BED
|
||||
thermalManager.temp_bed.target = 0;
|
||||
thermalManager.start_watching_bed();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
disp_desire_temp();
|
||||
break;
|
||||
case ID_P_RETURN:
|
||||
clear_cur_ui();
|
||||
draw_return_ui();
|
||||
break;
|
||||
case ID_P_ABS:
|
||||
thermalManager.setTargetHotend(PREHEAT_2_TEMP_HOTEND, 0);
|
||||
break;
|
||||
case ID_P_PLA:
|
||||
thermalManager.setTargetHotend(PREHEAT_1_TEMP_HOTEND, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void disp_add_dec() {
|
||||
// Create image buttons
|
||||
buttonAdd = lv_big_button_create(scr, "F:/bmp_Add.bin", preheat_menu.add, INTERVAL_V, titleHeight, event_handler, ID_P_ADD);
|
||||
buttonDec = lv_big_button_create(scr, "F:/bmp_Dec.bin", preheat_menu.dec, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_P_DEC);
|
||||
}
|
||||
|
||||
void lv_draw_preHeat() {
|
||||
scr = lv_screen_create(PRE_HEAT_UI);
|
||||
|
||||
// Create image buttons
|
||||
lv_big_button_create(scr, "F:/bmp_Add.bin", preheat_menu.add, INTERVAL_V, titleHeight, event_handler, ID_P_ADD);
|
||||
lv_big_button_create(scr, "F:/bmp_Dec.bin", preheat_menu.dec, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_P_DEC);
|
||||
disp_add_dec();
|
||||
|
||||
buttonType = lv_imgbtn_create(scr, nullptr, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_P_TYPE);
|
||||
buttonStep = lv_imgbtn_create(scr, nullptr, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_P_STEP);
|
||||
|
||||
if (uiCfg.curTempType == 0) disp_ext_heart();
|
||||
|
||||
#if HAS_ROTARY_ENCODER
|
||||
if (gCfgItems.encoder_enable) {
|
||||
lv_group_add_obj(g, buttonType);
|
||||
@ -184,6 +207,19 @@ void lv_draw_preHeat() {
|
||||
disp_desire_temp();
|
||||
}
|
||||
|
||||
void disp_ext_heart() {
|
||||
btn_abs = lv_btn_create(scr, 160, 40, 80, 40, event_handler, ID_P_ABS);
|
||||
btn_pla = lv_btn_create(scr, 260, 40, 80, 40, event_handler, ID_P_PLA);
|
||||
|
||||
lv_btn_set_style(btn_abs, LV_BTN_STYLE_PR, &btn_style_pre);
|
||||
lv_btn_set_style(btn_abs, LV_BTN_STYLE_REL, &btn_style_rel);
|
||||
lv_btn_set_style(btn_pla, LV_BTN_STYLE_PR, &btn_style_pre);
|
||||
lv_btn_set_style(btn_pla, LV_BTN_STYLE_REL, &btn_style_rel);
|
||||
|
||||
label_abs = lv_label_create(btn_abs, PREHEAT_2_LABEL);
|
||||
label_pla = lv_label_create(btn_pla, PREHEAT_1_LABEL);
|
||||
}
|
||||
|
||||
void disp_temp_type() {
|
||||
if (uiCfg.curTempType == 0) {
|
||||
if (uiCfg.extruderIndex == 1) {
|
||||
@ -200,7 +236,6 @@ void disp_temp_type() {
|
||||
lv_obj_align(labelType, buttonType, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
lv_imgbtn_set_src_both(buttonType, "F:/bmp_bed.bin");
|
||||
|
@ -30,6 +30,8 @@ void lv_clear_preHeat();
|
||||
void disp_temp_type();
|
||||
void disp_step_heat();
|
||||
void disp_desire_temp();
|
||||
void disp_ext_heart();
|
||||
void disp_add_dec();
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* C-declarations for C++ */
|
||||
|
@ -43,7 +43,7 @@
|
||||
#include "mks_hardware.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define ICON_POS_Y 38
|
||||
#define ICON_POS_Y 260
|
||||
#define TARGET_LABEL_MOD_Y -36
|
||||
#define LABEL_MOD_Y 30
|
||||
|
||||
@ -183,16 +183,16 @@ void lv_draw_ready_print() {
|
||||
lv_label_set_text(det_info, " ");
|
||||
}
|
||||
else {
|
||||
lv_big_button_create(scr, "F:/bmp_tool.bin", main_menu.tool, 20, 150, event_handler, ID_TOOL);
|
||||
lv_big_button_create(scr, "F:/bmp_set.bin", main_menu.set, 180, 150, event_handler, ID_SET);
|
||||
lv_big_button_create(scr, "F:/bmp_printing.bin", main_menu.print, 340, 150, event_handler, ID_PRINT);
|
||||
lv_big_button_create(scr, "F:/bmp_tool.bin", main_menu.tool, 20, 90, event_handler, ID_TOOL);
|
||||
lv_big_button_create(scr, "F:/bmp_set.bin", main_menu.set, 180, 90, event_handler, ID_SET);
|
||||
lv_big_button_create(scr, "F:/bmp_printing.bin", main_menu.print, 340, 90, event_handler, ID_PRINT);
|
||||
|
||||
// Monitoring
|
||||
#if HAS_HOTEND
|
||||
buttonExt1 = lv_big_button_create(scr, "F:/bmp_ext1_state.bin", " ", 55, ICON_POS_Y, event_handler, ID_INFO_EXT);
|
||||
buttonExt1 = lv_big_button_create(scr, "F:/bmp_ext1_state.bin", " ", 20, ICON_POS_Y, event_handler, ID_INFO_EXT);
|
||||
#endif
|
||||
#if HAS_MULTI_HOTEND
|
||||
buttonExt2 = lv_big_button_create(scr, "F:/bmp_ext2_state.bin", " ", 163, ICON_POS_Y, event_handler, ID_INFO_EXT);
|
||||
buttonExt2 = lv_big_button_create(scr, "F:/bmp_ext2_state.bin", " ", 180, ICON_POS_Y, event_handler, ID_INFO_EXT);
|
||||
#endif
|
||||
#if HAS_HEATED_BED
|
||||
buttonBedstate = lv_big_button_create(scr, "F:/bmp_bed_state.bin", " ", TERN(HAS_MULTI_HOTEND, 271, 210), ICON_POS_Y, event_handler, ID_INFO_BED);
|
||||
@ -219,22 +219,22 @@ void lv_temp_refr() {
|
||||
#if HAS_HOTEND
|
||||
sprintf(public_buf_l, printing_menu.temp1, thermalManager.wholeDegHotend(0), thermalManager.degTargetHotend(0));
|
||||
lv_label_set_text(labelExt1, public_buf_l);
|
||||
lv_obj_align(labelExt1, buttonExt1, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
|
||||
lv_obj_align(labelExt1, buttonExt1, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
|
||||
#endif
|
||||
#if HAS_MULTI_HOTEND
|
||||
sprintf(public_buf_l, printing_menu.temp1, thermalManager.wholeDegHotend(1), thermalManager.degTargetHotend(1));
|
||||
lv_label_set_text(labelExt2, public_buf_l);
|
||||
lv_obj_align(labelExt2, buttonExt2, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
|
||||
lv_obj_align(labelExt2, buttonExt2, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
|
||||
#endif
|
||||
#if HAS_HEATED_BED
|
||||
sprintf(public_buf_l, printing_menu.bed_temp, thermalManager.wholeDegBed(), thermalManager.degTargetBed());
|
||||
lv_label_set_text(labelBed, public_buf_l);
|
||||
lv_obj_align(labelBed, buttonBedstate, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
|
||||
lv_obj_align(labelBed, buttonBedstate, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
|
||||
#endif
|
||||
#if HAS_FAN
|
||||
sprintf_P(public_buf_l, PSTR("%d%%"), (int)thermalManager.fanSpeedPercent(0));
|
||||
lv_label_set_text(labelFan, public_buf_l);
|
||||
lv_obj_align(labelFan, buttonFanstate, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
|
||||
lv_obj_align(labelFan, buttonFanstate, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -241,8 +241,7 @@ void my_disp_flush(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * co
|
||||
|
||||
SPI_TFT.setWindow((uint16_t)area->x1, (uint16_t)area->y1, width, height);
|
||||
|
||||
for (uint16_t i = 0; i < height; i++)
|
||||
SPI_TFT.tftio.WriteSequence((uint16_t*)(color_p + width * i), width);
|
||||
SPI_TFT.tftio.WriteSequence((uint16_t*)color_p, width * height);
|
||||
|
||||
lv_disp_flush_ready(disp); // Indicate you are ready with the flushing
|
||||
|
||||
|
@ -68,7 +68,8 @@ WifiSerial::WifiSerial(usart_dev *usart_device, uint8 tx_pin, uint8 rx_pin) {
|
||||
#define disable_timer_if_necessary(dev, ch) NOOP
|
||||
|
||||
static void usart_enable_no_irq(usart_dev *usart_device, bool with_irq) {
|
||||
if (with_irq) usart_enable(usart_device);
|
||||
if (with_irq)
|
||||
usart_enable(usart_device);
|
||||
else {
|
||||
usart_reg_map *regs = usart_device->regs;
|
||||
regs->CR1 |= (USART_CR1_TE | USART_CR1_RE); // Preserve word length, etc. Use 'or' to preserve USART_CR1_M_8N1
|
||||
|
@ -450,7 +450,7 @@ EspUploadResult Sync(uint16_t timeout) {
|
||||
}
|
||||
}
|
||||
// DEBUG
|
||||
//else debug//printf("stat=%d\n", (int)stat);
|
||||
//else printf("stat=%d\n", (int)stat);
|
||||
return stat;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user