Add hyphenationFrequency attribute to TextView and StaticLayout.
This patch adds plumbing to TextView and StaticLayout to control the frequency of automatic hyphenation used in laying out paragraphs. Bug: 21038249 Change-Id: Ib45de190eb0a1ed738e69fd61f2b39561b11aec7
This commit is contained in:
@@ -653,6 +653,7 @@ package android {
|
||||
field public static final int horizontalScrollViewStyle = 16843603; // 0x1010353
|
||||
field public static final int horizontalSpacing = 16843028; // 0x1010114
|
||||
field public static final int host = 16842792; // 0x1010028
|
||||
field public static final int hyphenationFrequency = 16844024; // 0x10104f8
|
||||
field public static final int icon = 16842754; // 0x1010002
|
||||
field public static final int iconPreview = 16843337; // 0x1010249
|
||||
field public static final int iconTint = 16843999; // 0x10104df
|
||||
@@ -32166,6 +32167,9 @@ package android.text {
|
||||
field public static final int BREAK_STRATEGY_SIMPLE = 0; // 0x0
|
||||
field public static final int DIR_LEFT_TO_RIGHT = 1; // 0x1
|
||||
field public static final int DIR_RIGHT_TO_LEFT = -1; // 0xffffffff
|
||||
field public static final int HYPHENATION_FREQUENCY_FULL = 2; // 0x2
|
||||
field public static final int HYPHENATION_FREQUENCY_NONE = 0; // 0x0
|
||||
field public static final int HYPHENATION_FREQUENCY_NORMAL = 1; // 0x1
|
||||
}
|
||||
|
||||
public static final class Layout.Alignment extends java.lang.Enum {
|
||||
@@ -32364,6 +32368,7 @@ package android.text {
|
||||
method public android.text.StaticLayout.Builder setBreakStrategy(int);
|
||||
method public android.text.StaticLayout.Builder setEllipsize(android.text.TextUtils.TruncateAt);
|
||||
method public android.text.StaticLayout.Builder setEllipsizedWidth(int);
|
||||
method public android.text.StaticLayout.Builder setHyphenationFrequency(int);
|
||||
method public android.text.StaticLayout.Builder setIncludePad(boolean);
|
||||
method public android.text.StaticLayout.Builder setIndents(int[], int[]);
|
||||
method public android.text.StaticLayout.Builder setLineSpacing(float, float);
|
||||
@@ -41446,6 +41451,7 @@ package android.widget {
|
||||
method public int getHighlightColor();
|
||||
method public java.lang.CharSequence getHint();
|
||||
method public final android.content.res.ColorStateList getHintTextColors();
|
||||
method public int getHyphenationFrequency();
|
||||
method public int getImeActionId();
|
||||
method public java.lang.CharSequence getImeActionLabel();
|
||||
method public int getImeOptions();
|
||||
@@ -41552,6 +41558,7 @@ package android.widget {
|
||||
method public final void setHintTextColor(int);
|
||||
method public final void setHintTextColor(android.content.res.ColorStateList);
|
||||
method public void setHorizontallyScrolling(boolean);
|
||||
method public void setHyphenationFrequency(int);
|
||||
method public void setImeActionLabel(java.lang.CharSequence, int);
|
||||
method public void setImeOptions(int);
|
||||
method public void setIncludeFontPadding(boolean);
|
||||
|
||||
@@ -725,6 +725,7 @@ package android {
|
||||
field public static final int horizontalScrollViewStyle = 16843603; // 0x1010353
|
||||
field public static final int horizontalSpacing = 16843028; // 0x1010114
|
||||
field public static final int host = 16842792; // 0x1010028
|
||||
field public static final int hyphenationFrequency = 16844024; // 0x10104f8
|
||||
field public static final int icon = 16842754; // 0x1010002
|
||||
field public static final int iconPreview = 16843337; // 0x1010249
|
||||
field public static final int iconTint = 16843999; // 0x10104df
|
||||
@@ -34388,6 +34389,9 @@ package android.text {
|
||||
field public static final int BREAK_STRATEGY_SIMPLE = 0; // 0x0
|
||||
field public static final int DIR_LEFT_TO_RIGHT = 1; // 0x1
|
||||
field public static final int DIR_RIGHT_TO_LEFT = -1; // 0xffffffff
|
||||
field public static final int HYPHENATION_FREQUENCY_FULL = 2; // 0x2
|
||||
field public static final int HYPHENATION_FREQUENCY_NONE = 0; // 0x0
|
||||
field public static final int HYPHENATION_FREQUENCY_NORMAL = 1; // 0x1
|
||||
}
|
||||
|
||||
public static final class Layout.Alignment extends java.lang.Enum {
|
||||
@@ -34586,6 +34590,7 @@ package android.text {
|
||||
method public android.text.StaticLayout.Builder setBreakStrategy(int);
|
||||
method public android.text.StaticLayout.Builder setEllipsize(android.text.TextUtils.TruncateAt);
|
||||
method public android.text.StaticLayout.Builder setEllipsizedWidth(int);
|
||||
method public android.text.StaticLayout.Builder setHyphenationFrequency(int);
|
||||
method public android.text.StaticLayout.Builder setIncludePad(boolean);
|
||||
method public android.text.StaticLayout.Builder setIndents(int[], int[]);
|
||||
method public android.text.StaticLayout.Builder setLineSpacing(float, float);
|
||||
@@ -43979,6 +43984,7 @@ package android.widget {
|
||||
method public int getHighlightColor();
|
||||
method public java.lang.CharSequence getHint();
|
||||
method public final android.content.res.ColorStateList getHintTextColors();
|
||||
method public int getHyphenationFrequency();
|
||||
method public int getImeActionId();
|
||||
method public java.lang.CharSequence getImeActionLabel();
|
||||
method public int getImeOptions();
|
||||
@@ -44085,6 +44091,7 @@ package android.widget {
|
||||
method public final void setHintTextColor(int);
|
||||
method public final void setHintTextColor(android.content.res.ColorStateList);
|
||||
method public void setHorizontallyScrolling(boolean);
|
||||
method public void setHyphenationFrequency(int);
|
||||
method public void setImeActionLabel(java.lang.CharSequence, int);
|
||||
method public void setImeOptions(int);
|
||||
method public void setIncludeFontPadding(boolean);
|
||||
|
||||
@@ -79,7 +79,8 @@ public class DynamicLayout extends Layout
|
||||
boolean includepad,
|
||||
TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
|
||||
this(base, display, paint, width, align, TextDirectionHeuristics.FIRSTSTRONG_LTR,
|
||||
spacingmult, spacingadd, includepad, StaticLayout.BREAK_STRATEGY_SIMPLE,
|
||||
spacingmult, spacingadd, includepad,
|
||||
StaticLayout.BREAK_STRATEGY_SIMPLE, StaticLayout.HYPHENATION_FREQUENCY_NONE,
|
||||
ellipsize, ellipsizedWidth);
|
||||
}
|
||||
|
||||
@@ -96,7 +97,7 @@ public class DynamicLayout extends Layout
|
||||
TextPaint paint,
|
||||
int width, Alignment align, TextDirectionHeuristic textDir,
|
||||
float spacingmult, float spacingadd,
|
||||
boolean includepad, int breakStrategy,
|
||||
boolean includepad, int breakStrategy, int hyphenationFrequency,
|
||||
TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
|
||||
super((ellipsize == null)
|
||||
? display
|
||||
@@ -122,6 +123,7 @@ public class DynamicLayout extends Layout
|
||||
|
||||
mIncludePad = includepad;
|
||||
mBreakStrategy = breakStrategy;
|
||||
mHyphenationFrequency = hyphenationFrequency;
|
||||
|
||||
/*
|
||||
* This is annoying, but we can't refer to the layout until
|
||||
@@ -293,7 +295,8 @@ public class DynamicLayout extends Layout
|
||||
.setLineSpacing(getSpacingAdd(), getSpacingMultiplier())
|
||||
.setEllipsizedWidth(mEllipsizedWidth)
|
||||
.setEllipsize(mEllipsizeAt)
|
||||
.setBreakStrategy(mBreakStrategy);
|
||||
.setBreakStrategy(mBreakStrategy)
|
||||
.setHyphenationFrequency(mHyphenationFrequency);
|
||||
reflowed.generate(b, false, true);
|
||||
int n = reflowed.getLineCount();
|
||||
|
||||
@@ -719,6 +722,7 @@ public class DynamicLayout extends Layout
|
||||
private int mEllipsizedWidth;
|
||||
private TextUtils.TruncateAt mEllipsizeAt;
|
||||
private int mBreakStrategy;
|
||||
private int mHyphenationFrequency;
|
||||
|
||||
private PackedIntVector mInts;
|
||||
private PackedObjectVector<Directions> mObjects;
|
||||
|
||||
@@ -71,6 +71,35 @@ public abstract class Layout {
|
||||
*/
|
||||
public static final int BREAK_STRATEGY_BALANCED = 2;
|
||||
|
||||
/** @hide */
|
||||
@IntDef({HYPHENATION_FREQUENCY_NORMAL, HYPHENATION_FREQUENCY_FULL,
|
||||
HYPHENATION_FREQUENCY_NONE})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface HyphenationFrequency {}
|
||||
|
||||
/**
|
||||
* Value for hyphenation frequency indicating no automatic hyphenation. Useful
|
||||
* for backward compatibility, and for cases where the automatic hyphenation algorithm results
|
||||
* in incorrect hyphenation. Mid-word breaks may still happen when a word is wider than the
|
||||
* layout and there is otherwise no valid break. Soft hyphens are ignored and will not be used
|
||||
* as suggestions for potential line breaks.
|
||||
*/
|
||||
public static final int HYPHENATION_FREQUENCY_NONE = 0;
|
||||
|
||||
/**
|
||||
* Value for hyphenation frequency indicating a light amount of automatic hyphenation, which
|
||||
* is a conservative default. Useful for informal cases, such as short sentences or chat
|
||||
* messages.
|
||||
*/
|
||||
public static final int HYPHENATION_FREQUENCY_NORMAL = 1;
|
||||
|
||||
/**
|
||||
* Value for hyphenation frequency indicating the full amount of automatic hyphenation, typical
|
||||
* in typography. Useful for running text and where it's important to put the maximum amount of
|
||||
* text in a screen with limited space.
|
||||
*/
|
||||
public static final int HYPHENATION_FREQUENCY_FULL = 2;
|
||||
|
||||
private static final ParagraphStyle[] NO_PARA_SPANS =
|
||||
ArrayUtils.emptyArray(ParagraphStyle.class);
|
||||
|
||||
|
||||
@@ -92,6 +92,7 @@ public class StaticLayout extends Layout {
|
||||
b.mEllipsize = null;
|
||||
b.mMaxLines = Integer.MAX_VALUE;
|
||||
b.mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE;
|
||||
b.mHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE;
|
||||
|
||||
b.mMeasuredText = MeasuredText.obtain();
|
||||
return b;
|
||||
@@ -275,6 +276,19 @@ public class StaticLayout extends Layout {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set hyphenation frequency, to control the amount of automatic hyphenation used. The
|
||||
* default is {@link Layout#HYPHENATION_FREQUENCY_NONE}.
|
||||
*
|
||||
* @param hyphenationFrequency hyphenation frequency for the paragraph
|
||||
* @return this builder, useful for chaining
|
||||
* @see android.widget.TextView#setHyphenationFrequency
|
||||
*/
|
||||
public Builder setHyphenationFrequency(@HyphenationFrequency int hyphenationFrequency) {
|
||||
mHyphenationFrequency = hyphenationFrequency;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set indents. Arguments are arrays holding an indent amount, one per line, measured in
|
||||
* pixels. For lines past the last element in the array, the last element repeats.
|
||||
@@ -302,7 +316,8 @@ public class StaticLayout extends Layout {
|
||||
* the native code is as follows.
|
||||
*
|
||||
* For each paragraph, do a nSetupParagraph, which sets paragraph text, line width, tab
|
||||
* stops, break strategy (and possibly other parameters in the future).
|
||||
* stops, break strategy, and hyphenation frequency (and possibly other parameters in the
|
||||
* future).
|
||||
*
|
||||
* Then, for each run within the paragraph:
|
||||
* - setLocale (this must be done at least for the first run, optional afterwards)
|
||||
@@ -377,6 +392,7 @@ public class StaticLayout extends Layout {
|
||||
TextUtils.TruncateAt mEllipsize;
|
||||
int mMaxLines;
|
||||
int mBreakStrategy;
|
||||
int mHyphenationFrequency;
|
||||
|
||||
Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
|
||||
|
||||
@@ -644,7 +660,7 @@ public class StaticLayout extends Layout {
|
||||
|
||||
nSetupParagraph(b.mNativePtr, chs, paraEnd - paraStart,
|
||||
firstWidth, firstWidthLineCount, restWidth,
|
||||
variableTabStops, TAB_INCREMENT, b.mBreakStrategy);
|
||||
variableTabStops, TAB_INCREMENT, b.mBreakStrategy, b.mHyphenationFrequency);
|
||||
|
||||
// measurement has to be done before performing line breaking
|
||||
// but we don't want to recompute fontmetrics or span ranges the
|
||||
@@ -1153,7 +1169,7 @@ public class StaticLayout extends Layout {
|
||||
// Set up paragraph text and settings; done as one big method to minimize jni crossings
|
||||
private static native void nSetupParagraph(long nativePtr, char[] text, int length,
|
||||
float firstWidth, int firstWidthLineCount, float restWidth,
|
||||
int[] variableTabStops, int defaultTabStop, int breakStrategy);
|
||||
int[] variableTabStops, int defaultTabStop, int breakStrategy, int hyphenationFrequency);
|
||||
|
||||
private static native float nAddStyleRun(long nativePtr, long nativePaint,
|
||||
long nativeTypeface, int start, int end, boolean isRtl);
|
||||
|
||||
@@ -238,6 +238,7 @@ import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
|
||||
* @attr ref android.R.styleable#TextView_letterSpacing
|
||||
* @attr ref android.R.styleable#TextView_fontFeatureSettings
|
||||
* @attr ref android.R.styleable#TextView_breakStrategy
|
||||
* @attr ref android.R.styleable#TextView_hyphenationFrequency
|
||||
* @attr ref android.R.styleable#TextView_leftIndents
|
||||
* @attr ref android.R.styleable#TextView_rightIndents
|
||||
*/
|
||||
@@ -555,6 +556,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
private float mSpacingAdd = 0.0f;
|
||||
|
||||
private int mBreakStrategy;
|
||||
private int mHyphenationFrequency;
|
||||
private int[] mLeftIndents;
|
||||
private int[] mRightIndents;
|
||||
|
||||
@@ -696,6 +698,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
float letterSpacing = 0;
|
||||
String fontFeatureSettings = null;
|
||||
mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE;
|
||||
mHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE;
|
||||
|
||||
final Resources.Theme theme = context.getTheme();
|
||||
|
||||
@@ -1154,6 +1157,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
mBreakStrategy = a.getInt(attr, Layout.BREAK_STRATEGY_SIMPLE);
|
||||
break;
|
||||
|
||||
case com.android.internal.R.styleable.TextView_hyphenationFrequency:
|
||||
mHyphenationFrequency = a.getInt(attr, Layout.HYPHENATION_FREQUENCY_NONE);
|
||||
break;
|
||||
|
||||
case com.android.internal.R.styleable.TextView_leftIndents:
|
||||
TypedArray margins = res.obtainTypedArray(a.getResourceId(attr, View.NO_ID));
|
||||
mLeftIndents = parseDimensionArray(margins);
|
||||
@@ -3049,6 +3056,33 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
return mBreakStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the hyphenation frequency. The default value for both TextView and EditText, which is set
|
||||
* from the theme, is {@link Layout#HYPHENATION_FREQUENCY_NORMAL}.
|
||||
*
|
||||
* @attr ref android.R.styleable#TextView_hyphenationFrequency
|
||||
* @see #getHyphenationFrequency()
|
||||
*/
|
||||
public void setHyphenationFrequency(@Layout.HyphenationFrequency int hyphenationFrequency) {
|
||||
mHyphenationFrequency = hyphenationFrequency;
|
||||
if (mLayout != null) {
|
||||
nullLayouts();
|
||||
requestLayout();
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the currently set hyphenation frequency.
|
||||
*
|
||||
* @attr ref android.R.styleable#TextView_hyphenationFrequency
|
||||
* @see #setHyphenationFrequency(int)
|
||||
*/
|
||||
@Layout.HyphenationFrequency
|
||||
public int getHyphenationFrequency() {
|
||||
return mHyphenationFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set indents. Arguments are arrays holding an indent amount, one per line, measured in
|
||||
* pixels. For lines past the last element in the array, the last element repeats.
|
||||
@@ -6637,7 +6671,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
.setTextDir(mTextDir)
|
||||
.setLineSpacing(mSpacingAdd, mSpacingMult)
|
||||
.setIncludePad(mIncludePad)
|
||||
.setBreakStrategy(mBreakStrategy);
|
||||
.setBreakStrategy(mBreakStrategy)
|
||||
.setHyphenationFrequency(mHyphenationFrequency);
|
||||
if (mLeftIndents != null || mRightIndents != null) {
|
||||
builder.setIndents(mLeftIndents, mRightIndents);
|
||||
}
|
||||
@@ -6678,7 +6713,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
Layout result = null;
|
||||
if (mText instanceof Spannable) {
|
||||
result = new DynamicLayout(mText, mTransformed, mTextPaint, wantWidth,
|
||||
alignment, mTextDir, mSpacingMult, mSpacingAdd, mIncludePad, mBreakStrategy,
|
||||
alignment, mTextDir, mSpacingMult, mSpacingAdd, mIncludePad,
|
||||
mBreakStrategy, mHyphenationFrequency,
|
||||
getKeyListener() == null ? effectiveEllipsize : null, ellipsisWidth);
|
||||
} else {
|
||||
if (boring == UNKNOWN_BORING) {
|
||||
@@ -6726,7 +6762,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
.setTextDir(mTextDir)
|
||||
.setLineSpacing(mSpacingAdd, mSpacingMult)
|
||||
.setIncludePad(mIncludePad)
|
||||
.setBreakStrategy(mBreakStrategy);
|
||||
.setBreakStrategy(mBreakStrategy)
|
||||
.setHyphenationFrequency(mHyphenationFrequency);
|
||||
if (mLeftIndents != null || mRightIndents != null) {
|
||||
builder.setIndents(mLeftIndents, mRightIndents);
|
||||
}
|
||||
|
||||
@@ -48,10 +48,11 @@ struct JLineBreaksID {
|
||||
static jclass gLineBreaks_class;
|
||||
static JLineBreaksID gLineBreaks_fieldID;
|
||||
|
||||
// set text and set a number of parameters for creating a layout (width, tabstops, strategy)
|
||||
// set text and set a number of parameters for creating a layout (width, tabstops, strategy,
|
||||
// hyphenFrequency)
|
||||
static void nSetupParagraph(JNIEnv* env, jclass, jlong nativePtr, jcharArray text, jint length,
|
||||
jfloat firstWidth, jint firstWidthLineLimit, jfloat restWidth,
|
||||
jintArray variableTabStops, jint defaultTabStop, jint strategy) {
|
||||
jintArray variableTabStops, jint defaultTabStop, jint strategy, jint hyphenFrequency) {
|
||||
LineBreaker* b = reinterpret_cast<LineBreaker*>(nativePtr);
|
||||
b->resize(length);
|
||||
env->GetCharArrayRegion(text, 0, length, b->buffer());
|
||||
@@ -64,6 +65,7 @@ static void nSetupParagraph(JNIEnv* env, jclass, jlong nativePtr, jcharArray tex
|
||||
b->setTabStops(stops.get(), stops.size(), defaultTabStop);
|
||||
}
|
||||
b->setStrategy(static_cast<BreakStrategy>(strategy));
|
||||
b->setHyphenationFrequency(static_cast<HyphenationFrequency>(hyphenFrequency));
|
||||
}
|
||||
|
||||
static void recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks,
|
||||
@@ -177,7 +179,7 @@ static JNINativeMethod gMethods[] = {
|
||||
{"nFinishBuilder", "(J)V", (void*) nFinishBuilder},
|
||||
{"nLoadHyphenator", "(Ljava/lang/String;)J", (void*) nLoadHyphenator},
|
||||
{"nSetLocale", "(JLjava/lang/String;J)V", (void*) nSetLocale},
|
||||
{"nSetupParagraph", "(J[CIFIF[III)V", (void*) nSetupParagraph},
|
||||
{"nSetupParagraph", "(J[CIFIF[IIII)V", (void*) nSetupParagraph},
|
||||
{"nSetIndents", "(J[I)V", (void*) nSetIndents},
|
||||
{"nAddStyleRun", "(JJJIIZ)F", (void*) nAddStyleRun},
|
||||
{"nAddMeasuredRun", "(JII[F)V", (void*) nAddMeasuredRun},
|
||||
|
||||
@@ -4369,6 +4369,17 @@
|
||||
<!-- Line breaking stratgegy balances line lengths. -->
|
||||
<enum name="balanced" value="2" />
|
||||
</attr>
|
||||
<!-- Frequency of automatic hyphenation. -->
|
||||
<attr name="hyphenationFrequency">
|
||||
<!-- No hyphenation. -->
|
||||
<enum name="none" value="0" />
|
||||
<!-- Less frequent hyphenation, useful for informal use cases, such
|
||||
as chat messages. -->
|
||||
<enum name="normal" value="1" />
|
||||
<!-- Standard amount of hyphenation, useful for running text and for
|
||||
screens with limited space for text. -->
|
||||
<enum name="full" value="2" />
|
||||
</attr>
|
||||
<!-- Array of indents, one dimension value per line, left side. -->
|
||||
<attr name="leftIndents" format="reference" />
|
||||
<!-- Array of indents, one dimension value per line, right side. -->
|
||||
|
||||
@@ -2688,4 +2688,5 @@
|
||||
<public type="attr" name="stylusButtonPressable" />
|
||||
<public type="attr" name="supportsLaunchVoiceAssistFromKeyguard" />
|
||||
<public type="attr" name="scrollIndicators" />
|
||||
<public type="attr" name="hyphenationFrequency" />
|
||||
</resources>
|
||||
|
||||
@@ -498,6 +498,7 @@ please see styles_device_defaults.xml.
|
||||
<item name="textEditSuggestionItemLayout">?attr/textEditSuggestionItemLayout</item>
|
||||
<item name="textCursorDrawable">?attr/textCursorDrawable</item>
|
||||
<item name="breakStrategy">high_quality</item>
|
||||
<item name="hyphenationFrequency">normal</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.CheckedTextView">
|
||||
@@ -529,6 +530,7 @@ please see styles_device_defaults.xml.
|
||||
<item name="textColor">?attr/editTextColor</item>
|
||||
<item name="gravity">center_vertical</item>
|
||||
<item name="breakStrategy">simple</item>
|
||||
<item name="hyphenationFrequency">normal</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.ExpandableListView" parent="Widget.ListView">
|
||||
|
||||
Reference in New Issue
Block a user