🎉 Allow setting actor transitions in overview
This commit is contained in:
@@ -121,7 +121,8 @@ var SimpleFade = class SimpleFade {
|
|||||||
|
|
||||||
// This will be called in various places where a unique identifier for this effect is
|
// This will be called in various places where a unique identifier for this effect is
|
||||||
// required. It should match the prefix of the settings keys which store whether the
|
// required. It should match the prefix of the settings keys which store whether the
|
||||||
// effect is enabled currently (e.g. the '*-close-effect').
|
// effect is enabled currently (e.g. '*-close-effect'), and its animation time
|
||||||
|
// (e.g. '*-animation-time').
|
||||||
static getNick() {
|
static getNick() {
|
||||||
return 'simple-fade';
|
return 'simple-fade';
|
||||||
}
|
}
|
||||||
@@ -148,24 +149,12 @@ var SimpleFade = class SimpleFade {
|
|||||||
return new Shader(settings);
|
return new Shader(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is also called from extension.js. It is used to tweak the ongoing transitions of
|
// This is also called from extension.js. It is used to tweak the ongoing transition of
|
||||||
// the actor - usually windows are faded to transparency and scaled down slightly by
|
// the actor - usually windows are faded to transparency and scaled down slightly by
|
||||||
// GNOME Shell. Here, we modify this behavior as well as the transition duration.
|
// GNOME Shell. For each property, you can set a "from", "to", and a "mode". For this
|
||||||
static tweakTransitions(actor, settings) {
|
// effect, windows should neither be scaled nor faded.
|
||||||
const animationTime = settings.get_int('simple-fade-animation-time');
|
static getCloseTransition(actor, settings) {
|
||||||
|
return {'opacity': {to: 255}, 'scale-x': {to: 1.0}, 'scale-y': {to: 1.0}};
|
||||||
const tweakTransition = (property, value) => {
|
|
||||||
const transition = actor.get_transition(property);
|
|
||||||
if (transition) {
|
|
||||||
transition.set_to(value);
|
|
||||||
transition.set_duration(animationTime);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// We re-target these transitions so that the window is neither scaled nor faded.
|
|
||||||
tweakTransition('opacity', 255);
|
|
||||||
tweakTransition('scale-x', 1);
|
|
||||||
tweakTransition('scale-y', 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+57
-3
@@ -66,6 +66,10 @@ class Extension {
|
|||||||
// Store a reference to the settings object.
|
// Store a reference to the settings object.
|
||||||
this._settings = ExtensionUtils.getSettings();
|
this._settings = ExtensionUtils.getSettings();
|
||||||
|
|
||||||
|
// This will store an item of ALL_EFFECTS which was used the last time a window was
|
||||||
|
// closed.
|
||||||
|
this._effect = 0;
|
||||||
|
|
||||||
// We will monkey-patch these three methods. Let's store the original ones.
|
// We will monkey-patch these three methods. Let's store the original ones.
|
||||||
this._origWindowRemoved = Workspace.prototype._windowRemoved;
|
this._origWindowRemoved = Workspace.prototype._windowRemoved;
|
||||||
this._origDoRemoveWindow = Workspace.prototype._doRemoveWindow;
|
this._origDoRemoveWindow = Workspace.prototype._doRemoveWindow;
|
||||||
@@ -87,7 +91,20 @@ class Extension {
|
|||||||
|
|
||||||
WindowPreview.prototype._deleteAll = function() {
|
WindowPreview.prototype._deleteAll = function() {
|
||||||
if (!this._closeRequested) {
|
if (!this._closeRequested) {
|
||||||
|
|
||||||
|
this.metaWindow.connect('unmanaged', () => {
|
||||||
|
const transitionConfig = extensionThis._effect.getCloseTransition(
|
||||||
|
this.window_container, extensionThis._settings);
|
||||||
|
extensionThis._tweakTransitions(this.window_container, transitionConfig);
|
||||||
|
});
|
||||||
|
|
||||||
extensionThis._origDeleteAll.apply(this);
|
extensionThis._origDeleteAll.apply(this);
|
||||||
|
|
||||||
|
// This is required, else WindowPreview's _restack() which is called by the
|
||||||
|
// "this.overlayEnabled = false", sometimes tries to access an already delete
|
||||||
|
// WindowPreview.
|
||||||
|
this._stackAbove = null;
|
||||||
|
this.overlayEnabled = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -175,13 +192,14 @@ class Extension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Choose a random effect.
|
// Choose a random effect.
|
||||||
const Effect = enabledEffects[Math.floor(Math.random() * enabledEffects.length)];
|
this._effect = enabledEffects[Math.floor(Math.random() * enabledEffects.length)];
|
||||||
|
|
||||||
// The effect usually will choose to override the present transitions on the actor.
|
// The effect usually will choose to override the present transitions on the actor.
|
||||||
Effect.tweakTransitions(actor, this._settings);
|
const transitionConfig = this._effect.getCloseTransition(actor, this._settings);
|
||||||
|
this._tweakTransitions(actor, transitionConfig);
|
||||||
|
|
||||||
// Add a cool shader to our window actor!
|
// Add a cool shader to our window actor!
|
||||||
const shader = Effect.createShader(actor, this._settings);
|
const shader = this._effect.createShader(actor, this._settings);
|
||||||
|
|
||||||
if (shader) {
|
if (shader) {
|
||||||
actor.add_effect(shader);
|
actor.add_effect(shader);
|
||||||
@@ -255,6 +273,42 @@ class Extension {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is used to tweak the ongoing transitions of a window actor. This is either the
|
||||||
|
// actual actor of the Meta.Window or a clone in the overview. Usually windows are faded
|
||||||
|
// to transparency and scaled down slightly by GNOME Shell. Here, we allow modifications
|
||||||
|
// to this behavior by the effects.
|
||||||
|
_tweakTransitions(actor, config) {
|
||||||
|
const duration = this._settings.get_int(this._effect.getNick() + '-animation-time');
|
||||||
|
|
||||||
|
for (const property in config) {
|
||||||
|
const from = config[property].from;
|
||||||
|
const to = config[property].to;
|
||||||
|
const mode = config[property].mode;
|
||||||
|
|
||||||
|
const transition = actor.get_transition(property);
|
||||||
|
|
||||||
|
if (transition) {
|
||||||
|
transition.set_duration(duration);
|
||||||
|
|
||||||
|
if (to != undefined) transition.set_to(to);
|
||||||
|
if (from != undefined) transition.set_from(from);
|
||||||
|
if (mode != undefined) transition.set_progress_mode(mode);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (from != undefined) actor[property] = from;
|
||||||
|
|
||||||
|
if (to != undefined) {
|
||||||
|
actor.save_easing_state();
|
||||||
|
actor.set_easing_duration(duration)
|
||||||
|
if (mode != undefined) actor.set_easing_mode(mode);
|
||||||
|
actor[property] = to;
|
||||||
|
actor.restore_easing_state();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function is called once when the extension is loaded, not enabled.
|
// This function is called once when the extension is loaded, not enabled.
|
||||||
|
|||||||
+6
-18
@@ -40,7 +40,8 @@ var EnergizeA = class EnergizeA {
|
|||||||
|
|
||||||
// This will be called in various places where a unique identifier for this effect is
|
// This will be called in various places where a unique identifier for this effect is
|
||||||
// required. It should match the prefix of the settings keys which store whether the
|
// required. It should match the prefix of the settings keys which store whether the
|
||||||
// effect is enabled currently (e.g. the '*-close-effect').
|
// effect is enabled currently (e.g. '*-close-effect'), and its animation time
|
||||||
|
// (e.g. '*-animation-time').
|
||||||
static getNick() {
|
static getNick() {
|
||||||
return 'energize-a';
|
return 'energize-a';
|
||||||
}
|
}
|
||||||
@@ -80,24 +81,11 @@ var EnergizeA = class EnergizeA {
|
|||||||
return new Shader(settings);
|
return new Shader(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is also called from extension.js. It is used to tweak the ongoing transitions of
|
// This is also called from extension.js. It is used to tweak the ongoing transition of
|
||||||
// the actor - usually windows are faded to transparency and scaled down slightly by
|
// the actor - usually windows are faded to transparency and scaled down slightly by
|
||||||
// GNOME Shell. Here, we modify this behavior as well as the transition duration.
|
// GNOME Shell. For this effect, windows should neither be scaled nor faded.
|
||||||
static tweakTransitions(actor, settings) {
|
static getCloseTransition(actor, settings) {
|
||||||
const animationTime = settings.get_int('energize-a-animation-time');
|
return {'opacity': {to: 255}, 'scale-x': {to: 1.0}, 'scale-y': {to: 1.0}};
|
||||||
|
|
||||||
const tweakTransition = (property, value) => {
|
|
||||||
const transition = actor.get_transition(property);
|
|
||||||
if (transition) {
|
|
||||||
transition.set_to(value);
|
|
||||||
transition.set_duration(animationTime);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// We re-target these transitions so that the window is neither scaled nor faded.
|
|
||||||
tweakTransition('opacity', 255);
|
|
||||||
tweakTransition('scale-x', 1);
|
|
||||||
tweakTransition('scale-y', 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-18
@@ -40,7 +40,8 @@ var EnergizeB = class EnergizeB {
|
|||||||
|
|
||||||
// This will be called in various places where a unique identifier for this effect is
|
// This will be called in various places where a unique identifier for this effect is
|
||||||
// required. It should match the prefix of the settings keys which store whether the
|
// required. It should match the prefix of the settings keys which store whether the
|
||||||
// effect is enabled currently (e.g. the '*-close-effect').
|
// effect is enabled currently (e.g. '*-close-effect'), and its animation time
|
||||||
|
// (e.g. '*-animation-time').
|
||||||
static getNick() {
|
static getNick() {
|
||||||
return 'energize-b';
|
return 'energize-b';
|
||||||
}
|
}
|
||||||
@@ -80,24 +81,11 @@ var EnergizeB = class EnergizeB {
|
|||||||
return new Shader(settings);
|
return new Shader(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is also called from extension.js. It is used to tweak the ongoing transitions of
|
// This is also called from extension.js. It is used to tweak the ongoing transition of
|
||||||
// the actor - usually windows are faded to transparency and scaled down slightly by
|
// the actor - usually windows are faded to transparency and scaled down slightly by
|
||||||
// GNOME Shell. Here, we modify this behavior as well as the transition duration.
|
// GNOME Shell. For this effect, windows should neither be scaled nor faded.
|
||||||
static tweakTransitions(actor, settings) {
|
static getCloseTransition(actor, settings) {
|
||||||
const animationTime = settings.get_int('energize-b-animation-time');
|
return {'opacity': {to: 255}, 'scale-x': {to: 1.0}, 'scale-y': {to: 1.0}};
|
||||||
|
|
||||||
const tweakTransition = (property, value) => {
|
|
||||||
const transition = actor.get_transition(property);
|
|
||||||
if (transition) {
|
|
||||||
transition.set_to(value);
|
|
||||||
transition.set_duration(animationTime);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// We re-target these transitions so that the window is neither scaled nor faded.
|
|
||||||
tweakTransition('opacity', 255);
|
|
||||||
tweakTransition('scale-x', 1);
|
|
||||||
tweakTransition('scale-y', 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-18
@@ -44,7 +44,8 @@ var Fire = class Fire {
|
|||||||
|
|
||||||
// This will be called in various places where a unique identifier for this effect is
|
// This will be called in various places where a unique identifier for this effect is
|
||||||
// required. It should match the prefix of the settings keys which store whether the
|
// required. It should match the prefix of the settings keys which store whether the
|
||||||
// effect is enabled currently (e.g. the '*-close-effect').
|
// effect is enabled currently (e.g. '*-close-effect'), and its animation time
|
||||||
|
// (e.g. '*-animation-time').
|
||||||
static getNick() {
|
static getNick() {
|
||||||
return 'fire';
|
return 'fire';
|
||||||
}
|
}
|
||||||
@@ -101,24 +102,11 @@ var Fire = class Fire {
|
|||||||
return new Shader(settings);
|
return new Shader(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is also called from extension.js. It is used to tweak the ongoing transitions of
|
// This is also called from extension.js. It is used to tweak the ongoing transition of
|
||||||
// the actor - usually windows are faded to transparency and scaled down slightly by
|
// the actor - usually windows are faded to transparency and scaled down slightly by
|
||||||
// GNOME Shell. Here, we modify this behavior as well as the transition duration.
|
// GNOME Shell. For this effect, windows should neither be scaled nor faded.
|
||||||
static tweakTransitions(actor, settings) {
|
static getCloseTransition(actor, settings) {
|
||||||
const animationTime = settings.get_int('fire-animation-time');
|
return {'opacity': {to: 255}, 'scale-x': {to: 1.0}, 'scale-y': {to: 1.0}};
|
||||||
|
|
||||||
const tweakTransition = (property, value) => {
|
|
||||||
const transition = actor.get_transition(property);
|
|
||||||
if (transition) {
|
|
||||||
transition.set_to(value);
|
|
||||||
transition.set_duration(animationTime);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// We re-target these transitions so that the window is neither scaled nor faded.
|
|
||||||
tweakTransition('opacity', 255);
|
|
||||||
tweakTransition('scale-x', 1);
|
|
||||||
tweakTransition('scale-y', 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- private stuff
|
// ----------------------------------------------------------------------- private stuff
|
||||||
|
|||||||
+6
-18
@@ -44,7 +44,8 @@ var Matrix = class Matrix {
|
|||||||
|
|
||||||
// This will be called in various places where a unique identifier for this effect is
|
// This will be called in various places where a unique identifier for this effect is
|
||||||
// required. It should match the prefix of the settings keys which store whether the
|
// required. It should match the prefix of the settings keys which store whether the
|
||||||
// effect is enabled currently (e.g. the '*-close-effect').
|
// effect is enabled currently (e.g. '*-close-effect'), and its animation time
|
||||||
|
// (e.g. '*-animation-time').
|
||||||
static getNick() {
|
static getNick() {
|
||||||
return 'matrix';
|
return 'matrix';
|
||||||
}
|
}
|
||||||
@@ -86,24 +87,11 @@ var Matrix = class Matrix {
|
|||||||
return new Shader(settings);
|
return new Shader(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is also called from extension.js. It is used to tweak the ongoing transitions of
|
// This is also called from extension.js. It is used to tweak the ongoing transition of
|
||||||
// the actor - usually windows are faded to transparency and scaled down slightly by
|
// the actor - usually windows are faded to transparency and scaled down slightly by
|
||||||
// GNOME Shell. Here, we modify this behavior as well as the transition duration.
|
// GNOME Shell. For this effect, windows should neither be scaled nor faded.
|
||||||
static tweakTransitions(actor, settings) {
|
static getCloseTransition(actor, settings) {
|
||||||
const animationTime = settings.get_int('matrix-animation-time');
|
return {'opacity': {to: 255}, 'scale-x': {to: 1.0}, 'scale-y': {to: 1.0}};
|
||||||
|
|
||||||
const tweakTransition = (property, value) => {
|
|
||||||
const transition = actor.get_transition(property);
|
|
||||||
if (transition) {
|
|
||||||
transition.set_to(value);
|
|
||||||
transition.set_duration(animationTime);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// We re-target these transitions so that the window is neither scaled nor faded.
|
|
||||||
tweakTransition('opacity', 255);
|
|
||||||
tweakTransition('scale-x', 1);
|
|
||||||
tweakTransition('scale-y', 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-19
@@ -42,7 +42,8 @@ var TRexAttack = class TRexAttack {
|
|||||||
|
|
||||||
// This will be called in various places where a unique identifier for this effect is
|
// This will be called in various places where a unique identifier for this effect is
|
||||||
// required. It should match the prefix of the settings keys which store whether the
|
// required. It should match the prefix of the settings keys which store whether the
|
||||||
// effect is enabled currently (e.g. the '*-close-effect').
|
// effect is enabled currently (e.g. '*-close-effect'), and its animation time
|
||||||
|
// (e.g. '*-animation-time').
|
||||||
static getNick() {
|
static getNick() {
|
||||||
return 'trex';
|
return 'trex';
|
||||||
}
|
}
|
||||||
@@ -84,26 +85,17 @@ var TRexAttack = class TRexAttack {
|
|||||||
return new Shader(settings);
|
return new Shader(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is also called from extension.js. It is used to tweak the ongoing transitions of
|
// This is also called from extension.js. It is used to tweak the ongoing transition of
|
||||||
// the actor - usually windows are faded to transparency and scaled down slightly by
|
// the actor - usually windows are faded to transparency and scaled down slightly by
|
||||||
// GNOME Shell. Here, we modify this behavior as well as the transition duration.
|
// GNOME Shell. For this effect, we slightly increase the window's scale as part of the
|
||||||
static tweakTransitions(actor, settings) {
|
// warp effect.
|
||||||
const animationTime = settings.get_int('trex-animation-time');
|
static getCloseTransition(actor, settings) {
|
||||||
|
|
||||||
const tweakTransition = (property, value) => {
|
|
||||||
const transition = actor.get_transition(property);
|
|
||||||
if (transition) {
|
|
||||||
transition.set_to(value);
|
|
||||||
transition.set_duration(animationTime);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// For this effect, we slightly increase the window's scale as part of the warp
|
|
||||||
// effect.
|
|
||||||
const warp = 0.5 * settings.get_double('claw-scratch-warp');
|
const warp = 0.5 * settings.get_double('claw-scratch-warp');
|
||||||
tweakTransition('opacity', 255);
|
return {
|
||||||
tweakTransition('scale-x', 1.0 + warp);
|
'opacity': {to: 255},
|
||||||
tweakTransition('scale-y', 1.0 + warp);
|
'scale-x': {to: 1.0 + warp},
|
||||||
|
'scale-y': {to: 1.0 + warp}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-18
@@ -42,7 +42,8 @@ var TVEffect = class TVEffect {
|
|||||||
|
|
||||||
// This will be called in various places where a unique identifier for this effect is
|
// This will be called in various places where a unique identifier for this effect is
|
||||||
// required. It should match the prefix of the settings keys which store whether the
|
// required. It should match the prefix of the settings keys which store whether the
|
||||||
// effect is enabled currently (e.g. the '*-close-effect').
|
// effect is enabled currently (e.g. '*-close-effect'), and its animation time
|
||||||
|
// (e.g. '*-animation-time').
|
||||||
static getNick() {
|
static getNick() {
|
||||||
return 'tv';
|
return 'tv';
|
||||||
}
|
}
|
||||||
@@ -81,24 +82,11 @@ var TVEffect = class TVEffect {
|
|||||||
return new Shader(settings);
|
return new Shader(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is also called from extension.js. It is used to tweak the ongoing transitions of
|
// This is also called from extension.js. It is used to tweak the ongoing transition of
|
||||||
// the actor - usually windows are faded to transparency and scaled down slightly by
|
// the actor - usually windows are faded to transparency and scaled down slightly by
|
||||||
// GNOME Shell. Here, we modify this behavior as well as the transition duration.
|
// GNOME Shell. For this effect, windows are scaled down vertically.
|
||||||
static tweakTransitions(actor, settings) {
|
static getCloseTransition(actor, settings) {
|
||||||
const animationTime = settings.get_int('tv-animation-time');
|
return {'opacity': {to: 255}, 'scale-x': {to: 1.0}, 'scale-y': {to: 0.5}};
|
||||||
|
|
||||||
const tweakTransition = (property, value) => {
|
|
||||||
const transition = actor.get_transition(property);
|
|
||||||
if (transition) {
|
|
||||||
transition.set_to(value);
|
|
||||||
transition.set_duration(animationTime);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// For this effect, we scale the window only vertically.
|
|
||||||
tweakTransition('opacity', 255);
|
|
||||||
tweakTransition('scale-x', 1);
|
|
||||||
tweakTransition('scale-y', 0.5);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-21
@@ -27,9 +27,10 @@ const utils = Me.imports.src.utils;
|
|||||||
// The shader class for this effect is registered further down in this file.
|
// The shader class for this effect is registered further down in this file.
|
||||||
let Shader = null;
|
let Shader = null;
|
||||||
|
|
||||||
// The effect class is completely static. It can be used to get some metadata (like the
|
// This will be called in various places where a unique identifier for this effect is
|
||||||
// effect's name or supported GNOME Shell versions), to initialize the respective page of
|
// required. It should match the prefix of the settings keys which store whether the
|
||||||
// the settings dialog, as well as to create the actual shader for the effect.
|
// effect is enabled currently (e.g. '*-close-effect'), and its animation time
|
||||||
|
// (e.g. '*-animation-time').
|
||||||
var Wisps = class Wisps {
|
var Wisps = class Wisps {
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------- metadata
|
// ---------------------------------------------------------------------------- metadata
|
||||||
@@ -80,25 +81,11 @@ var Wisps = class Wisps {
|
|||||||
return new Shader(settings);
|
return new Shader(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is also called from extension.js. It is used to tweak the ongoing transitions of
|
// This is also called from extension.js. It is used to tweak the ongoing transition of
|
||||||
// the actor - usually windows are faded to transparency and scaled down slightly by
|
// the actor - usually windows are faded to transparency and scaled down slightly by
|
||||||
// GNOME Shell. Here, we modify this behavior as well as the transition duration.
|
// GNOME Shell. For this effect, windows should be scaled down slightly but not faded.
|
||||||
static tweakTransitions(actor, settings) {
|
static getCloseTransition(actor, settings) {
|
||||||
const animationTime = settings.get_int('wisps-animation-time');
|
return {'opacity': {to: 255}, 'scale-x': {to: 0.9}, 'scale-y': {to: 0.9}};
|
||||||
|
|
||||||
const tweakTransition = (property, value) => {
|
|
||||||
const transition = actor.get_transition(property);
|
|
||||||
if (transition) {
|
|
||||||
transition.set_to(value);
|
|
||||||
transition.set_duration(animationTime);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// We re-target these transitions so that the window is not faded but scaled down a
|
|
||||||
// tiny bit.
|
|
||||||
tweakTransition('opacity', 255);
|
|
||||||
tweakTransition('scale-x', 0.9);
|
|
||||||
tweakTransition('scale-y', 0.9);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user