mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-16 11:42:04 +08:00
Merge pull request #1128 from NativeScript/time-picker-min-max
time picker minHour, maxHour, minMinute and maxMinute properties added
This commit is contained in:
@ -67,6 +67,24 @@ export function test_WhenCreated_HourIsUndefined() {
|
||||
});
|
||||
}
|
||||
|
||||
export function test_WhenCreated_MinHourIs1() {
|
||||
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
|
||||
var timePicker = <timePickerModule.TimePicker>views[0];
|
||||
var actualValue = timePicker.minHour;
|
||||
var expectedValue = 1;
|
||||
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
|
||||
});
|
||||
}
|
||||
|
||||
export function test_WhenCreated_MaxHourIs23() {
|
||||
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
|
||||
var timePicker = <timePickerModule.TimePicker>views[0];
|
||||
var actualValue = timePicker.maxHour;
|
||||
var expectedValue = 23;
|
||||
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
|
||||
});
|
||||
}
|
||||
|
||||
export function test_WhenCreated_MinuteIsUndefined() {
|
||||
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
|
||||
var timePicker = <timePickerModule.TimePicker>views[0];
|
||||
@ -76,6 +94,108 @@ export function test_WhenCreated_MinuteIsUndefined() {
|
||||
});
|
||||
}
|
||||
|
||||
export function test_WhenCreated_MinMinuteIs0() {
|
||||
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
|
||||
var timePicker = <timePickerModule.TimePicker>views[0];
|
||||
var actualValue = timePicker.minMinute;
|
||||
var expectedValue = 0;
|
||||
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
|
||||
});
|
||||
}
|
||||
|
||||
export function test_WhenCreated_MaxMinuteIs59() {
|
||||
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
|
||||
var timePicker = <timePickerModule.TimePicker>views[0];
|
||||
var actualValue = timePicker.maxMinute;
|
||||
var expectedValue = 59;
|
||||
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
|
||||
});
|
||||
}
|
||||
|
||||
export function testHourThrowExceptionWhenLessThanMinHour() {
|
||||
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
|
||||
var timePicker = <timePickerModule.TimePicker>views[0];
|
||||
timePicker.minHour = 13;
|
||||
TKUnit.assertThrows(function () {
|
||||
timePicker.hour = timePicker.minHour - 1;
|
||||
}, "Setting hour property to a value less than minHour property value should throw.");
|
||||
});
|
||||
}
|
||||
|
||||
export function testHourThrowExceptionWhenGreaterThanMaxHour() {
|
||||
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
|
||||
var timePicker = <timePickerModule.TimePicker>views[0];
|
||||
timePicker.maxHour = 13;
|
||||
TKUnit.assertThrows(function () {
|
||||
timePicker.hour = timePicker.maxHour + 1;;
|
||||
}, "Setting hour property to a value greater than maxHour property value should throw.");
|
||||
});
|
||||
}
|
||||
|
||||
export function testMinuteThrowExceptionWhenLessThanMinMinute() {
|
||||
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
|
||||
var timePicker = <timePickerModule.TimePicker>views[0];
|
||||
timePicker.minMinute = 13;
|
||||
TKUnit.assertThrows(function () {
|
||||
timePicker.minute = timePicker.minMinute - 1;
|
||||
}, "Setting hour property to a value less than minHour property value should throw.");
|
||||
});
|
||||
}
|
||||
|
||||
export function testMinuteThrowExceptionWhenGreaterThanMaxMinute() {
|
||||
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
|
||||
var timePicker = <timePickerModule.TimePicker>views[0];
|
||||
timePicker.maxMinute = 13;
|
||||
TKUnit.assertThrows(function () {
|
||||
timePicker.minute = timePicker.maxMinute + 1;;
|
||||
}, "Setting hour property to a value greater than maxHour property value should throw.");
|
||||
});
|
||||
}
|
||||
|
||||
export function testHourFromNativeEqualToMinHourWhenLessThanMinHour() {
|
||||
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
|
||||
var timePicker = <timePickerModule.TimePicker>views[0];
|
||||
var expectedValue = 13;
|
||||
timePicker.minHour = expectedValue;
|
||||
timePickerTestsNative.setNativeHour(timePicker, expectedValue - 1);
|
||||
var actualValue = timePickerTestsNative.getNativeHour(timePicker);
|
||||
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
|
||||
});
|
||||
}
|
||||
|
||||
export function testHourFromNativeEqualToMaxHourWhenGreaterThanMaxHour() {
|
||||
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
|
||||
var timePicker = <timePickerModule.TimePicker>views[0];
|
||||
var expectedValue = 13;
|
||||
timePicker.maxHour = expectedValue;
|
||||
timePickerTestsNative.setNativeHour(timePicker, expectedValue + 1);
|
||||
var actualValue = timePickerTestsNative.getNativeHour(timePicker);
|
||||
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
|
||||
});
|
||||
}
|
||||
|
||||
export function testMinuteFromNativeEqualToMinMinuteWhenLessThanMinMinute() {
|
||||
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
|
||||
var timePicker = <timePickerModule.TimePicker>views[0];
|
||||
var expectedValue = 13;
|
||||
timePicker.minMinute = expectedValue;
|
||||
timePickerTestsNative.setNativeMinute(timePicker, expectedValue - 1);
|
||||
var actualValue = timePickerTestsNative.getNativeMinute(timePicker);
|
||||
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
|
||||
});
|
||||
}
|
||||
|
||||
export function testMinuteFromNativeEqualToMaxMinuteWhenGreaterThanMaxMinute() {
|
||||
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
|
||||
var timePicker = <timePickerModule.TimePicker>views[0];
|
||||
var expectedValue = 13;
|
||||
timePicker.maxMinute = expectedValue;
|
||||
timePickerTestsNative.setNativeMinute(timePicker, expectedValue + 1);
|
||||
var actualValue = timePickerTestsNative.getNativeMinute(timePicker);
|
||||
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
|
||||
});
|
||||
}
|
||||
|
||||
export function testHourFromLocalToNative() {
|
||||
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
|
||||
var timePicker = <timePickerModule.TimePicker>views[0];
|
||||
|
@ -2,10 +2,62 @@
|
||||
import dependencyObservable = require("ui/core/dependency-observable");
|
||||
import proxy = require("ui/core/proxy");
|
||||
import view = require("ui/core/view");
|
||||
import types = require("utils/types");
|
||||
|
||||
function isHourValid(value: number): boolean {
|
||||
return types.isNumber(value) && value >= 1 && value <= 23;
|
||||
}
|
||||
|
||||
function isMinuteValid(value: number): boolean {
|
||||
return types.isNumber(value) && value >= 0 && value <= 59;
|
||||
}
|
||||
|
||||
export function getValidHour(hour: number, minHour: number, maxHour: number): number {
|
||||
let hourValue = hour;
|
||||
|
||||
if (minHour && hour < minHour) {
|
||||
hourValue = minHour
|
||||
}
|
||||
|
||||
if (maxHour && hour > maxHour) {
|
||||
hourValue = maxHour
|
||||
}
|
||||
|
||||
return hourValue;
|
||||
}
|
||||
|
||||
export function getValidMinute(minute: number, minMinute: number, maxMinute: number): number {
|
||||
let minuteValue = minute;
|
||||
|
||||
if (minMinute && minute < minMinute) {
|
||||
minuteValue = minMinute
|
||||
}
|
||||
|
||||
if (maxMinute && minute > maxMinute) {
|
||||
minuteValue = maxMinute
|
||||
}
|
||||
|
||||
return minuteValue;
|
||||
}
|
||||
|
||||
export class TimePicker extends view.View implements definition.TimePicker {
|
||||
public static hourProperty = new dependencyObservable.Property("hour", "TimePicker", new proxy.PropertyMetadata(undefined));
|
||||
public static minuteProperty = new dependencyObservable.Property("minute", "TimePicker", new proxy.PropertyMetadata(undefined));
|
||||
public static hourProperty = new dependencyObservable.Property("hour", "TimePicker",
|
||||
new proxy.PropertyMetadata(undefined, dependencyObservable.PropertyMetadataSettings.None, undefined, isHourValid));
|
||||
|
||||
public static minHourProperty = new dependencyObservable.Property("minHour", "TimePicker",
|
||||
new proxy.PropertyMetadata(1, dependencyObservable.PropertyMetadataSettings.None, undefined, isHourValid));
|
||||
|
||||
public static maxHourProperty = new dependencyObservable.Property("maxHour", "TimePicker",
|
||||
new proxy.PropertyMetadata(23, dependencyObservable.PropertyMetadataSettings.None, undefined, isHourValid));
|
||||
|
||||
public static minuteProperty = new dependencyObservable.Property("minute", "TimePicker",
|
||||
new proxy.PropertyMetadata(undefined, dependencyObservable.PropertyMetadataSettings.None, undefined, isMinuteValid));
|
||||
|
||||
public static minMinuteProperty = new dependencyObservable.Property("minMinute", "TimePicker",
|
||||
new proxy.PropertyMetadata(0, dependencyObservable.PropertyMetadataSettings.None, undefined, isMinuteValid));
|
||||
|
||||
public static maxMinuteProperty = new dependencyObservable.Property("maxMinute", "TimePicker",
|
||||
new proxy.PropertyMetadata(59, dependencyObservable.PropertyMetadataSettings.None, undefined, isMinuteValid));
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@ -24,4 +76,32 @@ export class TimePicker extends view.View implements definition.TimePicker {
|
||||
set minute(value: number) {
|
||||
this._setValue(TimePicker.minuteProperty, value);
|
||||
}
|
||||
|
||||
get maxHour(): number {
|
||||
return this._getValue(TimePicker.maxHourProperty);
|
||||
}
|
||||
set maxHour(value: number) {
|
||||
this._setValue(TimePicker.maxHourProperty, value);
|
||||
}
|
||||
|
||||
get maxMinute(): number {
|
||||
return this._getValue(TimePicker.maxMinuteProperty);
|
||||
}
|
||||
set maxMinute(value: number) {
|
||||
this._setValue(TimePicker.maxMinuteProperty, value);
|
||||
}
|
||||
|
||||
get minHour(): number {
|
||||
return this._getValue(TimePicker.minHourProperty);
|
||||
}
|
||||
set minHour(value: number) {
|
||||
this._setValue(TimePicker.minHourProperty, value);
|
||||
}
|
||||
|
||||
get minMinute(): number {
|
||||
return this._getValue(TimePicker.minMinuteProperty);
|
||||
}
|
||||
set minMinute(value: number) {
|
||||
this._setValue(TimePicker.minMinuteProperty, value);
|
||||
}
|
||||
}
|
@ -2,27 +2,41 @@
|
||||
import dependencyObservable = require("ui/core/dependency-observable");
|
||||
import proxy = require("ui/core/proxy");
|
||||
import utils = require("utils/utils")
|
||||
import types = require("utils/types")
|
||||
|
||||
function onHourPropertyChanged(data: dependencyObservable.PropertyChangeData) {
|
||||
var picker = <TimePicker>data.object;
|
||||
picker._setNativeHourSilently(data.newValue);
|
||||
|
||||
var validValue = common.getValidHour(data.newValue, picker.minHour, picker.maxHour);
|
||||
if (validValue === data.newValue) {
|
||||
picker._setNativeValueSilently(data.newValue, picker.minute);
|
||||
} else {
|
||||
throw new Error(`Hour property value (${data.newValue}) is not valid. Min value: (${picker.minHour} ), max value: (${picker.maxHour} ).`);
|
||||
}
|
||||
}
|
||||
|
||||
(<proxy.PropertyMetadata>common.TimePicker.hourProperty.metadata).onSetNativeValue = onHourPropertyChanged;
|
||||
|
||||
function onMinutePropertyChanged(data: dependencyObservable.PropertyChangeData) {
|
||||
var picker = <TimePicker>data.object;
|
||||
picker._setNativeMinuteSilently(data.newValue);
|
||||
|
||||
var validValue = common.getValidMinute(data.newValue, picker.minMinute, picker.maxMinute);
|
||||
if (validValue === data.newValue) {
|
||||
picker._setNativeValueSilently(picker.hour, data.newValue);
|
||||
} else {
|
||||
throw new Error(`Minute property value (${data.newValue}) is not valid. Min value: (${picker.minMinute} ), max value: (${picker.maxMinute} ).`);
|
||||
}
|
||||
}
|
||||
|
||||
(<proxy.PropertyMetadata>common.TimePicker.minuteProperty.metadata).onSetNativeValue = onMinutePropertyChanged;
|
||||
|
||||
global.moduleMerge(common, exports);
|
||||
|
||||
var SDK = android.os.Build.VERSION.SDK_INT;
|
||||
|
||||
export class TimePicker extends common.TimePicker {
|
||||
private _android: android.widget.TimePicker;
|
||||
private _listener: android.widget.TimePicker.OnTimeChangedListener;
|
||||
private _isSettingTime: boolean = false;
|
||||
|
||||
get android(): android.widget.TimePicker {
|
||||
return this._android;
|
||||
@ -35,51 +49,51 @@ export class TimePicker extends common.TimePicker {
|
||||
|
||||
this._listener = new android.widget.TimePicker.OnTimeChangedListener(
|
||||
<utils.Owned & android.widget.TimePicker.IOnTimeChangedListener>{
|
||||
get owner() {
|
||||
return that.get();
|
||||
},
|
||||
get owner() {
|
||||
return that.get();
|
||||
},
|
||||
|
||||
onTimeChanged: function (picker: android.widget.TimePicker, hour: number, minute: number) {
|
||||
if (this.owner && !this.owner._isSettingTime) {
|
||||
onTimeChanged: function (picker: android.widget.TimePicker, hour: number, minute: number) {
|
||||
if (this.owner) {
|
||||
|
||||
if (hour !== this.owner.hour) {
|
||||
this.owner._onPropertyChangedFromNative(common.TimePicker.hourProperty, hour);
|
||||
}
|
||||
this.owner._setNativeValueSilently(hour, minute);
|
||||
|
||||
if (minute !== this.owner.minute) {
|
||||
this.owner._onPropertyChangedFromNative(common.TimePicker.minuteProperty, minute);
|
||||
if (hour !== this.owner.hour) {
|
||||
this.owner._onPropertyChangedFromNative(common.TimePicker.hourProperty, hour);
|
||||
}
|
||||
|
||||
if (minute !== this.owner.minute) {
|
||||
this.owner._onPropertyChangedFromNative(common.TimePicker.minuteProperty, minute);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
this._android.setOnTimeChangedListener(this._listener);
|
||||
}
|
||||
|
||||
public _setNativeHourSilently(newValue: number) {
|
||||
if (!this.android) {
|
||||
return;
|
||||
}
|
||||
public _setNativeValueSilently(hour: number, minute: number) {
|
||||
if (this.android) {
|
||||
this.android.setOnTimeChangedListener(null);
|
||||
|
||||
this._isSettingTime = true;
|
||||
try {
|
||||
this.android.setCurrentHour(new java.lang.Integer(newValue));
|
||||
}
|
||||
finally {
|
||||
this._isSettingTime = false;
|
||||
}
|
||||
}
|
||||
if (types.isNumber(hour)) {
|
||||
var h = new java.lang.Integer(common.getValidHour(hour, this.minHour, this.maxHour));
|
||||
if (SDK >= 23) {
|
||||
(<any>this.android).setHour(h);
|
||||
} else {
|
||||
this.android.setCurrentHour(h);
|
||||
}
|
||||
}
|
||||
|
||||
public _setNativeMinuteSilently(newValue: number) {
|
||||
if (!this.android) {
|
||||
return;
|
||||
}
|
||||
if (types.isNumber(minute)) {
|
||||
var m = new java.lang.Integer(common.getValidMinute(minute, this.minMinute, this.maxMinute));
|
||||
if (SDK >= 23) {
|
||||
(<any>this.android).setMinute(m);
|
||||
} else {
|
||||
this.android.setCurrentMinute(m);
|
||||
}
|
||||
}
|
||||
|
||||
this._isSettingTime = true;
|
||||
try {
|
||||
this.android.setCurrentMinute(new java.lang.Integer(newValue));
|
||||
}
|
||||
finally {
|
||||
this._isSettingTime = false;
|
||||
this.android.setOnTimeChangedListener(this._listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
20
ui/time-picker/time-picker.d.ts
vendored
20
ui/time-picker/time-picker.d.ts
vendored
@ -33,5 +33,25 @@ declare module "ui/time-picker" {
|
||||
* Gets or sets the time minute.
|
||||
*/
|
||||
minute: number;
|
||||
|
||||
/**
|
||||
* Gets or sets the max time hour.
|
||||
*/
|
||||
maxHour: number;
|
||||
|
||||
/**
|
||||
* Gets or sets the max time minute.
|
||||
*/
|
||||
maxMinute: number;
|
||||
|
||||
/**
|
||||
* Gets or sets the min time hour.
|
||||
*/
|
||||
minHour: number;
|
||||
|
||||
/**
|
||||
* Gets or sets the min time minute.
|
||||
*/
|
||||
minMinute: number;
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +1,42 @@
|
||||
import common = require("./time-picker-common");
|
||||
import dependencyObservable = require("ui/core/dependency-observable");
|
||||
import proxy = require("ui/core/proxy");
|
||||
import types = require("utils/types");
|
||||
|
||||
function getDate(date: NSDate, hour?: number, minute?: number): NSDate {
|
||||
var comps = NSCalendar.currentCalendar().componentsFromDate(NSCalendarUnit.NSCalendarUnitHour | NSCalendarUnit.NSCalendarUnitMinute, date);
|
||||
|
||||
if (hour) {
|
||||
comps.hour = hour;
|
||||
}
|
||||
|
||||
if (minute) {
|
||||
comps.minute = minute;
|
||||
}
|
||||
|
||||
return NSCalendar.currentCalendar().dateFromComponents(comps);
|
||||
}
|
||||
|
||||
function onHourPropertyChanged(data: dependencyObservable.PropertyChangeData) {
|
||||
var picker = <TimePicker>data.object;
|
||||
|
||||
if (picker.ios) {
|
||||
var comps = NSCalendar.currentCalendar().componentsFromDate(NSCalendarUnit.NSCalendarUnitHour | NSCalendarUnit.NSCalendarUnitMinute, picker.ios.date);
|
||||
comps.hour = data.newValue;
|
||||
picker.ios.setDateAnimated(NSCalendar.currentCalendar().dateFromComponents(comps), false);
|
||||
var validValue = common.getValidHour(data.newValue, picker.minHour, picker.maxHour);
|
||||
if (validValue === data.newValue) {
|
||||
picker.ios.setDateAnimated(getDate(picker.ios.date, data.newValue, picker.minute), false);
|
||||
} else {
|
||||
throw new Error(`Hour property value (${data.newValue}) is not valid. Min value: (${picker.minHour} ), max value: (${picker.maxHour} ).`);
|
||||
}
|
||||
}
|
||||
|
||||
(<proxy.PropertyMetadata>common.TimePicker.hourProperty.metadata).onSetNativeValue = onHourPropertyChanged;
|
||||
|
||||
function onMinutePropertyChanged(data: dependencyObservable.PropertyChangeData) {
|
||||
var picker = <TimePicker>data.object;
|
||||
|
||||
if (picker.ios) {
|
||||
var comps = NSCalendar.currentCalendar().componentsFromDate(NSCalendarUnit.NSCalendarUnitHour | NSCalendarUnit.NSCalendarUnitMinute, picker.ios.date);
|
||||
comps.minute = data.newValue;
|
||||
picker.ios.setDateAnimated(NSCalendar.currentCalendar().dateFromComponents(comps), false);
|
||||
var validValue = common.getValidMinute(data.newValue, picker.minMinute, picker.maxMinute);
|
||||
if (validValue === data.newValue) {
|
||||
picker.ios.setDateAnimated(getDate(picker.ios.date, picker.hour, data.newValue), false);
|
||||
} else {
|
||||
throw new Error(`Minute property value (${data.newValue}) is not valid. Min value: (${picker.minMinute} ), max value: (${picker.maxMinute} ).`);
|
||||
}
|
||||
}
|
||||
|
||||
(<proxy.PropertyMetadata>common.TimePicker.minuteProperty.metadata).onSetNativeValue = onMinutePropertyChanged;
|
||||
|
||||
global.moduleMerge(common, exports);
|
||||
@ -45,6 +58,20 @@ export class TimePicker extends common.TimePicker {
|
||||
get ios(): UIDatePicker {
|
||||
return this._ios;
|
||||
}
|
||||
|
||||
public _setNativeValueSilently(hour: number, minute: number) {
|
||||
if (this.ios) {
|
||||
this.ios.removeTargetActionForControlEvents(this._changeHandler, "valueChanged", UIControlEvents.UIControlEventValueChanged)
|
||||
|
||||
if (types.isNumber(hour) && types.isNumber(minute)) {
|
||||
this.ios.setDateAnimated(getDate(this.ios.date,
|
||||
common.getValidHour(hour, this.minHour, this.maxHour),
|
||||
common.getValidMinute(minute, this.minMinute, this.maxMinute)), false);
|
||||
}
|
||||
|
||||
this.ios.addTargetActionForControlEvents(this._changeHandler, "valueChanged", UIControlEvents.UIControlEventValueChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class UITimePickerChangeHandlerImpl extends NSObject {
|
||||
@ -64,6 +91,8 @@ class UITimePickerChangeHandlerImpl extends NSObject {
|
||||
}
|
||||
|
||||
var comps = NSCalendar.currentCalendar().componentsFromDate(NSCalendarUnit.NSCalendarUnitHour | NSCalendarUnit.NSCalendarUnitMinute, sender.date);
|
||||
owner._setNativeValueSilently(comps.hour, comps.minute);
|
||||
comps = NSCalendar.currentCalendar().componentsFromDate(NSCalendarUnit.NSCalendarUnitHour | NSCalendarUnit.NSCalendarUnitMinute, sender.date);
|
||||
|
||||
if (comps.hour !== owner.hour) {
|
||||
owner._onPropertyChangedFromNative(common.TimePicker.hourProperty, comps.hour);
|
||||
@ -76,5 +105,5 @@ class UITimePickerChangeHandlerImpl extends NSObject {
|
||||
|
||||
public static ObjCExposedMethods = {
|
||||
'valueChanged': { returns: interop.types.void, params: [UIDatePicker] }
|
||||
};
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user