mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-08-02 17:54:45 +00:00
taskswitcher: Expose visible state to DBus and hookup to homescreen anim
This commit is contained in:
parent
5f93d0198e
commit
083481d971
9 changed files with 91 additions and 32 deletions
|
|
@ -103,6 +103,14 @@ Item {
|
||||||
function onCloseAppLaunchAnimationRequested() {
|
function onCloseAppLaunchAnimationRequested() {
|
||||||
startupFeedback.close();
|
startupFeedback.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onIsTaskSwitcherVisibleChanged() {
|
||||||
|
if (MobileShellState.ShellDBusClient.isTaskSwitcherVisible) {
|
||||||
|
itemContainer.zoomOutImmediately();
|
||||||
|
} else {
|
||||||
|
itemContainer.zoomIn();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//END API implementation
|
//END API implementation
|
||||||
|
|
@ -132,9 +140,9 @@ Item {
|
||||||
|
|
||||||
// animations
|
// animations
|
||||||
opacity: 0
|
opacity: 0
|
||||||
property real zoomScale: 0.8
|
property real zoomScale: 1
|
||||||
|
|
||||||
Component.onCompleted: zoomIn()
|
readonly property real zoomScaleOut: 0.8
|
||||||
|
|
||||||
function zoomIn() {
|
function zoomIn() {
|
||||||
// don't use check animationsEnabled here, so we ensure the scale and opacity is always 1 when disabled
|
// don't use check animationsEnabled here, so we ensure the scale and opacity is always 1 when disabled
|
||||||
|
|
@ -143,31 +151,36 @@ Item {
|
||||||
opacityAnim.to = 1;
|
opacityAnim.to = 1;
|
||||||
opacityAnim.restart();
|
opacityAnim.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
function zoomOut() {
|
function zoomOut() {
|
||||||
if (ShellSettings.Settings.animationsEnabled) {
|
scaleAnim.to = zoomScaleOut;
|
||||||
scaleAnim.to = 0.8;
|
|
||||||
scaleAnim.restart();
|
scaleAnim.restart();
|
||||||
opacityAnim.to = 0;
|
opacityAnim.to = 0;
|
||||||
opacityAnim.restart();
|
opacityAnim.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function zoomOutImmediately() {
|
||||||
|
zoomScale = zoomScaleOut;
|
||||||
|
opacity = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
NumberAnimation on opacity {
|
NumberAnimation on opacity {
|
||||||
id: opacityAnim
|
id: opacityAnim
|
||||||
duration: ShellSettings.Settings.animationsEnabled ? 300 : 0
|
duration: 300
|
||||||
running: false
|
running: false
|
||||||
}
|
}
|
||||||
|
|
||||||
NumberAnimation on zoomScale {
|
NumberAnimation on zoomScale {
|
||||||
id: scaleAnim
|
id: scaleAnim
|
||||||
duration: ShellSettings.Settings.animationsEnabled ? 600 : 0
|
duration: 600
|
||||||
running: false
|
running: false
|
||||||
easing.type: Easing.OutExpo
|
easing.type: Easing.OutExpo
|
||||||
}
|
}
|
||||||
|
|
||||||
function evaluateAnimChange() {
|
function evaluateAnimChange() {
|
||||||
// only animate if homescreen is visible
|
// only animate if homescreen is visible
|
||||||
if (!WindowPlugin.WindowMaximizedTracker.showingWindow || WindowPlugin.WindowUtil.activeWindowIsShell) {
|
if ((!WindowPlugin.WindowMaximizedTracker.showingWindow || WindowPlugin.WindowUtil.activeWindowIsShell) &&
|
||||||
|
!MobileShellState.ShellDBusClient.isTaskSwitcherVisible) {
|
||||||
itemContainer.zoomIn();
|
itemContainer.zoomIn();
|
||||||
} else {
|
} else {
|
||||||
itemContainer.zoomOut();
|
itemContainer.zoomOut();
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,9 @@
|
||||||
ShellDBusClient::ShellDBusClient(QObject *parent)
|
ShellDBusClient::ShellDBusClient(QObject *parent)
|
||||||
: QObject{parent}
|
: QObject{parent}
|
||||||
, m_interface{new OrgKdePlasmashellInterface{QStringLiteral("org.kde.plasmashell"), QStringLiteral("/Mobile"), QDBusConnection::sessionBus(), this}}
|
, m_interface{new OrgKdePlasmashellInterface{QStringLiteral("org.kde.plasmashell"), QStringLiteral("/Mobile"), QDBusConnection::sessionBus(), this}}
|
||||||
|
, m_watcher{new QDBusServiceWatcher(QStringLiteral("org.kde.plasmashell"), QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForOwnerChange, this)}
|
||||||
, m_connected{false}
|
, m_connected{false}
|
||||||
{
|
{
|
||||||
m_watcher = new QDBusServiceWatcher(QStringLiteral("org.kde.plasmashell"), QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForOwnerChange, this);
|
|
||||||
|
|
||||||
if (m_interface->isValid()) {
|
if (m_interface->isValid()) {
|
||||||
connectSignals();
|
connectSignals();
|
||||||
}
|
}
|
||||||
|
|
@ -38,6 +37,7 @@ void ShellDBusClient::connectSignals()
|
||||||
{
|
{
|
||||||
connect(m_interface, &OrgKdePlasmashellInterface::isActionDrawerOpenChanged, this, &ShellDBusClient::updateIsActionDrawerOpen);
|
connect(m_interface, &OrgKdePlasmashellInterface::isActionDrawerOpenChanged, this, &ShellDBusClient::updateIsActionDrawerOpen);
|
||||||
connect(m_interface, &OrgKdePlasmashellInterface::doNotDisturbChanged, this, &ShellDBusClient::updateDoNotDisturb);
|
connect(m_interface, &OrgKdePlasmashellInterface::doNotDisturbChanged, this, &ShellDBusClient::updateDoNotDisturb);
|
||||||
|
connect(m_interface, &OrgKdePlasmashellInterface::isTaskSwitcherVisibleChanged, this, &ShellDBusClient::updateIsTaskSwitcherVisible);
|
||||||
connect(m_interface, &OrgKdePlasmashellInterface::openActionDrawerRequested, this, &ShellDBusClient::openActionDrawerRequested);
|
connect(m_interface, &OrgKdePlasmashellInterface::openActionDrawerRequested, this, &ShellDBusClient::openActionDrawerRequested);
|
||||||
connect(m_interface, &OrgKdePlasmashellInterface::closeActionDrawerRequested, this, &ShellDBusClient::closeActionDrawerRequested);
|
connect(m_interface, &OrgKdePlasmashellInterface::closeActionDrawerRequested, this, &ShellDBusClient::closeActionDrawerRequested);
|
||||||
connect(m_interface, &OrgKdePlasmashellInterface::openAppLaunchAnimationRequested, this, &ShellDBusClient::openAppLaunchAnimationRequested);
|
connect(m_interface, &OrgKdePlasmashellInterface::openAppLaunchAnimationRequested, this, &ShellDBusClient::openAppLaunchAnimationRequested);
|
||||||
|
|
@ -48,9 +48,10 @@ void ShellDBusClient::connectSignals()
|
||||||
|
|
||||||
updateIsActionDrawerOpen();
|
updateIsActionDrawerOpen();
|
||||||
updateDoNotDisturb();
|
updateDoNotDisturb();
|
||||||
|
updateIsTaskSwitcherVisible();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShellDBusClient::doNotDisturb()
|
bool ShellDBusClient::doNotDisturb() const
|
||||||
{
|
{
|
||||||
return m_doNotDisturb;
|
return m_doNotDisturb;
|
||||||
}
|
}
|
||||||
|
|
@ -60,7 +61,7 @@ void ShellDBusClient::setDoNotDisturb(bool value)
|
||||||
m_interface->setDoNotDisturb(value);
|
m_interface->setDoNotDisturb(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShellDBusClient::isActionDrawerOpen()
|
bool ShellDBusClient::isActionDrawerOpen() const
|
||||||
{
|
{
|
||||||
return m_isActionDrawerOpen;
|
return m_isActionDrawerOpen;
|
||||||
}
|
}
|
||||||
|
|
@ -80,6 +81,11 @@ void ShellDBusClient::closeActionDrawer()
|
||||||
m_interface->closeActionDrawer();
|
m_interface->closeActionDrawer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ShellDBusClient::isTaskSwitcherVisible() const
|
||||||
|
{
|
||||||
|
return m_isTaskSwitcherVisible;
|
||||||
|
}
|
||||||
|
|
||||||
void ShellDBusClient::openAppLaunchAnimation(QString splashIcon, QString title, qreal x, qreal y, qreal sourceIconSize)
|
void ShellDBusClient::openAppLaunchAnimation(QString splashIcon, QString title, qreal x, qreal y, qreal sourceIconSize)
|
||||||
{
|
{
|
||||||
m_interface->openAppLaunchAnimation(splashIcon, title, x, y, sourceIconSize);
|
m_interface->openAppLaunchAnimation(splashIcon, title, x, y, sourceIconSize);
|
||||||
|
|
@ -116,3 +122,9 @@ void ShellDBusClient::updateIsActionDrawerOpen()
|
||||||
m_isActionDrawerOpen = m_interface->isActionDrawerOpen();
|
m_isActionDrawerOpen = m_interface->isActionDrawerOpen();
|
||||||
Q_EMIT isActionDrawerOpenChanged();
|
Q_EMIT isActionDrawerOpenChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShellDBusClient::updateIsTaskSwitcherVisible()
|
||||||
|
{
|
||||||
|
m_isTaskSwitcherVisible = m_interface->isTaskSwitcherVisible();
|
||||||
|
Q_EMIT isTaskSwitcherVisibleChanged();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,19 +12,22 @@
|
||||||
class ShellDBusClient : public QObject
|
class ShellDBusClient : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(bool doNotDisturb READ doNotDisturb WRITE setDoNotDisturb NOTIFY doNotDisturbChanged);
|
Q_PROPERTY(bool doNotDisturb READ doNotDisturb WRITE setDoNotDisturb NOTIFY doNotDisturbChanged)
|
||||||
Q_PROPERTY(bool isActionDrawerOpen READ isActionDrawerOpen WRITE setIsActionDrawerOpen NOTIFY isActionDrawerOpenChanged);
|
Q_PROPERTY(bool isActionDrawerOpen READ isActionDrawerOpen WRITE setIsActionDrawerOpen NOTIFY isActionDrawerOpenChanged)
|
||||||
|
Q_PROPERTY(bool isTaskSwitcherVisible READ isTaskSwitcherVisible NOTIFY isTaskSwitcherVisibleChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ShellDBusClient(QObject *parent = nullptr);
|
explicit ShellDBusClient(QObject *parent = nullptr);
|
||||||
static ShellDBusClient *self();
|
static ShellDBusClient *self();
|
||||||
|
|
||||||
bool doNotDisturb();
|
bool doNotDisturb() const;
|
||||||
void setDoNotDisturb(bool value);
|
void setDoNotDisturb(bool value);
|
||||||
|
|
||||||
bool isActionDrawerOpen();
|
bool isActionDrawerOpen() const;
|
||||||
void setIsActionDrawerOpen(bool value);
|
void setIsActionDrawerOpen(bool value);
|
||||||
|
|
||||||
|
bool isTaskSwitcherVisible() const;
|
||||||
|
|
||||||
Q_INVOKABLE void openActionDrawer();
|
Q_INVOKABLE void openActionDrawer();
|
||||||
Q_INVOKABLE void closeActionDrawer();
|
Q_INVOKABLE void closeActionDrawer();
|
||||||
|
|
||||||
|
|
@ -38,6 +41,7 @@ public:
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void isActionDrawerOpenChanged();
|
void isActionDrawerOpenChanged();
|
||||||
void doNotDisturbChanged();
|
void doNotDisturbChanged();
|
||||||
|
void isTaskSwitcherVisibleChanged();
|
||||||
void openActionDrawerRequested();
|
void openActionDrawerRequested();
|
||||||
void closeActionDrawerRequested();
|
void closeActionDrawerRequested();
|
||||||
void openAppLaunchAnimationRequested(QString splashIcon, QString title, qreal x, qreal y, qreal sourceIconSize);
|
void openAppLaunchAnimationRequested(QString splashIcon, QString title, qreal x, qreal y, qreal sourceIconSize);
|
||||||
|
|
@ -49,6 +53,7 @@ Q_SIGNALS:
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void updateDoNotDisturb();
|
void updateDoNotDisturb();
|
||||||
void updateIsActionDrawerOpen();
|
void updateIsActionDrawerOpen();
|
||||||
|
void updateIsTaskSwitcherVisible();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void connectSignals();
|
void connectSignals();
|
||||||
|
|
@ -56,7 +61,9 @@ private:
|
||||||
OrgKdePlasmashellInterface *m_interface;
|
OrgKdePlasmashellInterface *m_interface;
|
||||||
QDBusServiceWatcher *m_watcher;
|
QDBusServiceWatcher *m_watcher;
|
||||||
|
|
||||||
bool m_doNotDisturb;
|
bool m_doNotDisturb = false;
|
||||||
bool m_isActionDrawerOpen;
|
bool m_isActionDrawerOpen = false;
|
||||||
bool m_connected;
|
bool m_isTaskSwitcherVisible = false;
|
||||||
|
|
||||||
|
bool m_connected = false;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,19 @@ void ShellDBusObject::setIsActionDrawerOpen(bool value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ShellDBusObject::isTaskSwitcherVisible()
|
||||||
|
{
|
||||||
|
return m_isTaskSwitcherVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShellDBusObject::setIsTaskSwitcherVisible(bool value)
|
||||||
|
{
|
||||||
|
if (value != m_isTaskSwitcherVisible) {
|
||||||
|
m_isTaskSwitcherVisible = value;
|
||||||
|
Q_EMIT isTaskSwitcherVisibleChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ShellDBusObject::openActionDrawer()
|
void ShellDBusObject::openActionDrawer()
|
||||||
{
|
{
|
||||||
Q_EMIT openActionDrawerRequested();
|
Q_EMIT openActionDrawerRequested();
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ public:
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
Q_SCRIPTABLE void doNotDisturbChanged();
|
Q_SCRIPTABLE void doNotDisturbChanged();
|
||||||
Q_SCRIPTABLE void isActionDrawerOpenChanged();
|
Q_SCRIPTABLE void isActionDrawerOpenChanged();
|
||||||
|
Q_SCRIPTABLE void isTaskSwitcherVisibleChanged();
|
||||||
Q_SCRIPTABLE void openActionDrawerRequested();
|
Q_SCRIPTABLE void openActionDrawerRequested();
|
||||||
Q_SCRIPTABLE void closeActionDrawerRequested();
|
Q_SCRIPTABLE void closeActionDrawerRequested();
|
||||||
Q_SCRIPTABLE void openAppLaunchAnimationRequested(QString splashIcon, QString title, qreal x, qreal y, qreal sourceIconSize);
|
Q_SCRIPTABLE void openAppLaunchAnimationRequested(QString splashIcon, QString title, qreal x, qreal y, qreal sourceIconSize);
|
||||||
|
|
@ -37,6 +38,9 @@ public Q_SLOTS:
|
||||||
Q_SCRIPTABLE bool isActionDrawerOpen();
|
Q_SCRIPTABLE bool isActionDrawerOpen();
|
||||||
Q_SCRIPTABLE void setIsActionDrawerOpen(bool value);
|
Q_SCRIPTABLE void setIsActionDrawerOpen(bool value);
|
||||||
|
|
||||||
|
Q_SCRIPTABLE bool isTaskSwitcherVisible();
|
||||||
|
Q_SCRIPTABLE void setIsTaskSwitcherVisible(bool value);
|
||||||
|
|
||||||
Q_SCRIPTABLE void openActionDrawer();
|
Q_SCRIPTABLE void openActionDrawer();
|
||||||
Q_SCRIPTABLE void closeActionDrawer();
|
Q_SCRIPTABLE void closeActionDrawer();
|
||||||
|
|
||||||
|
|
@ -52,4 +56,5 @@ private:
|
||||||
|
|
||||||
bool m_doNotDisturb = false;
|
bool m_doNotDisturb = false;
|
||||||
bool m_isActionDrawerOpen = false;
|
bool m_isActionDrawerOpen = false;
|
||||||
|
bool m_isTaskSwitcherVisible = false;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@
|
||||||
|
|
||||||
#include "mobiletaskswitchereffect.h"
|
#include "mobiletaskswitchereffect.h"
|
||||||
|
|
||||||
|
#include <QDBusConnection>
|
||||||
|
#include <QDBusMessage>
|
||||||
|
#include <QDBusReply>
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
#include <QMetaObject>
|
#include <QMetaObject>
|
||||||
#include <QQuickItem>
|
#include <QQuickItem>
|
||||||
|
|
@ -151,6 +154,7 @@ void MobileTaskSwitcherEffect::activate()
|
||||||
|
|
||||||
m_status = Status::Active;
|
m_status = Status::Active;
|
||||||
setRunning(true);
|
setRunning(true);
|
||||||
|
setDBusState(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MobileTaskSwitcherEffect::deactivate(bool deactivateInstantly)
|
void MobileTaskSwitcherEffect::deactivate(bool deactivateInstantly)
|
||||||
|
|
@ -165,6 +169,8 @@ void MobileTaskSwitcherEffect::deactivate(bool deactivateInstantly)
|
||||||
|
|
||||||
setGestureInProgress(false);
|
setGestureInProgress(false);
|
||||||
setPartialActivationFactor(0.0);
|
setPartialActivationFactor(0.0);
|
||||||
|
|
||||||
|
setDBusState(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MobileTaskSwitcherEffect::partialActivate(qreal factor)
|
void MobileTaskSwitcherEffect::partialActivate(qreal factor)
|
||||||
|
|
@ -249,4 +255,14 @@ void MobileTaskSwitcherEffect::setPartialActivationFactor(qreal factor)
|
||||||
Q_EMIT partialActivationFactorChanged();
|
Q_EMIT partialActivationFactorChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MobileTaskSwitcherEffect::setDBusState(bool active)
|
||||||
|
{
|
||||||
|
QDBusMessage request = QDBusMessage::createMethodCall(QStringLiteral("org.kde.plasmashell"),
|
||||||
|
QStringLiteral("/Mobile"),
|
||||||
|
QStringLiteral("org.kde.plasmashell"),
|
||||||
|
QStringLiteral("setIsTaskSwitcherVisible"));
|
||||||
|
request.setArguments({active});
|
||||||
|
const QDBusReply<bool> response = QDBusConnection::sessionBus().call(request);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,8 @@ public:
|
||||||
void reconfigure(ReconfigureFlags flags) override;
|
void reconfigure(ReconfigureFlags flags) override;
|
||||||
void grabbedKeyboardEvent(QKeyEvent *keyEvent) override;
|
void grabbedKeyboardEvent(QKeyEvent *keyEvent) override;
|
||||||
|
|
||||||
|
void setDBusState(bool active);
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void activate();
|
void activate();
|
||||||
void realDeactivate();
|
void realDeactivate();
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import org.kde.plasma.core as PlasmaCore
|
||||||
import org.kde.plasma.components 3.0 as PlasmaComponents
|
import org.kde.plasma.components 3.0 as PlasmaComponents
|
||||||
import org.kde.plasma.extras as PlasmaExtras
|
import org.kde.plasma.extras as PlasmaExtras
|
||||||
import org.kde.plasma.private.mobileshell as MobileShell
|
import org.kde.plasma.private.mobileshell as MobileShell
|
||||||
|
import org.kde.plasma.private.mobileshell.state as MobileShellState
|
||||||
|
|
||||||
import org.kde.kwin 3.0 as KWinComponents
|
import org.kde.kwin 3.0 as KWinComponents
|
||||||
import org.kde.kwin.private.effects 1.0
|
import org.kde.kwin.private.effects 1.0
|
||||||
|
|
@ -73,7 +74,6 @@ FocusScope {
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
taskList.jumpToFirstVisibleWindow();
|
taskList.jumpToFirstVisibleWindow();
|
||||||
taskList.minimizeAll();
|
taskList.minimizeAll();
|
||||||
|
|
||||||
taskSwitcherState.currentlyBeingOpened = true;
|
taskSwitcherState.currentlyBeingOpened = true;
|
||||||
|
|
||||||
// fully open the panel (if this is a button press, not gesture)
|
// fully open the panel (if this is a button press, not gesture)
|
||||||
|
|
@ -101,10 +101,6 @@ FocusScope {
|
||||||
taskSwitcherState.openApp(index, window);
|
taskSwitcherState.openApp(index, window);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setSingleActiveWindow(id) {
|
|
||||||
instantHide();
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: root.effect
|
target: root.effect
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -227,10 +227,6 @@ QtObject {
|
||||||
root.currentlyBeingOpened = false;
|
root.currentlyBeingOpened = false;
|
||||||
scrollingTasks = false;
|
scrollingTasks = false;
|
||||||
taskSwitcher.instantHide();
|
taskSwitcher.instantHide();
|
||||||
|
|
||||||
if (root.wasInActiveTask) {
|
|
||||||
taskSwitcher.setSingleActiveWindow(root.currentTaskIndex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -246,7 +242,6 @@ QtObject {
|
||||||
onFinished: {
|
onFinished: {
|
||||||
root.currentlyBeingClosed = false;
|
root.currentlyBeingClosed = false;
|
||||||
root.currentlyBeingOpened = false;
|
root.currentlyBeingOpened = false;
|
||||||
taskSwitcher.setSingleActiveWindow(root.currentTaskIndex);
|
|
||||||
taskSwitcher.instantHide();
|
taskSwitcher.instantHide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue