mirror of
https://github.com/yairm210/Unciv.git
synced 2025-03-09 04:09:35 +07:00
Organized Unit Table UI
This commit is contained in:
parent
c71f320731
commit
5b66f8f0f7
BIN
android/Images/OtherIcons/BackArrow.png
Normal file
BIN
android/Images/OtherIcons/BackArrow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 757 B |
@ -697,6 +697,13 @@ ImprovementIcons/Trading post
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
OtherIcons/BackArrow
|
||||
rotate: false
|
||||
xy: 1734, 1215
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
OtherIcons/Banner
|
||||
rotate: false
|
||||
xy: 1297, 1727
|
||||
@ -811,273 +818,273 @@ PolicyIcons/Aristocracy
|
||||
index: -1
|
||||
PolicyIcons/Citizenship
|
||||
rotate: false
|
||||
xy: 1734, 1215
|
||||
xy: 1734, 1163
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Civil Society
|
||||
rotate: false
|
||||
xy: 1734, 1163
|
||||
xy: 1734, 1111
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Collective Rule
|
||||
rotate: false
|
||||
xy: 1734, 1111
|
||||
xy: 1734, 1059
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Constitution
|
||||
rotate: false
|
||||
xy: 1734, 1059
|
||||
xy: 1734, 1007
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Democracy
|
||||
rotate: false
|
||||
xy: 1734, 1007
|
||||
xy: 1734, 955
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Discipline
|
||||
rotate: false
|
||||
xy: 1734, 955
|
||||
xy: 1734, 903
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Entrepreneurship
|
||||
rotate: false
|
||||
xy: 1734, 903
|
||||
xy: 1734, 851
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Facism
|
||||
rotate: false
|
||||
xy: 1734, 851
|
||||
xy: 1734, 799
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Free Religion
|
||||
rotate: false
|
||||
xy: 1734, 799
|
||||
xy: 1734, 747
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Free Speech
|
||||
rotate: false
|
||||
xy: 1734, 747
|
||||
xy: 1734, 695
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Free Thought
|
||||
rotate: false
|
||||
xy: 1734, 695
|
||||
xy: 1734, 643
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Humanism
|
||||
rotate: false
|
||||
xy: 1734, 643
|
||||
xy: 1734, 591
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Landed Elite
|
||||
rotate: false
|
||||
xy: 1734, 591
|
||||
xy: 1734, 539
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Legalism
|
||||
rotate: false
|
||||
xy: 1734, 539
|
||||
xy: 1734, 487
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Mandate Of Heaven
|
||||
rotate: false
|
||||
xy: 1734, 487
|
||||
xy: 1734, 435
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Mercantilism
|
||||
rotate: false
|
||||
xy: 1734, 435
|
||||
xy: 1734, 383
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Meritocracy
|
||||
rotate: false
|
||||
xy: 1734, 383
|
||||
xy: 1734, 331
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Militarism
|
||||
rotate: false
|
||||
xy: 1734, 331
|
||||
xy: 1892, 1237
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Military Caste
|
||||
rotate: false
|
||||
xy: 1892, 1237
|
||||
xy: 1944, 1237
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Military Tradition
|
||||
rotate: false
|
||||
xy: 1944, 1237
|
||||
xy: 1786, 1187
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Monarchy
|
||||
rotate: false
|
||||
xy: 1786, 1187
|
||||
xy: 1786, 1135
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Oligarchy
|
||||
rotate: false
|
||||
xy: 1786, 1135
|
||||
xy: 1838, 1187
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Organized Religion
|
||||
rotate: false
|
||||
xy: 1838, 1187
|
||||
xy: 1786, 1083
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Patronage
|
||||
rotate: false
|
||||
xy: 1786, 1083
|
||||
xy: 1838, 1135
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Police State
|
||||
rotate: false
|
||||
xy: 1838, 1135
|
||||
xy: 1786, 1031
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Populism
|
||||
rotate: false
|
||||
xy: 1786, 1031
|
||||
xy: 1838, 1083
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Professional Army
|
||||
rotate: false
|
||||
xy: 1838, 1083
|
||||
xy: 1786, 979
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Protectionism
|
||||
rotate: false
|
||||
xy: 1786, 979
|
||||
xy: 1838, 1031
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Reformation
|
||||
rotate: false
|
||||
xy: 1838, 1031
|
||||
xy: 1786, 927
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Representation
|
||||
rotate: false
|
||||
xy: 1786, 927
|
||||
xy: 1838, 979
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Republic
|
||||
rotate: false
|
||||
xy: 1838, 979
|
||||
xy: 1786, 875
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Scientific Revolution
|
||||
rotate: false
|
||||
xy: 1786, 875
|
||||
xy: 1838, 927
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Secularism
|
||||
rotate: false
|
||||
xy: 1838, 927
|
||||
xy: 1786, 823
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Sovereignty
|
||||
rotate: false
|
||||
xy: 1786, 823
|
||||
xy: 1838, 875
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Theocracy
|
||||
rotate: false
|
||||
xy: 1838, 875
|
||||
xy: 1786, 771
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Total War
|
||||
rotate: false
|
||||
xy: 1786, 771
|
||||
xy: 1838, 823
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Trade Unions
|
||||
rotate: false
|
||||
xy: 1838, 823
|
||||
xy: 1786, 719
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Universal Suffrage
|
||||
rotate: false
|
||||
xy: 1786, 719
|
||||
xy: 1838, 771
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
PolicyIcons/Warrior Code
|
||||
rotate: false
|
||||
xy: 1838, 771
|
||||
xy: 1786, 667
|
||||
size: 50, 50
|
||||
orig: 50, 50
|
||||
offset: 0, 0
|
||||
@ -2281,14 +2288,14 @@ UnitPromotionIcons/Coastal_Raider_I_(Civ5)
|
||||
index: -1
|
||||
UnitPromotionIcons/Cover_II_(Civ5)
|
||||
rotate: false
|
||||
xy: 1786, 697
|
||||
xy: 1838, 749
|
||||
size: 20, 20
|
||||
orig: 20, 20
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
UnitPromotionIcons/Cover_I_(Civ5)
|
||||
rotate: false
|
||||
xy: 1838, 749
|
||||
xy: 1786, 645
|
||||
size: 20, 20
|
||||
orig: 20, 20
|
||||
offset: 0, 0
|
||||
@ -2414,28 +2421,28 @@ UnitPromotionIcons/Shock_I_(Civ5)
|
||||
index: -1
|
||||
UnitPromotionIcons/Siege_(Civ5)
|
||||
rotate: false
|
||||
xy: 1786, 675
|
||||
xy: 1838, 727
|
||||
size: 20, 20
|
||||
orig: 20, 20
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
UnitPromotionIcons/Targeting_III_(Civ5)
|
||||
rotate: false
|
||||
xy: 1808, 697
|
||||
xy: 1860, 749
|
||||
size: 20, 20
|
||||
orig: 20, 20
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
UnitPromotionIcons/Targeting_II_(Civ5)
|
||||
rotate: false
|
||||
xy: 1838, 727
|
||||
xy: 1786, 623
|
||||
size: 20, 20
|
||||
orig: 20, 20
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
UnitPromotionIcons/Targeting_I_(Civ5)
|
||||
rotate: false
|
||||
xy: 1860, 749
|
||||
xy: 1808, 645
|
||||
size: 20, 20
|
||||
orig: 20, 20
|
||||
offset: 0, 0
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 797 KiB After Width: | Height: | Size: 798 KiB |
@ -94,6 +94,7 @@ class EmpireOverviewScreen : CameraStageBaseScreen(){
|
||||
table.defaults().pad(10f)
|
||||
table.background = ImageGetter.getBackground(civ.getNation().getColor())
|
||||
table.add(Label(civ.civName.tr(),skin).setFontColor(civ.getNation().getSecondaryColor())).row()
|
||||
table.addSeparator()
|
||||
for(offer in offersList){
|
||||
var offerText = offer.amount.toString()+" "+offer.name.tr()
|
||||
if(offer.duration>0)offerText += " ("+offer.duration+" {turns})".tr()
|
||||
|
@ -42,6 +42,7 @@ class DiplomacyScreen():CameraStageBaseScreen(){
|
||||
val peaceWarStatus = civDiplomacy.diplomaticStatus.toString()
|
||||
civTable.add(Label(civ.civName.tr() + " ({$peaceWarStatus})".tr(), skin)
|
||||
.apply { setFontSize(22); setFontColor(civ.getNation().getSecondaryColor()) }).row()
|
||||
civTable.addSeparator()
|
||||
|
||||
val tradeButton = TextButton("Trade".tr(), skin)
|
||||
tradeButton.onClick {
|
||||
|
@ -63,7 +63,10 @@ open class CameraStageBaseScreen : Screen {
|
||||
var skin = Skin(Gdx.files.internal("skin/flat-earth-ui.json"))
|
||||
.apply {
|
||||
get<TextButton.TextButtonStyle>(TextButton.TextButtonStyle::class.java).font = getFont(20)
|
||||
get<Label.LabelStyle>(Label.LabelStyle::class.java).font = getFont(18)
|
||||
get<Label.LabelStyle>(Label.LabelStyle::class.java).apply {
|
||||
font = getFont(18)
|
||||
fontColor= Color.WHITE
|
||||
}
|
||||
get<TextField.TextFieldStyle>(TextField.TextFieldStyle::class.java).font = getFont(18)
|
||||
get<SelectBox.SelectBoxStyle>(SelectBox.SelectBoxStyle::class.java).font = getFont(20)
|
||||
get<SelectBox.SelectBoxStyle>(SelectBox.SelectBoxStyle::class.java).listStyle.font = getFont(20)
|
||||
@ -192,4 +195,10 @@ fun Actor.onClick(function: () -> Unit) {
|
||||
|
||||
fun Image.surroundWithCircle(size:Float): IconCircleGroup {
|
||||
return IconCircleGroup(size,this)
|
||||
}
|
||||
|
||||
fun Table.addSeparator(): Image {
|
||||
val image = ImageGetter.getWhiteDot()
|
||||
add(image).colspan(columns).fill().row()
|
||||
return image
|
||||
}
|
@ -1,18 +1,32 @@
|
||||
package com.unciv.ui.worldscreen.unit
|
||||
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.scenes.scene2d.Touchable
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.badlogic.gdx.utils.Align
|
||||
import com.unciv.logic.map.TileInfo
|
||||
import com.unciv.ui.utils.CameraStageBaseScreen
|
||||
import com.unciv.ui.utils.ImageGetter
|
||||
import com.unciv.ui.utils.onClick
|
||||
import com.unciv.ui.worldscreen.TileMapHolder
|
||||
|
||||
class IdleUnitButton internal constructor(internal val unitTable: UnitTable,
|
||||
class IdleUnitButton (internal val unitTable: UnitTable,
|
||||
val tileMapHolder: TileMapHolder, val previous:Boolean)
|
||||
: TextButton(if(previous)"<" else ">", CameraStageBaseScreen.skin) {
|
||||
: Table() {
|
||||
|
||||
val image = ImageGetter.getImage("OtherIcons/BackArrow")
|
||||
|
||||
fun getTilesWithIdleUnits() = tileMapHolder.tileMap.values
|
||||
.filter { it.hasIdleUnit() && it.getUnits().first().owner == unitTable.worldScreen.civInfo.civName }
|
||||
|
||||
init {
|
||||
val imageSize = 25f
|
||||
if(!previous){
|
||||
image.setSize(imageSize,imageSize)
|
||||
image.setOrigin(Align.center)
|
||||
image.rotateBy(180f)
|
||||
}
|
||||
add(image).size(imageSize).pad(10f,20f,10f,20f)
|
||||
enable()
|
||||
onClick {
|
||||
val tilesWithIdleUnits = getTilesWithIdleUnits()
|
||||
|
||||
@ -30,5 +44,15 @@ class IdleUnitButton internal constructor(internal val unitTable: UnitTable,
|
||||
unitTable.worldScreen.update()
|
||||
}
|
||||
}
|
||||
|
||||
fun enable(){
|
||||
image.color= Color.WHITE
|
||||
touchable=Touchable.enabled
|
||||
}
|
||||
|
||||
fun disable(){
|
||||
image.color= Color.GRAY
|
||||
touchable=Touchable.disabled
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.unciv.ui.worldscreen.unit
|
||||
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Image
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Label
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.unciv.logic.map.MapUnit
|
||||
@ -14,13 +15,14 @@ class UnitTable(val worldScreen: WorldScreen) : Table(){
|
||||
private val unitIconHolder=Table()
|
||||
private val unitNameLabel = Label("",CameraStageBaseScreen.skin)
|
||||
private val promotionsTable = Table()
|
||||
private val unitDescriptionLabel = Label("",CameraStageBaseScreen.skin)
|
||||
private val unitDescriptionTable = Table(CameraStageBaseScreen.skin)
|
||||
var selectedUnit : MapUnit? = null
|
||||
var currentlyExecutingAction : String? = null
|
||||
|
||||
// This is so that not on every update(), we will update the unit table.
|
||||
// Most of the time it's the same unit with the same stats so why waste precious time?
|
||||
var selectedUnitHasChanged = false
|
||||
val separator: Image
|
||||
|
||||
init {
|
||||
pad(5f)
|
||||
@ -31,8 +33,9 @@ class UnitTable(val worldScreen: WorldScreen) : Table(){
|
||||
add(unitNameLabel).pad(5f)
|
||||
add(nextIdleUnitButton)
|
||||
}).colspan(2).row()
|
||||
add(promotionsTable).row()
|
||||
add(unitDescriptionLabel)
|
||||
separator= addSeparator()
|
||||
add(promotionsTable).colspan(2).row()
|
||||
add(unitDescriptionTable)
|
||||
}
|
||||
|
||||
fun update() {
|
||||
@ -58,32 +61,45 @@ class UnitTable(val worldScreen: WorldScreen) : Table(){
|
||||
}
|
||||
|
||||
if(selectedUnit!=null) { // set texts - this is valid even when it's the same unit, because movement points and health change
|
||||
separator.isVisible=true
|
||||
val unit = selectedUnit!!
|
||||
var nameLabelText = unit.name.tr()
|
||||
if(unit.health<100) nameLabelText+=" ("+unit.health+")"
|
||||
unitNameLabel.setText(nameLabelText)
|
||||
|
||||
var unitLabelText = "Movement".tr()+": " + unit.getMovementString()
|
||||
if (!unit.type.isCivilian())
|
||||
unitLabelText += "\n"+"Strength".tr()+": " + unit.baseUnit().strength
|
||||
unitDescriptionTable.clear()
|
||||
unitDescriptionTable.defaults().pad(2f).padRight(5f)
|
||||
unitDescriptionTable.add("Movement")
|
||||
unitDescriptionTable.add(unit.getMovementString()).row()
|
||||
|
||||
if (unit.baseUnit().rangedStrength!=0)
|
||||
unitLabelText += "\n"+"Ranged strength".tr()+": "+unit.baseUnit().rangedStrength
|
||||
if (!unit.type.isCivilian()) {
|
||||
unitDescriptionTable.add("Strength")
|
||||
unitDescriptionTable.add(unit.baseUnit().strength.toString()).row()
|
||||
}
|
||||
|
||||
if (!unit.type.isCivilian())
|
||||
unitLabelText += "\n"+"XP".tr()+": "+unit.promotions.XP+"/"+unit.promotions.xpForNextPromotion()
|
||||
if (unit.baseUnit().rangedStrength!=0) {
|
||||
unitDescriptionTable.add("Ranged strength")
|
||||
unitDescriptionTable.add(unit.baseUnit().rangedStrength.toString()).row()
|
||||
}
|
||||
|
||||
if(unit.isFortified() && unit.getFortificationTurns()>0)
|
||||
unitLabelText+="\n+"+unit.getFortificationTurns()*20+"% fortification"
|
||||
if (!unit.type.isCivilian()) {
|
||||
unitDescriptionTable.add("XP")
|
||||
unitDescriptionTable.add(unit.promotions.XP.toString()+"/"+unit.promotions.xpForNextPromotion()).row()
|
||||
}
|
||||
|
||||
unitDescriptionLabel.setText(unitLabelText)
|
||||
if(unit.isFortified() && unit.getFortificationTurns()>0) {
|
||||
unitDescriptionTable.add("Fortification")
|
||||
unitDescriptionTable.add(""+unit.getFortificationTurns() * 20 + "%")
|
||||
}
|
||||
unitDescriptionTable.pack()
|
||||
|
||||
if(unit.promotions.promotions.size != promotionsTable.children.size) // The unit has been promoted! Reload promotions!
|
||||
selectedUnitHasChanged = true
|
||||
}
|
||||
else {
|
||||
separator.isVisible=false
|
||||
unitNameLabel.setText("")
|
||||
unitDescriptionLabel.setText("")
|
||||
unitDescriptionTable.clear()
|
||||
unitIconHolder.clear()
|
||||
}
|
||||
|
||||
@ -91,15 +107,14 @@ class UnitTable(val worldScreen: WorldScreen) : Table(){
|
||||
|
||||
unitIconHolder.clear()
|
||||
promotionsTable.clear()
|
||||
unitDescriptionLabel.clearListeners()
|
||||
unitDescriptionTable.clearListeners()
|
||||
|
||||
if(selectedUnit!=null) {
|
||||
|
||||
unitIconHolder.add(TileGroup(TileInfo()).getUnitImage(selectedUnit!!,30f)).pad(5f)
|
||||
for(promotion in selectedUnit!!.promotions.promotions)
|
||||
promotionsTable.add(ImageGetter.getPromotionIcon(promotion)).size(20f)
|
||||
|
||||
unitDescriptionLabel.onClick { worldScreen.tileMapHolder.setCenterPosition(selectedUnit!!.getTile().position) }
|
||||
unitDescriptionTable.onClick { worldScreen.tileMapHolder.setCenterPosition(selectedUnit!!.getTile().position) }
|
||||
}
|
||||
|
||||
pack()
|
||||
|
Loading…
Reference in New Issue
Block a user