mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-29 20:26:39 +00:00
Use 12 columns grid
This commit is contained in:
parent
fde1bb7d6a
commit
8939dd2213
@ -14,12 +14,6 @@ import {
|
||||
} from "../panels/lovelace/common/compute-card-grid-size";
|
||||
import { HomeAssistant } from "../types";
|
||||
|
||||
declare global {
|
||||
interface HASSDomEvents {
|
||||
"grid-reset": undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement("ha-grid-size-picker")
|
||||
export class HaGridSizeEditor extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
@ -190,7 +184,12 @@ export class HaGridSizeEditor extends LitElement {
|
||||
|
||||
private _reset(ev) {
|
||||
ev.stopPropagation();
|
||||
fireEvent(this, "grid-reset");
|
||||
fireEvent(this, "value-changed", {
|
||||
value: {
|
||||
rows: undefined,
|
||||
columns: undefined,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private _sliderMoved(ev) {
|
||||
|
@ -1,11 +1,16 @@
|
||||
import type { Condition } from "../../../panels/lovelace/common/validate-condition";
|
||||
import type { LovelaceLayoutOptions } from "../../../panels/lovelace/types";
|
||||
import type {
|
||||
LovelaceGridOptions,
|
||||
LovelaceLayoutOptions,
|
||||
} from "../../../panels/lovelace/types";
|
||||
|
||||
export interface LovelaceCardConfig {
|
||||
index?: number;
|
||||
view_index?: number;
|
||||
view_layout?: any;
|
||||
/** @deprecated Use `grid_options` instead */
|
||||
layout_options?: LovelaceLayoutOptions;
|
||||
grid_options?: LovelaceGridOptions;
|
||||
type: string;
|
||||
[key: string]: any;
|
||||
visibility?: Condition[];
|
||||
|
@ -5,6 +5,7 @@ import { MediaQueriesListener } from "../../../common/dom/media_query";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace/config/card";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { migrateLayoutToGridOptions } from "../common/compute-card-grid-size";
|
||||
import { computeCardSize } from "../common/compute-card-size";
|
||||
import {
|
||||
attachConditionMediaQueriesListeners,
|
||||
@ -12,7 +13,7 @@ import {
|
||||
} from "../common/validate-condition";
|
||||
import { createCardElement } from "../create-element/create-card-element";
|
||||
import { createErrorCardConfig } from "../create-element/create-element-base";
|
||||
import type { LovelaceCard, LovelaceLayoutOptions } from "../types";
|
||||
import type { LovelaceCard, LovelaceGridOptions } from "../types";
|
||||
|
||||
declare global {
|
||||
interface HASSDomEvents {
|
||||
@ -67,20 +68,44 @@ export class HuiCard extends ReactiveElement {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public getLayoutOptions(): LovelaceLayoutOptions {
|
||||
const configOptions = this.config?.layout_options ?? {};
|
||||
if (this._element) {
|
||||
const cardOptions = this._element.getLayoutOptions?.() ?? {};
|
||||
return {
|
||||
...cardOptions,
|
||||
...configOptions,
|
||||
};
|
||||
}
|
||||
return configOptions;
|
||||
public getGridOptions(): LovelaceGridOptions {
|
||||
const elementOptions = this.getElementGridOptions();
|
||||
const configOptions = this.getConfigGridOptions();
|
||||
return {
|
||||
...elementOptions,
|
||||
...configOptions,
|
||||
};
|
||||
}
|
||||
|
||||
public getElementLayoutOptions(): LovelaceLayoutOptions {
|
||||
return this._element?.getLayoutOptions?.() ?? {};
|
||||
// options provided by the element
|
||||
public getElementGridOptions(): LovelaceGridOptions {
|
||||
if (!this._element) return {};
|
||||
|
||||
if (this._element.getGridOptions) {
|
||||
return this._element.getGridOptions();
|
||||
}
|
||||
if (this._element.getLayoutOptions) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(
|
||||
`This card (${this.config?.type}) is using "getLayoutOptions" and it is deprecated, contact the developer to suggest to use "getGridOptions" instead`
|
||||
);
|
||||
const config = migrateLayoutToGridOptions(
|
||||
this._element.getLayoutOptions()
|
||||
);
|
||||
return config;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
// options provided by the config
|
||||
public getConfigGridOptions(): LovelaceGridOptions {
|
||||
if (this.config?.grid_options) {
|
||||
return this.config.grid_options;
|
||||
}
|
||||
if (this.config?.layout_options) {
|
||||
return migrateLayoutToGridOptions(this.config.layout_options);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
private _updateElement(config: LovelaceCardConfig) {
|
||||
|
@ -1,8 +1,34 @@
|
||||
import { conditionalClamp } from "../../../common/number/clamp";
|
||||
import { LovelaceLayoutOptions } from "../types";
|
||||
import { LovelaceGridOptions, LovelaceLayoutOptions } from "../types";
|
||||
|
||||
const GRID_COLUMN_MULTIPLIER = 3;
|
||||
|
||||
const multiplyBy = <T extends number | string | undefined>(
|
||||
value: T,
|
||||
multiplier: number
|
||||
): T => (typeof value === "number" ? ((value * multiplier) as T) : value);
|
||||
|
||||
export const migrateLayoutToGridOptions = (
|
||||
options: LovelaceLayoutOptions
|
||||
): LovelaceGridOptions => {
|
||||
const gridOptions: LovelaceGridOptions = {
|
||||
columns: multiplyBy(options.grid_columns, GRID_COLUMN_MULTIPLIER),
|
||||
max_columns: multiplyBy(options.grid_max_columns, GRID_COLUMN_MULTIPLIER),
|
||||
min_columns: multiplyBy(options.grid_min_columns, GRID_COLUMN_MULTIPLIER),
|
||||
rows: options.grid_rows,
|
||||
max_rows: options.grid_max_rows,
|
||||
min_rows: options.grid_min_rows,
|
||||
};
|
||||
for (const [key, value] of Object.entries(gridOptions)) {
|
||||
if (value === undefined) {
|
||||
delete gridOptions[key];
|
||||
}
|
||||
}
|
||||
return gridOptions;
|
||||
};
|
||||
|
||||
export const DEFAULT_GRID_SIZE = {
|
||||
columns: 4,
|
||||
columns: 12,
|
||||
rows: "auto",
|
||||
} as CardGridSize;
|
||||
|
||||
@ -11,27 +37,23 @@ export type CardGridSize = {
|
||||
columns: number | "full";
|
||||
};
|
||||
|
||||
export const GRID_COLUMN_MULTIPLIER = 3;
|
||||
|
||||
export const computeCardGridSize = (
|
||||
options: LovelaceLayoutOptions
|
||||
options: LovelaceGridOptions
|
||||
): CardGridSize => {
|
||||
const rows = options.grid_rows ?? DEFAULT_GRID_SIZE.rows;
|
||||
const columns = options.grid_columns ?? DEFAULT_GRID_SIZE.columns;
|
||||
const minRows = options.grid_min_rows;
|
||||
const maxRows = options.grid_max_rows;
|
||||
const minColumns = options.grid_min_columns;
|
||||
const maxColumns = options.grid_max_columns;
|
||||
const precisionMode = options.grid_precision_mode;
|
||||
const rows = options.rows ?? DEFAULT_GRID_SIZE.rows;
|
||||
const columns = options.columns ?? DEFAULT_GRID_SIZE.columns;
|
||||
const minRows = options.min_rows;
|
||||
const maxRows = options.max_rows;
|
||||
const minColumns = options.min_columns;
|
||||
const maxColumns = options.max_columns;
|
||||
|
||||
const clampedRows =
|
||||
typeof rows === "string" ? rows : conditionalClamp(rows, minRows, maxRows);
|
||||
|
||||
const clampedColumns =
|
||||
typeof columns === "string" || precisionMode
|
||||
typeof columns === "string"
|
||||
? columns
|
||||
: conditionalClamp(columns, minColumns, maxColumns) *
|
||||
GRID_COLUMN_MULTIPLIER;
|
||||
: conditionalClamp(columns, minColumns, maxColumns);
|
||||
|
||||
return {
|
||||
rows: clampedRows,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import type { ActionDetail } from "@material/mwc-list";
|
||||
import { mdiCheck, mdiDotsVertical } from "@mdi/js";
|
||||
import { css, html, LitElement, nothing, PropertyValues } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
@ -17,7 +17,6 @@ import "../../../../components/ha-slider";
|
||||
import "../../../../components/ha-svg-icon";
|
||||
import "../../../../components/ha-switch";
|
||||
import "../../../../components/ha-yaml-editor";
|
||||
import type { HaYamlEditor } from "../../../../components/ha-yaml-editor";
|
||||
import { LovelaceCardConfig } from "../../../../data/lovelace/config/card";
|
||||
import { LovelaceSectionConfig } from "../../../../data/lovelace/config/section";
|
||||
import { haStyle } from "../../../../resources/styles";
|
||||
@ -26,9 +25,9 @@ import { HuiCard } from "../../cards/hui-card";
|
||||
import {
|
||||
CardGridSize,
|
||||
computeCardGridSize,
|
||||
GRID_COLUMN_MULTIPLIER,
|
||||
migrateLayoutToGridOptions,
|
||||
} from "../../common/compute-card-grid-size";
|
||||
import { LovelaceLayoutOptions } from "../../types";
|
||||
import { LovelaceGridOptions } from "../../types";
|
||||
|
||||
@customElement("hui-card-layout-editor")
|
||||
export class HuiCardLayoutEditor extends LitElement {
|
||||
@ -38,57 +37,48 @@ export class HuiCardLayoutEditor extends LitElement {
|
||||
|
||||
@property({ attribute: false }) public sectionConfig!: LovelaceSectionConfig;
|
||||
|
||||
@state() _defaultLayoutOptions?: LovelaceLayoutOptions;
|
||||
@state() _defaultGridOptions?: LovelaceGridOptions;
|
||||
|
||||
@state() public _yamlMode = false;
|
||||
|
||||
@state() public _uiAvailable = true;
|
||||
|
||||
@query("ha-yaml-editor") private _yamlEditor?: HaYamlEditor;
|
||||
|
||||
private _cardElement?: HuiCard;
|
||||
|
||||
private _mergedOptions = memoizeOne(
|
||||
(
|
||||
options?: LovelaceLayoutOptions,
|
||||
defaultOptions?: LovelaceLayoutOptions
|
||||
) => ({
|
||||
(options?: LovelaceGridOptions, defaultOptions?: LovelaceGridOptions) => ({
|
||||
...defaultOptions,
|
||||
...options,
|
||||
})
|
||||
);
|
||||
|
||||
private _computeCardGridSize = memoizeOne(
|
||||
(options: LovelaceLayoutOptions) => {
|
||||
const size = computeCardGridSize(options);
|
||||
if (!options.grid_precision_mode) {
|
||||
size.columns =
|
||||
typeof size.columns === "number"
|
||||
? Math.round(size.columns / GRID_COLUMN_MULTIPLIER)
|
||||
: size.columns;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
);
|
||||
private _computeCardGridSize = memoizeOne(computeCardGridSize);
|
||||
|
||||
private _isDefault = memoizeOne(
|
||||
(options?: LovelaceLayoutOptions) =>
|
||||
options?.grid_columns === undefined &&
|
||||
options?.grid_rows === undefined &&
|
||||
options?.grid_precision_mode === undefined
|
||||
(options?: LovelaceGridOptions) =>
|
||||
options?.columns === undefined && options?.rows === undefined
|
||||
);
|
||||
|
||||
private _configGridOptions = (config: LovelaceCardConfig) => {
|
||||
if (config.grid_options) {
|
||||
return config.grid_options;
|
||||
}
|
||||
if (config.layout_options) {
|
||||
return migrateLayoutToGridOptions(config.layout_options);
|
||||
}
|
||||
return {};
|
||||
};
|
||||
|
||||
render() {
|
||||
const configGridOptions = this._configGridOptions(this.config);
|
||||
const options = this._mergedOptions(
|
||||
this.config.layout_options,
|
||||
this._defaultLayoutOptions
|
||||
configGridOptions,
|
||||
this._defaultGridOptions
|
||||
);
|
||||
|
||||
const value = this._computeCardGridSize(options);
|
||||
|
||||
const totalColumns = (this.sectionConfig.column_span ?? 1) * 4;
|
||||
|
||||
const precisionMode = options.grid_precision_mode ?? false;
|
||||
const totalColumns = (this.sectionConfig.column_span ?? 1) * 12;
|
||||
|
||||
return html`
|
||||
<div class="header">
|
||||
@ -146,44 +136,25 @@ export class HuiCardLayoutEditor extends LitElement {
|
||||
? html`
|
||||
<ha-yaml-editor
|
||||
.hass=${this.hass}
|
||||
.defaultValue=${this.config.layout_options}
|
||||
.defaultValue=${configGridOptions}
|
||||
@value-changed=${this._valueChanged}
|
||||
></ha-yaml-editor>
|
||||
`
|
||||
: html`
|
||||
${precisionMode
|
||||
? html`
|
||||
<ha-grid-size-picker
|
||||
style=${styleMap({
|
||||
"max-width": `${totalColumns * 50 + 50}px`,
|
||||
})}
|
||||
.columns=${totalColumns * GRID_COLUMN_MULTIPLIER}
|
||||
.hass=${this.hass}
|
||||
.value=${value}
|
||||
.isDefault=${this._isDefault(this.config.layout_options)}
|
||||
@grid-reset=${this._reset}
|
||||
@value-changed=${this._gridSizeChanged}
|
||||
.rowMin=${options.grid_min_rows}
|
||||
.rowMax=${options.grid_max_rows}
|
||||
></ha-grid-size-picker>
|
||||
`
|
||||
: html`
|
||||
<ha-grid-size-picker
|
||||
style=${styleMap({
|
||||
"max-width": `${totalColumns * 50 + 50}px`,
|
||||
})}
|
||||
.columns=${totalColumns}
|
||||
.hass=${this.hass}
|
||||
.value=${value}
|
||||
.isDefault=${this._isDefault(this.config.layout_options)}
|
||||
@grid-reset=${this._reset}
|
||||
@value-changed=${this._gridSizeChanged}
|
||||
.rowMin=${options.grid_min_rows}
|
||||
.rowMax=${options.grid_max_rows}
|
||||
.columnMin=${options.grid_min_columns}
|
||||
.columnMax=${options.grid_max_columns}
|
||||
></ha-grid-size-picker>
|
||||
`}
|
||||
<ha-grid-size-picker
|
||||
style=${styleMap({
|
||||
"max-width": `${totalColumns * 20 + 50}px`,
|
||||
})}
|
||||
.columns=${totalColumns}
|
||||
.hass=${this.hass}
|
||||
.value=${value}
|
||||
.isDefault=${this._isDefault(configGridOptions)}
|
||||
@value-changed=${this._gridSizeChanged}
|
||||
.rowMin=${options.min_rows}
|
||||
.rowMax=${options.max_rows}
|
||||
.columnMin=${options.min_columns}
|
||||
.columnMax=${options.max_columns}
|
||||
></ha-grid-size-picker>
|
||||
<ha-settings-row>
|
||||
<span slot="heading" data-for="full-width">
|
||||
${this.hass.localize(
|
||||
@ -213,12 +184,7 @@ export class HuiCardLayoutEditor extends LitElement {
|
||||
"ui.panel.lovelace.editor.edit_card.layout.precision_mode_helper"
|
||||
)}
|
||||
</span>
|
||||
<ha-switch
|
||||
@change=${this._precisionModeChanged}
|
||||
.checked=${precisionMode}
|
||||
name="full-precision_mode"
|
||||
>
|
||||
</ha-switch>
|
||||
<ha-switch name="full-precision_mode"> </ha-switch>
|
||||
</ha-settings-row>
|
||||
`}
|
||||
`;
|
||||
@ -233,11 +199,10 @@ export class HuiCardLayoutEditor extends LitElement {
|
||||
this._cardElement.config = this.config;
|
||||
this._cardElement.addEventListener("card-updated", (ev: Event) => {
|
||||
ev.stopPropagation();
|
||||
this._defaultLayoutOptions =
|
||||
this._cardElement?.getElementLayoutOptions();
|
||||
this._defaultGridOptions = this._cardElement?.getElementGridOptions();
|
||||
});
|
||||
this._cardElement.load();
|
||||
this._defaultLayoutOptions = this._cardElement.getElementLayoutOptions();
|
||||
this._defaultGridOptions = this._cardElement.getElementGridOptions();
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(err);
|
||||
@ -267,47 +232,46 @@ export class HuiCardLayoutEditor extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private async _reset() {
|
||||
const newConfig = { ...this.config };
|
||||
delete newConfig.layout_options;
|
||||
this._yamlEditor?.setValue({});
|
||||
fireEvent(this, "value-changed", { value: newConfig });
|
||||
}
|
||||
|
||||
private _gridSizeChanged(ev: CustomEvent): void {
|
||||
ev.stopPropagation();
|
||||
const value = ev.detail.value as CardGridSize;
|
||||
|
||||
const newConfig: LovelaceCardConfig = {
|
||||
...this.config,
|
||||
layout_options: {
|
||||
...this.config.layout_options,
|
||||
grid_columns: value.columns,
|
||||
grid_rows: value.rows,
|
||||
grid_options: {
|
||||
...this.config.grid_options,
|
||||
columns: value.columns,
|
||||
rows: value.rows,
|
||||
},
|
||||
};
|
||||
|
||||
if (newConfig.layout_options!.grid_columns === undefined) {
|
||||
delete newConfig.layout_options!.grid_columns;
|
||||
}
|
||||
if (newConfig.layout_options!.grid_rows === undefined) {
|
||||
delete newConfig.layout_options!.grid_rows;
|
||||
}
|
||||
if (Object.keys(newConfig.layout_options!).length === 0) {
|
||||
delete newConfig.layout_options;
|
||||
}
|
||||
this._updateValue(newConfig);
|
||||
}
|
||||
|
||||
fireEvent(this, "value-changed", { value: newConfig });
|
||||
private _updateValue(value: LovelaceCardConfig): void {
|
||||
if (value.grid_options!.columns === undefined) {
|
||||
delete value.grid_options!.columns;
|
||||
}
|
||||
if (value.grid_options!.rows === undefined) {
|
||||
delete value.grid_options!.rows;
|
||||
}
|
||||
if (Object.keys(value.grid_options!).length === 0) {
|
||||
delete value.grid_options;
|
||||
}
|
||||
if (value.layout_options) {
|
||||
delete value.layout_options;
|
||||
}
|
||||
fireEvent(this, "value-changed", { value });
|
||||
}
|
||||
|
||||
private _valueChanged(ev: CustomEvent): void {
|
||||
ev.stopPropagation();
|
||||
const options = ev.detail.value as LovelaceLayoutOptions;
|
||||
const options = ev.detail.value as LovelaceGridOptions;
|
||||
const newConfig: LovelaceCardConfig = {
|
||||
...this.config,
|
||||
layout_options: options,
|
||||
grid_options: options,
|
||||
};
|
||||
fireEvent(this, "value-changed", { value: newConfig });
|
||||
this._updateValue(newConfig);
|
||||
}
|
||||
|
||||
private _fullWidthChanged(ev): void {
|
||||
@ -315,42 +279,12 @@ export class HuiCardLayoutEditor extends LitElement {
|
||||
const value = ev.target.checked;
|
||||
const newConfig: LovelaceCardConfig = {
|
||||
...this.config,
|
||||
layout_options: {
|
||||
...this.config.layout_options,
|
||||
grid_columns: value
|
||||
? "full"
|
||||
: (this._defaultLayoutOptions?.grid_min_columns ?? 1),
|
||||
grid_options: {
|
||||
...this.config.grid_options,
|
||||
columns: value ? "full" : (this._defaultGridOptions?.min_columns ?? 1),
|
||||
},
|
||||
};
|
||||
fireEvent(this, "value-changed", { value: newConfig });
|
||||
}
|
||||
|
||||
private _precisionModeChanged(ev): void {
|
||||
ev.stopPropagation();
|
||||
const value = ev.target.checked;
|
||||
|
||||
const preciseMode = value;
|
||||
const gridColumns = this.config.layout_options?.grid_columns;
|
||||
|
||||
const newGridColumns =
|
||||
typeof gridColumns === "number"
|
||||
? preciseMode
|
||||
? gridColumns * GRID_COLUMN_MULTIPLIER
|
||||
: Math.round(gridColumns / GRID_COLUMN_MULTIPLIER)
|
||||
: gridColumns;
|
||||
|
||||
const newConfig: LovelaceCardConfig = {
|
||||
...this.config,
|
||||
layout_options: {
|
||||
...this.config.layout_options,
|
||||
grid_columns: newGridColumns,
|
||||
grid_precision_mode: preciseMode || undefined,
|
||||
},
|
||||
};
|
||||
if (Object.keys(newConfig.layout_options!).length === 0) {
|
||||
delete newConfig.layout_options;
|
||||
}
|
||||
fireEvent(this, "value-changed", { value: newConfig });
|
||||
this._updateValue(newConfig);
|
||||
}
|
||||
|
||||
static styles = [
|
||||
|
@ -4,5 +4,6 @@ export const baseLovelaceCardConfig = object({
|
||||
type: string(),
|
||||
view_layout: any(),
|
||||
layout_options: any(),
|
||||
grid_options: any(),
|
||||
visibility: any(),
|
||||
});
|
||||
|
@ -84,9 +84,9 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
||||
(_cardConfig, idx) => {
|
||||
const card = this.cards![idx];
|
||||
card.layout = "grid";
|
||||
const layoutOptions = card.getLayoutOptions();
|
||||
const gridOptions = card.getGridOptions();
|
||||
|
||||
const { rows, columns } = computeCardGridSize(layoutOptions);
|
||||
const { rows, columns } = computeCardGridSize(gridOptions);
|
||||
|
||||
return html`
|
||||
<div
|
||||
@ -96,7 +96,7 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
||||
"--row-size": typeof rows === "number" ? rows : undefined,
|
||||
})}
|
||||
class="card ${classMap({
|
||||
"fit-rows": typeof layoutOptions?.grid_rows === "number",
|
||||
"fit-rows": typeof rows === "number",
|
||||
"full-width": columns === "full",
|
||||
})}"
|
||||
>
|
||||
|
@ -49,7 +49,15 @@ export type LovelaceLayoutOptions = {
|
||||
grid_min_columns?: number;
|
||||
grid_min_rows?: number;
|
||||
grid_max_rows?: number;
|
||||
grid_precision_mode?: boolean;
|
||||
};
|
||||
|
||||
export type LovelaceGridOptions = {
|
||||
columns?: number | "full";
|
||||
rows?: number | "auto";
|
||||
max_columns?: number;
|
||||
min_columns?: number;
|
||||
min_rows?: number;
|
||||
max_rows?: number;
|
||||
};
|
||||
|
||||
export interface LovelaceCard extends HTMLElement {
|
||||
@ -57,7 +65,9 @@ export interface LovelaceCard extends HTMLElement {
|
||||
preview?: boolean;
|
||||
layout?: string;
|
||||
getCardSize(): number | Promise<number>;
|
||||
/** @deprecated Use `getGridOptions` instead */
|
||||
getLayoutOptions?(): LovelaceLayoutOptions;
|
||||
getGridOptions?(): LovelaceGridOptions;
|
||||
setConfig(config: LovelaceCardConfig): void;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user