[Enhancement] improve `passive` and `win` filters by applying new Tri-state toggle dropdown in the starter select UI (#3252)
* split unlocks filter into shiny and passive * update tri state dropdown. apply it to passive and win dropdown
This commit is contained in:
parent
cce68f6ef7
commit
0ad4986fa5
|
@ -6,12 +6,15 @@ import i18next from "i18next";
|
|||
|
||||
export enum DropDownState {
|
||||
ON = 0,
|
||||
OFF
|
||||
OFF = 1,
|
||||
INCLUDE = 2,
|
||||
EXCLUDE = 3,
|
||||
}
|
||||
|
||||
export enum DropDownType {
|
||||
MULTI = 0,
|
||||
SINGLE
|
||||
SINGLE = 1,
|
||||
TRI = 2
|
||||
}
|
||||
|
||||
export enum SortDirection {
|
||||
|
@ -26,11 +29,30 @@ export class DropDownOption extends Phaser.GameObjects.Container {
|
|||
public sprite?: Phaser.GameObjects.Sprite;
|
||||
public val: any;
|
||||
public dir: SortDirection = SortDirection.ASC;
|
||||
public offStateLabel: string; // label for OFF state in TRI dropdown
|
||||
public includeStateLabel: string; // label for INCLUDE state in TRI dropdown
|
||||
public excludeStateLabel: string; // label for EXCLUDE state in TRI dropdown
|
||||
private onColor = 0x55ff55;
|
||||
private offColor = 0x272727;
|
||||
private includeColor = 0x55ff55;
|
||||
private excludeColor = 0xff5555;
|
||||
|
||||
constructor(scene: SceneBase, val: any, text: string, sprite?: Phaser.GameObjects.Sprite, state: DropDownState = DropDownState.ON) {
|
||||
|
||||
constructor(scene: SceneBase, val: any, text: string | string[], sprite?: Phaser.GameObjects.Sprite, state: DropDownState = DropDownState.ON) {
|
||||
super(scene);
|
||||
this.val = val;
|
||||
this.state = state;
|
||||
if (text) {
|
||||
if (Array.isArray(text)) {
|
||||
this.offStateLabel = text[0];
|
||||
this.includeStateLabel = text[1];
|
||||
this.excludeStateLabel = text[2];
|
||||
text = text[0];
|
||||
} else {
|
||||
this.offStateLabel = undefined;
|
||||
this.includeStateLabel = undefined;
|
||||
this.excludeStateLabel = undefined;
|
||||
}
|
||||
this.text = addTextObject(scene, 0, 0, text, TextStyle.TOOLTIP_CONTENT);
|
||||
this.text.setOrigin(0, 0.5);
|
||||
this.add(this.text);
|
||||
|
@ -40,11 +62,10 @@ export class DropDownOption extends Phaser.GameObjects.Container {
|
|||
this.sprite = sprite.setOrigin(0, 0.5);
|
||||
this.add(this.sprite);
|
||||
}
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public setupToggle(type: DropDownType): void {
|
||||
if (type === DropDownType.MULTI) {
|
||||
if (type === DropDownType.MULTI || type === DropDownType.TRI) {
|
||||
this.toggle = this.scene.add.sprite(0, 0, "candy");
|
||||
this.toggle.setScale(0.3);
|
||||
this.toggle.setOrigin(0, 0.5);
|
||||
|
@ -57,18 +78,54 @@ export class DropDownOption extends Phaser.GameObjects.Container {
|
|||
this.add(this.toggle);
|
||||
}
|
||||
|
||||
public setOptionState(state: DropDownState): DropDownState {
|
||||
this.state = state % 2;
|
||||
if (this.state === DropDownState.OFF) {
|
||||
this.toggle.setTint(0x272727);
|
||||
} else {
|
||||
this.toggle.setTint(0x55ff55);
|
||||
public setOptionState(type: DropDownType, state: DropDownState): DropDownState {
|
||||
this.state = state;
|
||||
// if type is MULTI or SINGLE, set the color of the toggle based on the state
|
||||
if (type === DropDownType.MULTI || type === DropDownType.SINGLE) {
|
||||
if (this.state === DropDownState.OFF) {
|
||||
this.toggle.setTint(this.offColor);
|
||||
} else if (this.state === DropDownState.ON) {
|
||||
this.toggle.setTint(this.onColor);
|
||||
}
|
||||
} else if (type === DropDownType.TRI) {
|
||||
if (this.state === DropDownState.OFF) {
|
||||
this.text.setText(this.offStateLabel);
|
||||
this.toggle.setTint(this.offColor);
|
||||
} else if (this.state === DropDownState.INCLUDE) {
|
||||
this.text.setText(this.includeStateLabel);
|
||||
this.toggle.setTint(this.includeColor);
|
||||
} else if (this.state === DropDownState.EXCLUDE) {
|
||||
this.text.setText(this.excludeStateLabel);
|
||||
this.toggle.setTint(this.excludeColor);
|
||||
}
|
||||
}
|
||||
return this.state;
|
||||
}
|
||||
|
||||
public toggleOptionState(): DropDownState {
|
||||
return this.setOptionState(this.state + 1);
|
||||
public toggleOptionState(type: DropDownType): DropDownState {
|
||||
if (type === DropDownType.TRI) {
|
||||
switch (this.state) {
|
||||
case DropDownState.OFF:
|
||||
this.state = DropDownState.INCLUDE;
|
||||
break;
|
||||
case DropDownState.INCLUDE:
|
||||
this.state = DropDownState.EXCLUDE;
|
||||
break;
|
||||
case DropDownState.EXCLUDE:
|
||||
this.state = DropDownState.OFF;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (this.state) {
|
||||
case DropDownState.ON:
|
||||
this.state = DropDownState.OFF;
|
||||
break;
|
||||
case DropDownState.OFF:
|
||||
this.state = DropDownState.ON;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return this.setOptionState(type, this.state);
|
||||
}
|
||||
|
||||
public setDirection(dir: SortDirection): void {
|
||||
|
@ -117,7 +174,7 @@ export class DropDown extends Phaser.GameObjects.Container {
|
|||
if (type === DropDownType.SINGLE && option.state === DropDownState.OFF) {
|
||||
option.toggle.setVisible(false);
|
||||
}
|
||||
option.setOptionState(option.state);
|
||||
option.setOptionState(type, option.state);
|
||||
|
||||
option.width = optionWidth;
|
||||
option.y = index * optionHeight + index * optionSpacing + optionPaddingY;
|
||||
|
@ -130,8 +187,13 @@ export class DropDown extends Phaser.GameObjects.Container {
|
|||
option.sprite.x = cursorOffset + optionPaddingX + 3 + 8;
|
||||
option.sprite.y = optionHeight / 2;
|
||||
}
|
||||
option.toggle.x = cursorOffset + optionPaddingX + 3 + (type === DropDownType.MULTI ? 0 : 3);
|
||||
option.toggle.y = optionHeight / 2 + (type === DropDownType.MULTI ? 0 : 1);
|
||||
if (type === DropDownType.SINGLE) {
|
||||
option.toggle.x = cursorOffset + optionPaddingX + 3 + 3;
|
||||
option.toggle.y = optionHeight / 2 + 1;
|
||||
} else {
|
||||
option.toggle.x = cursorOffset + optionPaddingX + 3;
|
||||
option.toggle.y = optionHeight / 2;
|
||||
}
|
||||
});
|
||||
this.window = addWindow(scene, 0, 0, optionWidth, options[options.length - 1].y + optionHeight + optionPaddingY, false, false, null, null, WindowVariant.XTHIN);
|
||||
this.add(this.window);
|
||||
|
@ -164,37 +226,39 @@ export class DropDown extends Phaser.GameObjects.Container {
|
|||
|
||||
toggleOptionState(): void {
|
||||
if (this.dropDownType === DropDownType.MULTI) {
|
||||
const newState = this.options[this.cursor].toggleOptionState();
|
||||
|
||||
const newState = this.options[this.cursor].toggleOptionState(this.dropDownType);
|
||||
if (this.cursor === 0) {
|
||||
this.options.forEach((option, index) => {
|
||||
if (index !== this.cursor) {
|
||||
option.setOptionState(newState);
|
||||
option.setOptionState(this.dropDownType, newState);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (this.checkForAllOff()) {
|
||||
this.options[0].setOptionState(DropDownState.OFF);
|
||||
this.options[0].setOptionState(this.dropDownType, DropDownState.OFF);
|
||||
} else if (this.checkForAllOn()) {
|
||||
this.options[0].setOptionState(DropDownState.ON);
|
||||
this.options[0].setOptionState(this.dropDownType, DropDownState.ON);
|
||||
} else {
|
||||
this.options[0].setOptionState(DropDownState.OFF);
|
||||
this.options[0].setOptionState(this.dropDownType, DropDownState.OFF);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else if (this.dropDownType === DropDownType.SINGLE) {
|
||||
if (this.options[this.cursor].state === DropDownState.OFF) {
|
||||
this.options.forEach((option) => {
|
||||
option.setOptionState(DropDownState.OFF);
|
||||
option.setOptionState(this.dropDownType, DropDownState.OFF);
|
||||
option.setDirection(SortDirection.ASC);
|
||||
option.toggle.setVisible(false);
|
||||
});
|
||||
this.options[this.cursor].setOptionState(DropDownState.ON);
|
||||
this.options[this.cursor].setOptionState(this.dropDownType, DropDownState.ON);
|
||||
this.options[this.cursor].setDirection(this.lastDir);
|
||||
this.options[this.cursor].toggle.setVisible(true);
|
||||
} else {
|
||||
this.options[this.cursor].toggleDirection();
|
||||
this.lastDir = this.options[this.cursor].dir;
|
||||
}
|
||||
} else if (this.dropDownType === DropDownType.TRI) {
|
||||
this.options[this.cursor].toggleOptionState(this.dropDownType);
|
||||
this.autoSize();
|
||||
}
|
||||
this.onChange();
|
||||
}
|
||||
|
@ -220,6 +284,11 @@ export class DropDown extends Phaser.GameObjects.Container {
|
|||
getVals(): any[] {
|
||||
if (this.dropDownType === DropDownType.MULTI) {
|
||||
return this.options.filter((option, i) => i > 0 && option.state === DropDownState.ON).map((option) => option.val);
|
||||
// in TRI dropdown, if state is ON, return the "ON" with the value, if state is OFF, return the "OFF" with the value, if state is TRI, return the "TRI" with the value
|
||||
} else if (this.dropDownType === DropDownType.TRI) {
|
||||
return this.options.filter((option, i) => option.state === DropDownState.OFF || option.state === DropDownState.INCLUDE || option.state === DropDownState.EXCLUDE).map((option) => {
|
||||
return {val: option.val, state: option.state};
|
||||
});
|
||||
} else {
|
||||
return this.options.filter((option, i) => option.state === DropDownState.ON).map((option) => {
|
||||
return {val: option.val, dir: option.dir};
|
||||
|
|
|
@ -7,8 +7,9 @@ import { addWindow, WindowVariant } from "./ui-theme";
|
|||
export enum DropDownColumn {
|
||||
GEN,
|
||||
TYPES,
|
||||
SHINY,
|
||||
UNLOCKS,
|
||||
WIN,
|
||||
MISC,
|
||||
SORT
|
||||
}
|
||||
|
||||
|
@ -22,8 +23,9 @@ export class FilterBar extends Phaser.GameObjects.Container {
|
|||
private lastCursor: number = -1;
|
||||
public defaultGenVals: any[] = [];
|
||||
public defaultTypeVals: any[] = [];
|
||||
public defaultUnlockVals: any[] = [];
|
||||
public defaultWinVals: any[] = [];
|
||||
public defaultShinyVals: any[] = [];
|
||||
public defaultUnlocksVals: any[] = [];
|
||||
public defaultMiscVals: any[] = [];
|
||||
public defaultSortVals: any[] = [];
|
||||
|
||||
constructor(scene: BattleScene, x: number, y: number, width: number, height: number) {
|
||||
|
@ -57,43 +59,51 @@ export class FilterBar extends Phaser.GameObjects.Container {
|
|||
updateFilterLabels(): void {
|
||||
const genVals = this.getVals(DropDownColumn.GEN);
|
||||
const typeVals = this.getVals(DropDownColumn.TYPES);
|
||||
const unlockVals = this.getVals(DropDownColumn.UNLOCKS);
|
||||
const winVals = this.getVals(DropDownColumn.WIN);
|
||||
const shinyVals = this.getVals(DropDownColumn.SHINY);
|
||||
const unlocksVals = this.getVals(DropDownColumn.UNLOCKS);
|
||||
const miscVals = this.getVals(DropDownColumn.MISC);
|
||||
const sortVals = this.getVals(DropDownColumn.SORT);
|
||||
|
||||
// onColor is Yellow, offColor is White
|
||||
const onColor = 0xffef5c;
|
||||
const offColor = 0xffffff;
|
||||
|
||||
// if genVals and defaultGenVals has same elements, set the label to White else set it to Green
|
||||
// if genVals and defaultGenVals has same elements, set the label to offColor else set it to onColor
|
||||
if (genVals.length === this.defaultGenVals.length && genVals.every((value, index) => value === this.defaultGenVals[index])) {
|
||||
this.labels[DropDownColumn.GEN].setTint(offColor);
|
||||
} else {
|
||||
this.labels[DropDownColumn.GEN].setTint(onColor);
|
||||
}
|
||||
|
||||
// if typeVals and defaultTypeVals has same elements, set the label to White else set it to Green
|
||||
// if typeVals and defaultTypeVals has same elements, set the label to offColor else set it to onColor
|
||||
if (typeVals.length === this.defaultTypeVals.length && typeVals.every((value, index) => value === this.defaultTypeVals[index])) {
|
||||
this.labels[DropDownColumn.TYPES].setTint(offColor);
|
||||
} else {
|
||||
this.labels[DropDownColumn.TYPES].setTint(onColor);
|
||||
}
|
||||
|
||||
// if unlockVals and defaultUnlockVals has same elements, set the label to White else set it to Green
|
||||
if (unlockVals.length === this.defaultUnlockVals.length && unlockVals.every((value, index) => value === this.defaultUnlockVals[index])) {
|
||||
// if shinyVals and defaultShinyVals has same elements, set the label to offColor else set it to onColor
|
||||
if (shinyVals.length === this.defaultShinyVals.length && shinyVals.every((value, index) => value === this.defaultShinyVals[index])) {
|
||||
this.labels[DropDownColumn.SHINY].setTint(offColor);
|
||||
} else {
|
||||
this.labels[DropDownColumn.SHINY].setTint(onColor);
|
||||
}
|
||||
|
||||
// if unlocksVals and defaultUnlocksVals has same elements, set the label to offColor else set it to onColor
|
||||
if (unlocksVals.every((value, index) => value["val"] === this.defaultUnlocksVals[index]["val"] && value["state"] === this.defaultUnlocksVals[index]["state"])) {
|
||||
this.labels[DropDownColumn.UNLOCKS].setTint(offColor);
|
||||
} else {
|
||||
this.labels[DropDownColumn.UNLOCKS].setTint(onColor);
|
||||
}
|
||||
|
||||
// if winVals and defaultWinVals has same elements, set the label to White else set it to Green
|
||||
if (winVals.length === this.defaultWinVals.length && winVals.every((value, index) => value === this.defaultWinVals[index])) {
|
||||
this.labels[DropDownColumn.WIN].setTint(offColor);
|
||||
// if miscVals and defaultMiscVals has same elements, set the label to offColor else set it to onColor
|
||||
if (miscVals.every((value, index) => value["val"] === this.defaultMiscVals[index]["val"] && value["state"] === this.defaultMiscVals[index]["state"])) {
|
||||
this.labels[DropDownColumn.MISC].setTint(offColor);
|
||||
} else {
|
||||
this.labels[DropDownColumn.WIN].setTint(onColor);
|
||||
this.labels[DropDownColumn.MISC].setTint(onColor);
|
||||
}
|
||||
|
||||
// if sortVals and defaultSortVals has same value and dir, set the label to White else set it to Green
|
||||
// if sortVals and defaultSortVals has same value and dir, set the label to offColor else set it to onColor
|
||||
if (sortVals[0]["dir"] === this.defaultSortVals[0]["dir"] && sortVals[0]["val"] === this.defaultSortVals[0]["val"]) {
|
||||
this.labels[DropDownColumn.SORT].setTint(offColor);
|
||||
} else {
|
||||
|
|
|
@ -327,7 +327,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||
// set gen filter to all off except for the I GEN
|
||||
for (const option of genOptions) {
|
||||
if (option.val !== 1) {
|
||||
option.setOptionState(DropDownState.OFF);
|
||||
option.setOptionState(DropDownType.MULTI ,DropDownState.OFF);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -346,7 +346,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||
this.filterBar.addFilter(i18next.t("filterBar:typeFilter"), new DropDown(this.scene, 0, 0, typeOptions, this.updateStarters, DropDownType.MULTI, 0.5));
|
||||
this.filterBar.defaultTypeVals = this.filterBar.getVals(DropDownColumn.TYPES);
|
||||
|
||||
// Unlocks filter
|
||||
// shiny filter
|
||||
const shiny1Sprite = this.scene.add.sprite(0, 0, "shiny_icons");
|
||||
shiny1Sprite.setOrigin(0.15, 0.2);
|
||||
shiny1Sprite.setScale(0.6);
|
||||
|
@ -363,24 +363,32 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||
shiny3Sprite.setFrame(getVariantIcon(2));
|
||||
shiny3Sprite.setTint(getVariantTint(2));
|
||||
|
||||
const unlocksOptions = [
|
||||
const shinyOptions = [
|
||||
new DropDownOption(this.scene, "SHINY3", null, shiny3Sprite),
|
||||
new DropDownOption(this.scene, "SHINY2", null, shiny2Sprite),
|
||||
new DropDownOption(this.scene, "SHINY", null, shiny1Sprite),
|
||||
new DropDownOption(this.scene, "NORMAL", i18next.t("filterBar:normal")),
|
||||
new DropDownOption(this.scene, "UNCAUGHT", i18next.t("filterBar:uncaught")),
|
||||
new DropDownOption(this.scene, "PASSIVEUNLOCKED", i18next.t("filterBar:passiveUnlocked")),
|
||||
new DropDownOption(this.scene, "PASSIVELOCKED", i18next.t("filterBar:passiveLocked"))];
|
||||
];
|
||||
|
||||
this.filterBar.addFilter(i18next.t("filterBar:unlocksFilter"), new DropDown(this.scene, 0, 0, unlocksOptions, this.updateStarters, DropDownType.MULTI));
|
||||
this.filterBar.defaultUnlockVals = this.filterBar.getVals(DropDownColumn.UNLOCKS);
|
||||
this.filterBar.addFilter("Owned", new DropDown(this.scene, 0, 0, shinyOptions, this.updateStarters, DropDownType.MULTI));
|
||||
this.filterBar.defaultShinyVals = this.filterBar.getVals(DropDownColumn.SHINY);
|
||||
|
||||
// win filter
|
||||
const winOptions = [
|
||||
new DropDownOption(this.scene, "WIN", i18next.t("filterBar:hasWon")),
|
||||
new DropDownOption(this.scene, "NOTWIN", i18next.t("filterBar:hasNotWon"))];
|
||||
this.filterBar.addFilter(i18next.t("filterBar:winFilter"), new DropDown(this.scene, 0, 0, winOptions, this.updateStarters, DropDownType.MULTI));
|
||||
this.filterBar.defaultWinVals = this.filterBar.getVals(DropDownColumn.WIN);
|
||||
|
||||
// unlocks filter
|
||||
const unlocksOptions = [
|
||||
new DropDownOption(this.scene, "PASSIVE", ["Passive", i18next.t("filterBar:passiveUnlocked"), i18next.t("filterBar:passiveLocked")], null, DropDownState.OFF),
|
||||
];
|
||||
|
||||
this.filterBar.addFilter(i18next.t("filterBar:unlocksFilter"), new DropDown(this.scene, 0, 0, unlocksOptions, this.updateStarters, DropDownType.TRI));
|
||||
this.filterBar.defaultUnlocksVals = this.filterBar.getVals(DropDownColumn.UNLOCKS);
|
||||
|
||||
// misc filter
|
||||
const miscOptions = [
|
||||
new DropDownOption(this.scene, "WIN", ["Win", "Win - Yes", "Win - No"], null, DropDownState.OFF),
|
||||
];
|
||||
this.filterBar.addFilter("Misc", new DropDown(this.scene, 0, 0, miscOptions, this.updateStarters, DropDownType.TRI));
|
||||
this.filterBar.defaultMiscVals = this.filterBar.getVals(DropDownColumn.MISC);
|
||||
|
||||
// sort filter
|
||||
const sortOptions = [
|
||||
|
@ -1956,11 +1964,15 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||
const isCaught = !!(caughtVariants & DexAttr.NON_SHINY);
|
||||
const isUncaught = !isCaught && !isVariantCaught && !isVariant2Caught && !isVariant3Caught;
|
||||
const isPassiveUnlocked = this.scene.gameData.starterData[container.species.speciesId].passiveAttr > 0;
|
||||
|
||||
const isWin = this.scene.gameData.starterData[container.species.speciesId].classicWinCount > 0;
|
||||
const isNotWin = this.scene.gameData.starterData[container.species.speciesId].classicWinCount === 0;
|
||||
const isUndefined = this.scene.gameData.starterData[container.species.speciesId].classicWinCount === undefined;
|
||||
|
||||
const fitsGen = this.filterBar.getVals(DropDownColumn.GEN).includes(container.species.generation);
|
||||
|
||||
const fitsType = this.filterBar.getVals(DropDownColumn.TYPES).some(type => container.species.isOfType((type as number) - 1));
|
||||
const fitsShiny = this.filterBar.getVals(DropDownColumn.UNLOCKS).some(variant => {
|
||||
|
||||
const fitsShiny = this.filterBar.getVals(DropDownColumn.SHINY).some(variant => {
|
||||
if (variant === "SHINY3") {
|
||||
return isVariant3Caught;
|
||||
} else if (variant === "SHINY2") {
|
||||
|
@ -1973,22 +1985,26 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||
return isUncaught;
|
||||
}
|
||||
});
|
||||
const fitsPassive = this.filterBar.getVals(DropDownColumn.UNLOCKS).some(variant => {
|
||||
if (variant === "PASSIVEUNLOCKED") {
|
||||
|
||||
const fitsPassive = this.filterBar.getVals(DropDownColumn.UNLOCKS).some(unlocks => {
|
||||
if (unlocks.val === "PASSIVE" && unlocks.state === DropDownState.INCLUDE) {
|
||||
return isPassiveUnlocked;
|
||||
} else if (variant === "PASSIVELOCKED") {
|
||||
} else if (unlocks.val === "PASSIVE" && unlocks.state === DropDownState.EXCLUDE) {
|
||||
return !isPassiveUnlocked;
|
||||
} else if (unlocks.val === "PASSIVE" && unlocks.state === DropDownState.OFF) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
const isWin = this.scene.gameData.starterData[container.species.speciesId].classicWinCount > 0;
|
||||
const isNotWin = this.scene.gameData.starterData[container.species.speciesId].classicWinCount === 0;
|
||||
const isUndefined = this.scene.gameData.starterData[container.species.speciesId].classicWinCount === undefined;
|
||||
|
||||
const fitsWin = this.filterBar.getVals(DropDownColumn.WIN).some(win => {
|
||||
if (win === "WIN") {
|
||||
const fitsWin = this.filterBar.getVals(DropDownColumn.MISC).some(misc => {
|
||||
if (container.species.speciesId < 10) {
|
||||
}
|
||||
if (misc.val === "WIN" && misc.state === DropDownState.INCLUDE) {
|
||||
return isWin;
|
||||
} else if (win === "NOTWIN") {
|
||||
} else if (misc.val === "WIN" && misc.state === DropDownState.EXCLUDE) {
|
||||
return isNotWin || isUndefined;
|
||||
} else if (misc.val === "WIN" && misc.state === DropDownState.OFF) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue